Bit Angle Modulation (BAM) in a PIC


Closed Thread
Results 1 to 40 of 151

Hybrid View

  1. #1
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Artistic License claims to have "Invented" BAM. But nowhere have I found a claim that they have received or even applied for a patent.
    Although I have found a dozen or so patents that would probably keep A.L. from getting one if they tried.

    Not that it would matter very much, because this is not BAM.
    BAM is flawed, and MIBAM represents a "Significant Improvement".
    <br>
    DT

  2. #2
    Join Date
    Sep 2007
    Location
    USA, CA
    Posts
    271


    Did you find this post helpful? Yes | No

    Default

    BAM has been in public domain for over one year. That alone means it is not patentable.

  3. #3
    Join Date
    Nov 2004
    Posts
    61


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    Artistic License claims to have "Invented" BAM. But nowhere have I found a claim that they have received or even applied for a patent.
    Although I have found a dozen or so patents that would probably keep A.L. from getting one if they tried.

    Not that it would matter very much, because this is not BAM.
    BAM is flawed, and MIBAM represents a "Significant Improvement".
    <br>
    ....... BAM was published by AL *specifically* to place the idea & implementation in the public domain and keep companies from patenting it.

    Partly because there's been some ugliness in the professional lighting / theatre world by companies patenting (and then aggressively litigating) LED dimming and control techniques. These techniques have been obvious to those skilled in the trade since at least the 1970s, but the patents were granted nonetheless.

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Thumbs up

    Quote Originally Posted by JEC View Post
    ....... BAM was published by AL *specifically* to place the idea & implementation in the public domain and keep companies from patenting it.
    Excellent move by Artistic License.

    Hopefully, by finding the Mirror Image improvement to BAM and releasing it to the public domain ...
    RadikalQ3 and I have made it impossible for some squatter to patent a MIBAM equivalent too.

    MIBAM - (Mirror Imaged Bit Angle Modulation)
    http://www.picbasic.co.uk/forum/showthread.php?t=10564
    <br>
    DT

  5. #5
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Hi Darrel,

    May I pass along my late congrats' on some brilliant work and share a couple ideas?

    Instead of using six instructions (6 cycles) per LED during each update interval you might consider updating one port at a time using an exclusive-or instruction (2 cycles) and data from an eight byte "toggle" array that's refreshed during that long 64T end-of-period interval. This reduces overhead from 288 cycles for 48 LEDs to just 12 cycles during each update interval. Using "toggle" data and an exclusive-or instruction lets us update MIBAM output bits without changing non-MIBAM bits on each port.

    Since the three '1T' intervals seem to be a major bottleneck we might consider combining the center |2T|1T|1T|1T|2T| intervals into a single '7T' interval and use small in-line isochronous delays to effect precise timing between updates. This would practically eliminate "overhead" effects on the center three '1T' intervals.

    Here's a pseudo C code driver example (sorry, I don't have PBP). I'm sure you realize that the "switch" function should be replaced with assembly language to reduce overhead and eliminate jitter and that the LEDs and "data benders" should probably be setup as macros as you did in your driver.

    An assembly language version I wrote supports 48 LEDs at decent refresh rates at almost any clock (4-MHz, 177 Hz, 1T = 22-usecs).

    Food for thought. Kind regards, Mike, K8LH

    Code:
    unsigned char interval = 0;     // ISR state machine var'
    
    unsigned char red = 44;
    unsigned char grn = 55;
    unsigned char blu = 66;
    
    volatile unsigned short ccpr1 @ 0xFBE;
    
    /*                                                                  *
     *  original intervals -> |64|32|16|8|4|2|1|1|1|2|4|8|16|32|64|     *
     *  modified intervals -> |64|32|16|8|4|----7----|4|8|16|32|64|     *
     *                                                                  */
    void interrupt()                // CCP1 "special event" interrupts
    { unsigned char Adat[8];        // porta "toggle" array
      unsigned char Bdat[8];        // portb "toggle" array
      pir1.CCP1IF = 0;              // clear CCP1 interrupt flag
      switch(interval++)            //
      { case 0:                     // 64T
          porta ^= Adat[7];         //
          portb ^= Bdat[7];         //
          ccpr1 = (64*tStep);       // ccpr1 = half 2^7 (64T)
          break;                    //
        case 1:                     // 32T
          porta ^= Adat[6];         //
          portb ^= Bdat[6];         //
          ccpr1 >>= 1;              // ccpr1 = half 2^6 (32T)
          break;                    //
        case 2:                     // 16T
          porta ^= Adat[5];         //
          portb ^= Bdat[5];         //
          ccpr1 >>= 1;              // ccpr1 = half 2^5 (16T)
          break;                    //
        case 3:                     // 8T
          porta ^= Adat[4];         //
          portb ^= Bdat[4];         //
          ccpr1 >>= 1;              // ccpr1 = half 2^4 (8T)
          break;                    //
        case 4:                     // 4T
          porta ^= Adat[3];         //
          portb ^= Bdat[3];         //
          ccpr1 >>= 1;              // ccpr1 = half 2^3 (4T)
          break;                    //
        case 5:                     // 7T (2T+1T+1T+1T+2T)
          porta ^= Adat[2];         //
          portb ^= Bdat[2];         //
          ccpr1 = (7*tStep);        // ccpr1 = 7*tStep  (7T)
          delayCy(2*tStep-8);       // 2T minus 8 cycles
          porta ^= Adat[1];         //
          portb ^= Bdat[1];         //
          delayCy(1*tStep-4);       // 1T minus 4 cycles
          porta ^= Adat[0];         //
          portb ^= Bdat[0];         //
          delayCy(1*tStep-4);       // 1T minus 4 cycles
          porta ^= Adat[0];         //
          portb ^= Bdat[0];         //
          delayCy(1*tStep-4);       // 1T minus 4 cycles
          porta ^= Adat[1];         //
          portb ^= Bdat[1];         //
          break;                    //
        case 6:                     // 4T
          porta ^= Adat[2];         //
          portb ^= Bdat[2];         //
          ccpr1 = (4*tStep);        // ccpr1 = half 2^3 (4T)
          break;                    //
        case 7:                     // 8T
          porta ^= Adat[3];         //
          portb ^= Bdat[3];         //
          ccpr1 <<= 1;              // ccpr1 = half 2^4 (8T)
          break;                    //
        case 8:                     // 16T
          porta ^= Adat[4];         //
          portb ^= Bdat[4];         //
          ccpr1 <<= 1;              // ccpr1 = half 2^5 (16T)
          break;                    //
        case 9:                     // 32T
          porta ^= Adat[5];         //
          portb ^= Bdat[5];         //
          ccpr1 <<= 1;              // ccpr1 = half 2^6 (32T)
          break;                    //
        case 10:                    // 64T (end-of-period)
          porta ^= Adat[6];         //
          portb ^= Bdat[6];         //
          ccpr1 <<= 1;              // ccpr1 = half 2^7 (64T)
          interval = 0;             // prep for new period
          Adat[0] = 0; Adat[1] = 0; // clear Adat[] array
          Adat[2] = 0; Adat[3] = 0; //
          Adat[4] = 0; Adat[5] = 0; //
          Adat[6] = 0; Adat[7] = 0; //
          Bdat[0] = 0; Bdat[1] = 0; // clear Bdat[] array
          Bdat[2] = 0; Bdat[3] = 0; //
          Bdat[4] = 0; Bdat[5] = 0; //
          Bdat[6] = 0; Bdat[7] = 0; //
    /*                                                                  *
     *  use one "data bender" for each LED (16 cycles each)             *
     *                                                                  */
          if(red.0) Bdat[0] |= 1;   // 2^0 data RB0 pin
          if(red.1) Bdat[1] |= 1;   // 2^1 data RB0 pin
          if(red.2) Bdat[2] |= 1;   // 2^2 data RB0 pin
          if(red.3) Bdat[3] |= 1;   // 2^3 data RB0 pin
          if(red.4) Bdat[4] |= 1;   // 2^4 data RB0 pin
          if(red.5) Bdat[5] |= 1;   // 2^5 data RB0 pin
          if(red.6) Bdat[6] |= 1;   // 2^6 data RB0 pin
          if(red.7) Bdat[7] |= 1;   // 2^7 data RB0 pin
    
          if(grn.0) Bdat[0] |= 2;   // 2^0 data RB1 pin
          if(grn.1) Bdat[1] |= 2;   // 2^1 data RB1 pin
          if(grn.2) Bdat[2] |= 2;   // 2^2 data RB1 pin
          if(grn.3) Bdat[3] |= 2;   // 2^3 data RB1 pin
          if(grn.4) Bdat[4] |= 2;   // 2^4 data RB1 pin
          if(grn.5) Bdat[5] |= 2;   // 2^5 data RB1 pin
          if(grn.6) Bdat[6] |= 2;   // 2^6 data RB1 pin
          if(grn.7) Bdat[7] |= 2;   // 2^7 data RB1 pin
    
          if(blu.0) Bdat[0] |= 4;   // 2^0 data RB2 pin
          if(blu.1) Bdat[1] |= 4;   // 2^1 data RB2 pin
          if(blu.2) Bdat[2] |= 4;   // 2^2 data RB2 pin
          if(blu.3) Bdat[3] |= 4;   // 2^3 data RB2 pin
          if(blu.4) Bdat[4] |= 4;   // 2^4 data RB2 pin
          if(blu.5) Bdat[5] |= 4;   // 2^5 data RB2 pin
          if(blu.6) Bdat[6] |= 4;   // 2^6 data RB2 pin
          if(blu.7) Bdat[7] |= 4;   // 2^7 data RB2 pin
    /*                                                                  *
     *  convert Bdat[] and Adat[] array "output" data to "toggle" data  *
     *                                                                  *
     *  red  0x2C 00101100 (on RB0)                                     *
     *  grn  0x37 00110111 (on RB1)                                     *
     *  blu  0x42 01000010 (on RB2)                                     *
     *                                                                  *
     *  Bdat 'output data'   Bdat 'toggle data'   Bdat 'toggle data'    *
     *   [0] 0x02 00000010    [0] 0x04 00000100    [0] 0x04 00000100    *
     *   [1] 0x06 00000110    [1] 0x05 00000101    [1] 0x05 00000101    *
     *   [2] 0x03 00000011    [2] 0x02 00000010    [2] 0x02 00000010    *
     *   [3] 0x01 00000001    [3] 0x03 00000011    [3] 0x03 00000011    *
     *   [4] 0x02 00000010    [4] 0x01 00000001    [4] 0x01 00000001    *
     *   [5] 0x03 00000011    [5] 0x07 00000111    [5] 0x07 00000111    *
     *   [6] 0x04 00000100    [6] 0x04 00000100    [6] 0x04 00000100    *
     *   [7] 0x00 00000000    [7] 0x00 00000000    [7] 0x01 00000001    *
     *                      portb 0x00 00000000  portb 0x01 00000001    *
     *                                                                  */
          asm {
          movf  _porta,W            // get current PORTA bits
          andlw 0                   // keep only MIBAM output bits
          xorwf _Adat+7,F           // create 2^7 toggle bits
          xorwf _Adat+7,W           // W simulates cumulative PORTA
          xorwf _Adat+6,F           // create 2^6 toggle bits
          xorwf _Adat+6,W           //
          xorwf _Adat+5,F           // create 2^5 toggle bits
          xorwf _Adat+5,W           //
          xorwf _Adat+4,F           // create 2^4 toggle bits
          xorwf _Adat+4,W           //
          xorwf _Adat+3,F           // create 2^3 toggle bits
          xorwf _Adat+3,W           //
          xorwf _Adat+2,F           // create 2^2 toggle bits
          xorwf _Adat+2,W           //
          xorwf _Adat+1,F           // create 2^1 toggle bits
          xorwf _Adat+1,W           //
          xorwf _Adat+0,F           // create 2^0 toggle bits
    
          movf  _portb,W            // get current PORTB bits
          andlw 7                   // keep only MIBAM output bits
          xorwf _Bdat+7,F           // create 2^7 toggle bits
          xorwf _Bdat+7,W           // W simulates cumulative PORTB
          xorwf _Bdat+6,F           // create 2^6 toggle bits
          xorwf _Bdat+6,W           //
          xorwf _Bdat+5,F           // create 2^5 toggle bits
          xorwf _Bdat+5,W           //
          xorwf _Bdat+4,F           // create 2^4 toggle bits
          xorwf _Bdat+4,W           //
          xorwf _Bdat+3,F           // create 2^3 toggle bits
          xorwf _Bdat+3,W           //
          xorwf _Bdat+2,F           // create 2^2 toggle bits
          xorwf _Bdat+2,W           //
          xorwf _Bdat+1,F           // create 2^1 toggle bits
          xorwf _Bdat+1,W           //
          xorwf _Bdat+0,F           // create 2^0 toggle bits
          }
          break;                    //
      }
    }
    Last edited by Mike, K8LH; - 26th July 2009 at 14:01.

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    WooHoo! Somebody's paying attention.

    Hi Mike,

    That's a VERY interesting idea!
    Not sure at this point how I can let the user assign the pins at random, in any order, and any number of them, on any chip. But this sounds good enough to see if I can find a way.

    For combining the smallest periods ... I already add the lsb from each side of the "mirror" into a single period to double the minimum interrupt time. Not sure where your 3rd one comes from. That would make the lsb worth 1.5.

    I had also tried combining the 2 lsb's on both sides, but that reduced the resolution to 7-bit instead of 8, so the results weren't very good.

    I'll see what I can do with the "Full PORT Press".

    Thanks for the great idea.

    Add: Hmmm, that would help minimze R-M-W issues too.
    <br>
    Last edited by Darrel Taylor; - 26th July 2009 at 16:56. Reason: RMW
    DT

  7. #7
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post

    For combining the smallest periods ... I already add the lsb from each side of the "mirror" into a single period to double the minimum interrupt time. Not sure where your 3rd one comes from. That would make the lsb worth 1.5.
    I'm not sure I follow you here. The duty cycle b0 bit output is still 1T long smack in the middle and the b1 bit still generates two 1T outputs on either side of the b0 1T output so we're not losing any resolution. I've just combined those |2T|1T|1T|1T|2T| outputs into a single 7T interval so that our minimum ISR interval is now 4T instead of 1T which gives us more headroom and much higher refresh intervals (even with the overhead of full ISR context save/restore)

    Not sure at this point how I can let the user assign the pins at random, in any order, and any number of them, on any chip. But this sounds good enough to see if I can find a way.
    I'm not exactly sure how to do it either and then we would still need to dynamically come up with Amask, Bmask, Cmask constants or variables for each port output-to-toggle routine but like you, I'm excited enough to try and find a way.

    With the new smaller 4T minimum ISR interval my assembly language test driver can achieve Kilohertz range refresh rates with some of the higher clock frequencies, though I'm not sure if that's really useful (grin).

    Kind regards, Mike, K8LH

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Mike, K8LH View Post
    I'm not sure I follow you here. The duty cycle b0 bit output is still 1T long smack in the middle and the b1 bit still generates two 1T outputs on either side of the b0 1T output so we're not losing any resolution. I've just combined those |2T|1T|1T|1T|2T| outputs into a single 7T interval so that our minimum ISR interval is now 4T instead of 1T which gives us more headroom and much higher refresh intervals (even with the overhead of full ISR context save/restore)
    By combining those periods, you can't switch the LED for bit0, because it's combined in with bit1. That's what drops it down to 7-bit resolution. If it were a single output, you could combine them, but with multiple LED's, bit0 has to remain separate from bit1.

    With MIBAM, it looks like this, with the red line being the "mirror".
    Code:
    Bit- 1  0    0  1
        |2T|1T|1T|2T|
    The 1T's on either side can be combined into a single period equal to 2T, but they can't be combined with the bit1 (2T's).

    I'm excited enough to try and find a way.
    I think I know how now, but welcome any more thoughts.
    Just a matter of getting it done.

    Thanks,
    DT

Similar Threads

  1. decoding quadrature encoders
    By ice in forum mel PIC BASIC Pro
    Replies: 93
    Last Post: - 28th February 2017, 09:02
  2. Cordic trig assembly code for PIC18f
    By ScaleRobotics in forum mel PIC BASIC Pro
    Replies: 54
    Last Post: - 8th September 2015, 05:36
  3. AT/PS2 Keybord - PIC Interface?
    By Kamikaze47 in forum Code Examples
    Replies: 73
    Last Post: - 9th August 2009, 16:10
  4. MIBAM - (Mirror Imaged Bit Angle Modulation)
    By Darrel Taylor in forum Code Examples
    Replies: 2
    Last Post: - 15th February 2009, 16:02
  5. Bit Angle Modulation
    By BH_epuk in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 18th November 2008, 07:01

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts