Menu

Mirror Image Bit Angle Modulation (MIBAM) implimentation in GCB

2023-07-06
2023-07-25
  • David Abrames

    David Abrames - 2023-07-06

    Hello,
    I am looking for some guidance in implementing Mirror Image Bit Angle Modulation (MIBAM) in Great Cow Basic.

    MIBAM was created by Darrel Taylor using PICBASIC in 2009. I have included a link to his work here:
    http://www.picbasic.co.uk/forum/showthread.php?t=7393

    MIBAM is a replacement for Pulse Width Modulation to allow for driving many more LEDs Using TIMER Interrupts. The heart of the feature is an Interrupt Routine that is compiled using MPASM.

    I have all the original sample source (attached) and I am trying to implement MIBAM using GCB but I am having issues with getting the interrupt routine to work. Is there any examples or tutorials about using Assembly code with GCB? I have looked at the information about interrupts but I can always use more knowledge as I find interrupt handling confusing.

    Since I am a bit weak in the area of interrupt handling and also new to GCB it is possible I am going at this all wrong and maybe should just code this all in GCB and let the GCB Compiler do all the heavy lifting.

    I am more than willing to do all the work figuring this out but would like some feedback from those that are more knowledgeable with GCB as to how best to get this working.

    Thank you very much for you time
    David

     
  • Anobium

    Anobium - 2023-07-07

    Many, many questions.


    Why do this at all? There are PICs that support many more PWMs than PICs did in 2009.

    How many PWMs are required?


    The port. This port is relatively simple. Do not use ASM.

    GCBASIC will create optimised ASM for you and it will be portable across the different chip architectures.

    I have reviewed the PHP and it the ISR is essentially a CASE-SELECT supporting the 8 PWM channels. There is code that will not port as it specific to specific chips but GCBASIC will handle all the context stuff anyway.


    How far have you got in GCBASIC?

    We can help!

     
  • stan cartwright

    stan cartwright - 2023-07-07

    I got your ' PCA9685 routines for the GCBASIC compiler
    ' Copyright (C) 2018 Evan R. Venn
    16 channel but i2c but today and think I used it for 2 stepper motor drives

     
    • Anobium

      Anobium - 2023-07-07

      Good point Stan. PCA9685 could be a solution.

       
  • Anobium

    Anobium - 2023-07-07

    @David

    Looking at the code more.

    There is an assumption of 8 LEDs/ports with no checking that the eight are defined in the user program. Which means the interrupt handles 8 even if they are not defined.

    The calcs for the Interrupt latency are hard coded. This will have to made a real calculation for the chip.

    The code has limited documentation. I think I know what the ISR is doing.

    The user program is relatively simple. This is a 15 minote port. I can post that... but, the library will be based on what you have.

    Evan

     
    • Anobium

      Anobium - 2023-07-08

      @David.

      variable BuffAddr#v(FDutyVar) = _BAM_Buffers + BAMpinCount

      I  have no idea what this does. Not the _BAM_Buffers + BAMpinCount bit the variable piece.
          `variable BuffAddr#v(FDutyVar) = _BAM_Buffers + BAMpinCount`
          This defines a variable but what does the #v mean?
          Then, the value of FDutyVar could be 0 to 255... that is crazy. As this would create an array of 8 * 256 bytes.  So, this is not correct.
      
          So, for now... shove this into the BAM_BUFFERS(array)
      

      Another one that I need explaining,
      andwf BAM_Buffers#v(FDutyVar), W - the use of BAM_Buffers#v(FDutyVar).

      My analysis. CylonMask AND BAM_Buffers(BuffPointer) Then so something
      // movf _CylonMask, W
      // andwf BAM_Buffers#v(FDutyVar), W
      // btfss STATUS,Z ; copy Inverted Z to the Pin
      // bsf LATport,Pin
      // btfsc STATUS,Z
      // bcf LATport,Pin

      New code coulde be ...
      if ( CylonMask AND BAM_Buffers( BuffPointer) ) =1 then
      Port_Pin = 1
      else
      Port_Pin = 0
      end if


      MOVE?BB FDutyVar, BAM_Buffers#v(FDutyVar)

      What is this MOVE?BB. Same addressing code but as this will be explain above this question is in relation to to MOVE?BB


      The interrupt is easy. It is the rest of the code... :-)

       
  • Jerry Messina

    Jerry Messina - 2023-07-08

    MOVE?BB is an asm macro to do a byte-to-byte move,, ie MOVFF if the byte locations require it..

     
    • Anobium

      Anobium - 2023-07-09

      Thanks Jerry,

      So MOVE?BB FDutyVar, BuffAddr#v(FDutyVar) means assign the value of FDutyVar to BuffAddr#v(FDutyVar). I just need to know what BuffAddr#v() means.

       
  • Anobium

    Anobium - 2023-07-09

    The interrupt handler

    This is optimised by the compiler and generates the same ASM.
    However, this is meaningless in the context that the rest of the library does not work. :-(
    I am certain the values of BAM_PeriodX are totally incorect.

    Note: There is no need for ISR context management as this is managed by GCBASIC. Lots of other code in the original ISR address issues in the orginal compiler and again these are not needed.

    ;----[Interrupt handler for BAM-BAM]----------------------------------------

    Sub BAM_ISR
    
        TMR1ON = 0                          ; Stop the Timer
        Timer1 = Timer1 - BAM_NextTimerLoad     ; subtract the BAM_ReloadCount value
        TMR1ON = 1                          ; Start the Timer
        TMR1IF = 0
    
        BAM_LIST                            ; set all BAM bits
    
        If BAM_DIRECTION = 1 Then               ; If BAM_DIRECTION = 1 Then
            ScanLeft:
            Set C Off
            Rotate BAM_CylonMask Left
            If C = 1 Then 
                BAM_DIRECTION = 1
                BAM_CylonMask.7 = 1
                BAM_INITIALIZING = 2
                BAM_LIST                               ; copy DutyVar to WorkingVar
                BAM_INITIALIZING = 2
            End If
        Else
            ScanRight:                                     ;   sending MSB first
            Set C OFF    
            ROTATE BAM_CylonMask Right
            If BAM_CylonMask.0 = 1 Then
                BAM_DIRECTION = 0
            end if
        end if
    
        If BAM_CylonMask.1 = 1 Then 
            BAM_NextTimerLoad = BAM_Period1
            Else If BAM_CylonMask.0 = 1 Then
                BAM_NextTimerLoad = BAM_Period0
                Else If BAM_CylonMask.2 = 1 Then
                    BAM_NextTimerLoad = BAM_Period2
                    Else If BAM_CylonMask.3 = 1 Then
                        BAM_NextTimerLoad = BAM_Period3
                        Else If BAM_CylonMask.4 = 1 Then
                            BAM_NextTimerLoad = BAM_Period4
                            Else If BAM_CylonMask.5 = 1 Then
                                BAM_NextTimerLoad = BAM_Period5
                                Else If BAM_CylonMask.6 = 1 Then
                                    BAM_NextTimerLoad = BAM_Period6
                                    Else If BAM_CylonMask.7 = 1 Then
                                        BAM_NextTimerLoad = BAM_Period7
        End If
    End Sub
    

    Generates

    BAM_ISR
        bcf T1CON,TMR1ON
        movf    BAM_NEXTTIMERLOAD,W
        subwf   TIMER1,F
        movlw   0
        btfss   STATUS,C
        movlw   0 + 1
        subwf   TIMER1_H,F
        bsf T1CON,TMR1ON
        bcf PIR1,TMR1IF
        call    BAM_LIST
        btfss   SYSBITVAR0,1
        goto    ELSE32_1
    SCANLEFT
        bcf STATUS,C
        rlf BAM_CYLONMASK,F
        btfss   STATUS,C
        goto    ENDIF34
        bsf SYSBITVAR0,1
        bsf BAM_CYLONMASK,7
        movlw   2
        movwf   BAM_INITIALIZING
        call    BAM_LIST
        movlw   2
        movwf   BAM_INITIALIZING
    ENDIF34
        goto    ENDIF32
    ELSE32_1
    SCANRIGHT
        bcf STATUS,C
        rrf BAM_CYLONMASK,F
        btfsc   BAM_CYLONMASK,0
        bcf SYSBITVAR0,1
    ENDIF32
        btfss   BAM_CYLONMASK,1
        goto    ELSE33_1
        movlw   1
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_1
        btfss   BAM_CYLONMASK,0
        goto    ELSE33_2
        movlw   1
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_2
        btfss   BAM_CYLONMASK,2
        goto    ELSE33_3
        movlw   2
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_3
        btfss   BAM_CYLONMASK,3
        goto    ELSE33_4
        movlw   4
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_4
        btfss   BAM_CYLONMASK,4
        goto    ELSE33_5
        movlw   8
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_5
        btfss   BAM_CYLONMASK,5
        goto    ELSE33_6
        movlw   16
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_6
        btfss   BAM_CYLONMASK,6
        goto    ELSE33_7
        movlw   32
        movwf   BAM_NEXTTIMERLOAD
        goto    ENDIF33
    ELSE33_7
        btfss   BAM_CYLONMASK,7
        goto    ENDIF33
        movlw   64
        movwf   BAM_NEXTTIMERLOAD
    ENDIF33
        return
    
     

    Last edit: Anobium 2023-07-09
  • Anobium

    Anobium - 2023-07-09

    I found the explanation!!

    It is MPASM macro expansion. Hence, this code would have only compiled using MPASM.

    #v(expr)
    Returns the integer value of expr. Typically, used to create unique variable names with common prefixes or suffixes.


    It is some smart way of doing something.

     
  • David Abrames

    David Abrames - 2023-07-10

    Thank you for all your comments and especially @evanvennn. I fully understand this was written at a time when PICs had a lot fewer PWM modules available but I have a lot of those older PICs in my stockpile that I would like to use. I like using GCBasic and lot better than anything else so I have been slowing moving all my project over to GCBasic and this particular module was one I just could not seem to work out. However you have really answered my basic question as it looks like I should not port this over but just recreate this in GCBasic as the compiler will do what the MPASM compiler did for the original code and that is create an optimized ISR.

    Thank you all again for your very helpful feedback.

    David

     
  • Anobium

    Anobium - 2023-07-10

    I get the rational now. Thanks for the explanation.


    The ISR is replica of the original and it is just wrong. The ISR prevents the 7th bit from being set. So, this means the resolution is 7-bit not 8-bit.

    I am working through the ISR at the moment changing it to 8-bit. Then, the rest should work.

    The huge advantage we have with GCBASIC is we can easily add serial debug that 'back in the day ' adding debug was a major task. The demo code has a scope for debug. I added serial debug to the ISR to check the bit rotation and the errors at both ends of the direction change is very obvious.

    I will post an update soon.

     
  • Jerry Messina

    Jerry Messina - 2023-07-10

    I haven't really looked at the code, but MIBAM is different than normal PWM code would be... it generates a different waveform..

     
    • Anobium

      Anobium - 2023-07-11

      @Jerry

      Yes. I can see the signals. The issue is that no 7th bit pulse, and, bit 0 is pused twice when rotation is left and once when rotation is right. That cannot be correct .

       
  • Jerry Messina

    Jerry Messina - 2023-07-12

    The ISR prevents the 7th bit from being set

    I'm probably missing something... I don't see where that happens. What 7th bit do you mean?
    As I see it, the actual output is done by PinList (which resolves to the BAM_LIST macro), and that has all eight bits of PORTD defined

    CylonMask gets bit-shifted 7->0->7->0..., and there are eight bit tests for the loading of the TMR.

     
  • Anobium

    Anobium - 2023-07-12

    Bits get shifted. agree.
    Size the .7 bit does not get handled by the remainder of the ISR. .7=1, shift to .6=1 therefore .7 is not handled.

    And, bit .1 is processed three times.

    It may work but it does not seem right to me.

     
    • Anobium

      Anobium - 2023-07-12

      The correct way to ensure all conditions are met is to use something similar to the code below.

      This works correctly permitting the IRS to handle the uses cases:

      Init value of BAM_CylonMask = 128 with Left or Right direction selected
      Init value of BAM_CylonMask = 1 with Left or Right direction selected
      Init value of BAM_CylonMask = 2,4,8,16,32,64 with Left or Right direction selected

      The later part of the ISR would now handle BAM_CylonMask.7 ( BIT 7) and there is no repeat of the BAM_CylonMask.0 (BIT 0) when the direction changes.

      This major difference is the BAM_IninitalPass check which enables the initial value to be handle correctly, and, the other of things.

      Sub BAM_ISR
      
          StopTimer 1                          ; Stop the Timer
          Timer1 = Timer1 - BAM_NextTimerLoad     ; subtract the BAM_ReloadCount value
          StartTimer 1                          ; Start the Timer
          TMR1IF = 0
      
          If BAM_DIRECTION = BAMLEFT Then               ; If BAM_DIRECTION = 0 Then
              ScanLeft:
                  If BAM_IninitalPass = 1 Then
                      'First pass
                      BAM_IninitalPass = 0
                  Else
                      Set C Off
                      Rotate BAM_CylonMask Left
                      If C = 1 Then
                          BAM_CylonMask = 128 
                          BAM_DIRECTION = BAMRIGHT
                      End if
                  End if
          Else
              ScanRight:                                     ;   sending MSB first
                  If BAM_IninitalPass = 1 Then
                      'First pass
                      BAM_IninitalPass = 0
                  Else
                      'Normal operations
                      Set C OFF   
                      ROTATE BAM_CylonMask Right
                      If C = 1 Then
                          BAM_CylonMask = 1
                          BAM_DIRECTION = BAMLEFT
                      end if
                  End if
          End if
          .... more code
      
       
  • Anobium

    Anobium - 2023-07-14

    I have completed a 'port' of MIBAM.

    The demo program is not operating the same... so, I know I have not done something correct. I wish there was more documentation explaining the 'concept of operation' as this would help. I will keep trying to resolve.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.