Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Bam test

Status
Not open for further replies.

tubos

New Member
BAM = Bit angle modulation.
Here's a good description:
https://www.picbasic.co.uk/forum/showthread.php?t=7393

PIC used: PIC18F14K22 at 64 mhz

I'm just looking to do basic 256 levels bam but I don't know how to get the timings right.
I cant use timer1 CCP1 compare because I need it for A realtime clock with 32768 xtal.



I thought i could use the TMR0H and TMR0L registers to set the timings but after checking
it with my oscope there is not a lot of accuracy.

Anyone has an idea?

Code:
if(INTCON.TMR0IF ) // TMR0 Interrupt?     {
     LEDRED^=1;
     if(BAMbit--==0) BAMbit=7;
     
     TMR0H = ~(BAMmsk<<BAMbit);      // 0000 0000
     TMR0L=2;                                     // Correct 2 cycles for write

     INTCON.TMR0IF = 0;    // clear T0 Int flag
    }
 
Last edited:
This is the first dirty bam test with 1 led.
256 levels + gamma correction.
I need some better accuracy on the bit timings.

Can someone help me getting the timings better? (see below)

Code:
if(INTCON.TMR0IF ) // TMR0 Interrupt?  
    {

     if(BAMbit--==0) BAMbit=7;      // ( 0 - 7)
     itmp=0x80;
     itmp>>=Bambit;
     if(gamma[level] & itmp) LEDRED=1; else LEDRED=0;
     
     TMR0H = ~(BAMmsk>>BAMbit);      // 0000 0000
     TMR0L=2;                        // adjust for 2 cycle wait

     INTCON.TMR0IF = 0;    // clear T0 Int flag
    }

In the video I'm gradually increasing brightness using all BAM levels.
 
Last edited by a moderator:
What is bam? Which chip? What crystal? Is the RTC using timer1 oscillator? Can you post more code?

For an accurate timed interrupt use timer2.

Mike.
 
Last edited:
I've updated the first post with some more information.
Unfortunately I cant change the topic title.
Timer1 is used with an external xtal for RTC.system clock is internal
16mhz * 4 (PLL).

The RTC interrupts every second and runs perfect.

The other code is only some initialisation:
Code:
   T0CON = 0b10000000;         // TMR0 enabled in 16bit mode; Prescaler OFF 1/1   
   INTCON.TMR0IE=1;            // Timer0 int on
   INTCON.GIE = 1;             // Enable Global Interrupts

   char BAMmsk=0x80; // Mask
   char BAMbit=7;    // Current active bit for BAM
 
Last edited:
Bam it how to say PWM with out being sued


"Bit Angle Modulation" A led light company holds a patent on the PWM and is suing people who use PWM in there leds for dimming led lights and try to sell then for profit.

LEDs Magazine - LED Alliance seeks ammunition for battle with Color Kinetics

There a post over at parallax I can't think of his name but he writes for Nut's and volts magazine

Said to cover his butt they changed to BAM instead of calling it PWM in some code he wrote because
of a letter saying that if you use PWM to control your leds your stealing are design.
 
Last edited:
I really don't have time for this but it's downright painful watching you struggle with this. So here's a couple suggestions, including a repeat of one previous suggestion;

(1) Use the CCP module in "special event" mode. You can use Timer 3 instead of Timer 1 on your device. The advantages are that the Timer is automatically reset to 0 on the compare match interrupt (no timer jitter), and you can reload the CCPR3 "compare" register quickly with the binary weighted delay value for each interval.

(2) Consider precalculating the eight BAM interval patterns for the next period at the end of each period. This means you want to start a period with the 1T (2^0) weighted interval since that's the shortest interval, and you refresh the BAM array during the end-of-period 128T (2^7) interval. With a 1T interval of 8-usecs (128 cycles) you would have 16384 cycles between the 128T (2^7) interval interrupt and the next 1T (2^0) interrupt, which is plenty of time to refresh the BAM array for the next period with bended data from your LED duty cycle array.

Here's a driver code snippet and I really hope it doesn't do more harm than good since it's not a complete solution. It assumes an active high LED on RB0 and uses an 8-usec (128 cycle) 1T (2^0) duty cycle step interval with a 64-MHz clock (refresh rate = 488-Hz).

Regards, Mike

Code:
unsigned char bam[8] @0x0100;  // bended bam duty cycle array
unsigned char index = 0x100;   // bam[] array index
unsigned char duty = 128;      // duty cycle value, 0..255


void interrupt()               // CCP/TMR3 "special event" interrupts
{ pir1.CCP1IF = 0;             // clear "special event" interrupt flag
  ccpr3 = interval;            // new "compare" interrupt value

  fsr2 = index++;              // fast indirect access to bam[] array
  latb = indf2;                // update outputs

  if(interval.14 == 0)         // if not last (2^7) interval
  { interval <<= 1;            // multiply interval by 2
  }
  else                         // end of period
  { interval = 128;            // reset to 1T (2^0) interval (128 cycles)
    index = 0x100;             // reset bam[] array index
   /* 
    *  update bam[] array with bended data for RB0 LED
    */
    bam[0] = 0; bam[1] = 0;    //
    bam[2] = 0; bam[3] = 0;    //
    bam[4] = 0; bam[5] = 0;    //
    bam[6] = 0; bam[7] = 0;    //
    if(duty.0) bam[0] |= 1;    // insert b0 (2^0) duty cycle bit
    if(duty.1) bam[1] |= 1;    // insert b1 (2^1) duty cycle bit
    if(duty.2) bam[2] |= 1;    // insert b2 (2^2) duty cycle bit
    if(duty.3) bam[3] |= 1;    // insert b3 (2^3) duty cycle bit
    if(duty.4) bam[4] |= 1;    // insert b4 (2^4) duty cycle bit
    if(duty.5) bam[5] |= 1;    // insert b5 (2^5) duty cycle bit
    if(duty.6) bam[6] |= 1;    // insert b6 (2^6) duty cycle bit
    if(duty.7) bam[7] |= 1;    // insert b7 (2^7) duty cycle bit
  }
}
}
 
Last edited:
Thx , I'm struggling but learning a lot at the same time :)

I was at a point of getting the timings right with the TMR0
module when I used (0000 0000,1000 0000,1100 0000,11100 000 etc)
in the TMR0H register. The fading looks really nice with the gamma
correction table you provided earlier.

Since the refresh rate was too slow i'm planning
to shift those values closer to the TMR0L register (4 bits)
so updates should be 16 times faster.

I will see where i can go with this, and certainly will use your tips
and dougy's to do it.

On actual coding tips for BAM etc there's not so much to google
and if there is I read it all :)

thx mike and now get on with what you were doin :p
 
Mike college is a bear, Nice code

tubo if you haven't read this it real good Do It Up With DMX and BAM

It really gos into detail of BAM, and LED Modulation without Legal Hassles.
 
Last edited:
.... I was at a point of getting the timings right with the TMR0
module when I used (0000 0000,1000 0000,1100 0000,11100 000 etc) in the TMR0H register. ....

Those aren't the correct binary weighted intervals for BAM. Here's an example of the timer or compare values for binary weighted intervals with a 1T (2^0) step size of 4-usecs (64 cycles), assuming a 1:1 prescaler value on your timer;

Code:
  1T (2^0) Interval Compare Value  '00000000 01000000' (64 cycles)
  2T (2^1) Interval Compare Value  '00000000 10000000' (128 cycles)
  4T (2^2) Interval Compare Value  '00000001 00000000' (256 cycles)
  8T (2^3) Interval Compare Value  '00000010 00000000' (512 cycles)
 16T (2^4) Interval Compare Value  '00000100 00000000' (1024 cycles)
 32T (2^5) Interval Compare Value  '00001000 00000000' (2048 cycles)
 64T (2^6) Interval Compare Value  '00010000 00000000' (4096 cycles)
128T (2^7) Interval Compare Value  '00100000 00000000' (8192 cycles)
Best of luck. Regards, Mike
 
Last edited:
I must disagree I think they are correctly weighted
since tmr0 counts up and generates an interrupt at 0
starting with 00000000 -> 256 , 128 and so on.
Anyway I checked with a scope and they are dead on.

Now if its a good idea to use TMR0 thats another thing :p

// 8 bits BAM TMR0H:TMR0L Same here but faster (+2c)
//Bit VALUE LEFT | TMR0H TMR0L
// B7 0000 0000 256 | 0000 0000:0000 0010
// B6 1000 0000 128 | 0000 1000:0000 0010
// B5 1100 0000 64 | 0000 1100:0000 0010
// B4 1110 0000 32 | 0000 1110:0000 0010
// B3 1111 0000 16 | 0000 1111:0000 0010
// B2 1111 1000 8 | 0000 1111:1000 0010
// B1 1111 1100 4 | 0000 1111:1100 0010
// B0 1111 1110 2 | 0000 1111:1110 0010
 
Legal issues aside BAM creates the same 'general' lighting effect as PWM buth with fewer processor cycles. The savings increase with the number of intensity steps.

For the people who have not yet played with interrupts you can think of these numbers as representing trips through a loop. I will continue here talking about BAM using a loop in that more people can understand it.

With PWM we need one trip through the loop for each intensity step. With PAM we need one trip through the loop for each bit in the binary number used to represent the number of intensity steps used.

Code:
STEPS PAM   PWM
4       4   16
8       8   256
10     10   1024
...
The following is in no specific language

Code:
loop:
    dTime  = x    // a delay that generates 1 intensity step
    intensity = y   // some 8 bit intensity number
    loopCnt = 0
cycle:
    if the low order bit of intensity is 1 then ledOn
    delay(dTime)
    dTime = dTime *2
    intensity = intensity / 2
    loopCnt = loopCnt +1
    ledOff
    if  loopCnt is less then 8 goto cycle
    goto loop
Many people will realized that we can use simple bit manipulation liking anding and shifting to accomplish the math in this program.

There is a good deal of beautiful simplicity here.

I can only speculate how this would work with DC brushed motors. One would not have a fixed frequency as with PWM.

Notes:
Hardware generated PWM should still be faster.
 
I was going with the code below to get more interrupts / sec
it looked fine on the scope but when I actually measured the
timings they were getting gradually more off the lower the
bit value interrupt.

Probably due to the time I reside in the interrupt before setting the TMR0 registers
stays has a greater influence on the smaller periods.

I guess I will have to use the CCP compare function after all.
I didnt want to do it to be able to use my code on an 16F pic as well
where I dont have an TMR3 , so another lesson Learned.




Code:
     asm INCF   _BAMbit+0, 1       //
     asm MOVLW  7                  //
     asm ANDWF  _BAMbit+0, 1       // BAMbit = ( BAMbit+1 ) & 7
     asm BZ LBL00                  // if(Bambit==0) BamH= 0b11111110;
     asm RLCF _BamH                // BamH<<=1;
     asm GOTO LBL01                // Were done for now
     asm LBL00:
     asm MOVLW 0b11111110          //
     asm MOVWF _BamH               // BamH= 0b11111110;
     asm LBL01:
     BamL=BamH;                    // Make a temporary copy
     asm SWAPF _BamL               // swap nibbles
     BamL |=0xF0;                  // Set Hi nibble
     asm MOVFF _BamL,TMR0H         // Set TMR0H
     asm MOVFF _BamH,_BamL         // swap nibbles
     asm SWAPF _BamL               // swap nibbles
     BamL &=0xF0;                  // clear low nibble
     BamL |=0x02;                  // Add 2 for adjust TMR0 Write
     asm MOVFF _BamL,TMR0L         // Write new timer value
 
tubos BAM On a base line chip but all you could do is control some led's
 
I setup the special event Interrupt on timer3
with CCPR1H=0x00; CCPR1L=0xFF;

I get 32khz refresh looks normal

Code:
// Timer 3 Settings
   T3CON=0b00001001;
   //      0-------  = 2 8bit operations
   //      --00----  = Prescaler = 1/1
   //      ----1---  = Timer3 is Source For CCP compare
   //      ------0-  = Internal Clock is source for TIMER0
   //      -------1  = Timer 3 enabled
// CCP module settings
   CCP1CON=0b00001011;
   //        xxxx1011 = Compare mode, trigger special event (ECCP resets TMR3)
   PIE1.CCP1IE=1;     // Enable CC1P interrupt
 
Last edited:
I was going with the code below to get more interrupts / sec
it looked fine on the scope but when I actually measured the
timings they were getting gradually more off the lower the
bit value interrupt.

Probably due to the time I reside in the interrupt before setting the TMR0 registers
stays has a greater influence on the smaller periods.

I guess I will have to use the CCP compare function after all.
I didnt want to do it to be able to use my code on an 16F pic as well
where I dont have an TMR3 , so another lesson Learned.

Code:
     asm INCF   _BAMbit+0, 1       //
     asm MOVLW  7                  //
     asm ANDWF  _BAMbit+0, 1       // BAMbit = ( BAMbit+1 ) & 7
     asm BZ LBL00                  // if(Bambit==0) BamH= 0b11111110;
     asm RLCF _BamH                // BamH<<=1;
     asm GOTO LBL01                // Were done for now
     asm LBL00:
     asm MOVLW 0b11111110          //
     asm MOVWF _BamH               // BamH= 0b11111110;
     asm LBL01:
     BamL=BamH;                    // Make a temporary copy
     asm SWAPF _BamL               // swap nibbles
     BamL |=0xF0;                  // Set Hi nibble
     asm MOVFF _BamL,TMR0H         // Set TMR0H
     asm MOVFF _BamH,_BamL         // swap nibbles
     asm SWAPF _BamL               // swap nibbles
     BamL &=0xF0;                  // clear low nibble
     BamL |=0x02;                  // Add 2 for adjust TMR0 Write
     asm MOVFF _BamL,TMR0L         // Write new timer value

I can't quite figure out your pseudo code but if you were writing a value into the TMR0L register instead of adding a value to the TMR0L register then that will cause the problem you were seeing. You have to account for the counts accumulated in timer 0 after it overflows.

Code:
'
'
void interrupt()
{ intcon.T0IF = 0;          // clear TMR0 interrupt flag
  tmr0 += -128+2;           // reset TMR0 for 128 cycle interrupts
}
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top