Hello, welcome to our forum.

It looks like you have registered but you have not yet posted and messages. Our requirements are that you must post at least two messages, to allow the moderators to review your registration, before you will be allowed access to the full range of forum areas.

Please make a couple of posts, until then you may see a notice that says you are banned from certain forum areas.

Thank you.

# Thread: Bit Angle Modulation (BAM) in a PIC

1. ## Bit Angle Modulation (BAM) in a PIC

I have read a few posts about BAM on this website but I can't completely understand the difference between it and PWM. I have also read something on the Artistic website that says it is a better technique that PWM for dimming leds. Exactly what is the difference between BAM and PWM and how can it be implemented in a PIC?

2. ## BAM vs PWM.

<table><tr><td>PWM (Pulse Width Modulation) has 2 periods per cycle.
There's the period when the output is HIGH, and the period when it is LOW.

There will always be only 2 periods, and together they add up to the time it takes for 1 complete cycle. The ratio of the "ON" time to the total Cycle time defines the DutyCycle. (Corrected by The Borg)

BAM (Bit Angle Modulation) has as many periods as there are Bits in the Resolution. For instance, 8-bit resolution (0-255) would have 8 periods per cycle.

Each Period has a duration that corresponds to the Bit number, with each period being half as long as the previous one.

</td><td></td></tr><tr><td valign=top><hr>Assuming a 100hz refresh rate, each cycle will take 0.01 sec. (1/100)

Bit 7 of the DutyCyle will last for half of that, or 0.005 sec.
Bit 6 is half of that again, or 0.0025 sec.
then, continuing to divide in half each time, you end up with the lowest bit taking 0.000039 sec, (39 uS).

When you add up all the "ON" times for the example at DutyCycle=168, then you'll get 0.0065625 sec. which is the exact same amount of time that the PWM cycle would have been "ON" during it's Single "ON" Period.

This works good for controlling anything that depends on the Average Output, like LED's. But, it's not good for driving motors, or anything with inductance. </td><td></td></tr></table>
<hr>
Why is it better than PWM?

Well, the real savings come in when you have Multiple Outputs.

With 8-bit PWM, you would have to Interrupt 256 times per cycle to accommodate multiple outputs switching at different times.
And at 100 Hz refresh rate, it would need 25,600 interrupts per second.

But with BAM, you only need 8 Interrupts per Cycle (1 for each bit of resolution), and @ 100Hz, that's only 800 Interrupts per Second or 3% of the processing power required for software PWM.

So now that it has all this extra time on it's hands, the PIC can control the brightness of 16-32 or more LED's, and still have time left over to do the animations.

More on BAM ...
http://www.artisticlicence.com/app%20notes/appnote011.pdf<!-- BitAngleModulation.pdf -->
Last edited by Darrel Taylor; - 30th October 2007 at 19:25. Reason: Paul found a mistake.

3. ## BAM theory problem

I've been working with this on and off for quite some time now.
I've also had it working for quite some time now ... (with 1 exception).

It creates some of the smoothest fading effects I've seen so far, so I really want to figure out this one last problem with BAM theory.

The problem happens when passing in either direction of 128 DutyCycle.
Before that point, after that point, even continuously at that point, all works perfectly. But as it transitions from either above or below 128 there is a visble BLINK from the LEDs.

It's taken me Waaaay too long to figure out why, but I'm now pretty sure this is the reason ...

With anything below 128, the waveform looks something like this ...

<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3127" /> <!-- -->
<br>
And with anything equal or above 128, it looks like this ...
<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3125" /> <!-- -->

A continuous stream of either of the above pulses works perfect.
It's only in the transition from below to above 128 that 1 out of the 100 pulses that second looks like this ...

<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3126" /> <!-- -->

The change in pulse positions creates an ON period equal to 255, just for 1 period. Then it's fine again.
But that 1 period, is extremely visible.

Going from 127 to 128 it's a bright blink. From 128 to 127 it's a Dim blink, because they line up the other way (combined period = 0 dutycycle).

The visual appeal and resulting reduction in processor requirements are too great to just give up on BAM.
<br>

4. You can invert the value of the bits in each cycle.

In odd cycles, do first the normal order retard for each bit:
1,2,4,8,16,32,64,128

and, in the even cycles, reverse the value of each bit:
128,64,32,16,8,4,2,1

Edit:
Oops this can generate the problem even without transtitions of the dutty cycle used... hummm... maybe rearranging the value of the bits, not just reversing them :?
Last edited by RadikalQ3; - 16th January 2009 at 08:41.

5. Hmmmm, such a Radikal idea.
Very interesting ...

I had thought of putting the 7th bit in the middle, but it always came up lop-sided since it's Half of the period.

But making a mirror image of the pulses (at twice the frequency) would put it smack dab in the middle of a nice symetrical waveform that might actually work.

I must try this ...

Oh, and Hi there Q3.
Welcome to the forum!

6. Originally Posted by Darrel Taylor
Very interesting ...

I had thought of putting the 7th bit in the middle, but it always came up lop-sided since it's Half of the period.

But making a mirror image of the pulses (at twice the frequency) would put it smack dab in the middle of a nice symetrical waveform that might actually work.

I must try this ...

Oh, and Hi there Q3.
Welcome to the forum!
Just my musings can you do a check if duty cycle = 127 + 1 then bit 7=0 (0.005s interrupt) then 128 duty cycle. I.e cause a timer interupt delay before starting on with the BAM again.

7. Originally Posted by anonymouse
Just my musings can you do a check if duty cycle = 127 + 1 then bit 7=0 (0.005s interrupt) then 128 duty cycle. I.e cause a timer interupt delay before starting on with the BAM again.
Thats as clear as mud, => 128 begin reverse read byte and vice versa

Thanks for the Mirror Image idea!
It has completely removed the blinking problem.

Unfortunately the higher frequency and extra code to reverse things has created some new ones, but I think I can work through them.

For your first post here, it was an awesome one.

Thanks again,

Also, thanks anonymouse,
But with multiple channels at different dutycycles all using the same timer, changing the interrupt sequence at 127 isn't possible.
I hadn't mentioned the multi-channel part yet ... oops.

9. Originally Posted by Darrel Taylor
Thanks for the Mirror Image idea!
It has completely removed the blinking problem.
Oh, it's nothing... just was an idea.
I have spent the last days reading all I found in internet about PWM, BAM, Frecuency Modulation, etc.
Simply... I found your topic (and this forum) and I thought that was a nice challenge solve your blinking problem O
I am waiting the recepcion of some hardware and in a few days I can do test with this for my own.

Later, I realized that this is a forum on basic! (and I just use assembler)

10. Videos of oscilloscopes never seem to work very well.
But it's interesting to watch the way the mirror image works.

Let's call it BAM-BAM.

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/4eZho2fN3r8&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/4eZho2fN3r8&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>

It's going through a ramp from 0-255 and back down.

11. Hi Darrel. It looks very good! Congratulations on that!

Very good job.

Ioannis

12. I'd run in to the exact same issues between 127 and 128. Never had time to investigate it further.

My implementation just used a state machine in the interrupt routine - 1 state for each bit.

Each state sets TMR1 to a different level, then sets / clears the appropriate pins.

I assume that you're implementing the 2xF 'mirror' method in a similar way? Very clever.
Last edited by JEC; - 19th January 2009 at 17:24.

13. Hi Ioannis

Hi John,
&nbsp; Just yesterday I was thinking about how this might be good for your Christmas Lights.
&nbsp; Apparently, the thought had not escaped you.

Originally Posted by JEC
I assume that you're implementing the 2xF 'mirror' method in a similar way?
Well, the best method, is still to be determined. I'm trying every way I can think of ...

Currently, I'm rotating the DutyCycle out to the Pin, and when rotating it left, I shift the timer value Right to give 1/2 the period for the next bit, when rotating right, the timerval gets shifted left for 2x the period.

I'm also trying to incorporate the "Cylon Scanner" that Bruce and I were playing with last year.
With the mirror image, the bit's are scanned back and forth much like a Cylon (or Kitt the car).

Never thought that optimization exercise would actually be useful some day.
<br>

14. &nbsp; Just yesterday I was thinking about how this might be good for your Christmas Lights.
&nbsp; Apparently, the thought had not escaped you.
Pity the 10F doesn't have a TMR1...

15. Originally Posted by Darrel Taylor
Let's call it BAM-BAM.
Better... BAM-MAB

Better... BAM-MAB
I had thought of that ... but it was too hard to say (unless you're drunk).
Besides, I thought maybe Pebbles would show up to see what BamBam was doing.

Progress is cranking.
Should have an update soon.
<br>

17. Should be BAMAB... unless your program stick too much on a side of the PWM cycle ;o)

18. I played with BAM some time ago, but always found this step in the middle of the range to be its big issue. Thank you for a workable solution !!!

Its interesting that Artistic License (the inventor, or populariser of BAM) make no mention of this issue.

Bill.

19. Its interesting that Artistic License (the inventor, or populariser of BAM) make no mention of this issue.
I think Artistic License had given up on it, since all mention of BAM has been removed from their website. And when I was searching the web for answers, all I found was lots of threads with people complaining of blinking problems.

BAM-BAM to the rescue!
<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3147&stc=1&d=123283468 8" /> <!-- -->

I now have working code.
Anyone want to beta test it before I make it public?

It can run up to 48 LEDs simultaniously. (48mhz OSC)
Or 1 LED per mhz. 4mhz=4 LEDs, 20mhz=20 LEDs.
It has a self-contained Interrupt system. Instant Interrupts not required.
<br>

20. Would love a copy. Just emailed you. What's the processor utilization per MHz per LED?

21. What's the processor utilization per MHz per LED?
Utilization is less than 6% of total.

The limiting factor is the Least Significant Bit in the dutycycle. It's so short that it doesn't give much time to do anything. The mirror image helped some, because I was able to combine the LSB of both halves of the mirror for a longer period, but it's still only 68 instructions (worst case).

It has to get into the interrupt handler, save context, reload the Timer, service all the LEDs dutycycles, keep track of the bit sequencing, restore context and exit the interrupt within those 68 instructions.

Each PIN uses 6 instructions, and the rest of the handler uses about 40.
So @ 4 mhz you can only get 4 LED's (40 + 24 = 64).
Refresh rate @ 4mhz = 80 hz with 4 LEDs.

With higher OSC freqs, refresh rates can be as high as 650hz, depends on how many LEDs there are.
The rate can be set lower with a DEFINE if needed.

Warnings from the assembler will indicate if your setup is out of range.
<br>
Last edited by Darrel Taylor; - 13th February 2009 at 13:28. Reason: Change to less than 6%, forgot the othe half of the cycle.

22. Originally Posted by Darrel Taylor
Utilization is less than 3% of total.

The limiting factor is the Least Significant Bit in the dutycycle. It's so short that it doesn't give much time to do anything. The mirror image helped some, because I was able to combine the LSB of both halves of the mirror, for a longer period, but it's still only 68 instructions (worst case).

It has to get into the interrupt handler, save context, reload the Timer, service all the LEDs dutycycles, keep track of the bit sequencing, restore context and exit the interrupt within those 68 instructions.

Each PIN uses 6 instructions, and the rest of the handler uses about 40.
So @ 4 mhz you can only get 4 LED's (40 + 24 = 64).
Refresh rate @ 4mhz = 80 hz with 4 LEDs.

With higher OSC freqs, refresh rates can be as high as 650hz, depends on how many LEDs there are.
The rate can be set lower with a DEFINE if needed.

Warnings from the assembler will indicate if your setup is out of range.
<br>

How flickery is 80 Hz x 4 @ 4 MHz?

23. How flickery is 80 Hz x 4 @ 4 MHz?
Even though it's 80hz, the ducycycle is put out to the pin twice, so it's visually better than 80hz PWM would be.

I don't notice any flicker.
<br>

24. Bam sounds great. Does anybody have a sample code? Thank you in advance.
Last edited by PicLearner; - 26th January 2009 at 07:39.

25. I played with a very simple form of BAM a while back, with at least 24 LEDs on a 20MHz 16F877A. This is the main loop:

Code:
```     BAM:                        'each pass is one cycle, equiv to one PWM period
delay_index=%00000001
for i=0 to 7                        'time slots, 0 shortest, 7 longest
PORTA.1=LED1>>i
PORTA.2=LED2>>i
PORTA.3=LED3>>i
.
.
.
PORTA.n=LEDn>>1
for j=1 to delay_index      'empty delay loop for each time slot, total 255
next j
delay_index=delay_index<<1
next i
GOTO BAM```

where LED1, LED2 are intensity values that are updated when needed by interrupt. Refresh is totally dependent on clock speed and number of LEDs driven, but 100Hz is achievable.

I came across a scheme to reorder bits to avoid phase shift glitches but didn't get that far myself. See http://www.tenmilesquare.com/library

I'd love to see Darrel's code...

Gary

26. <img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3157&stc=1&d=123328553 8" />

Had that come up first, I woud have tried it. Looks interesting.

But the mirror image seems to work great, so no reason to change horses just yet.

There's 3 of our regular members looking at it now.
I like knowing they can set CONFIGs and disable A/D on their own.

Barring any problems, I'll post it soon.
<br>

27. ## Code Released

After realizing that Pebbles is probably 60-70 years old by now ...
I'm not so interested in BAMBAM anymore.

The name has been changed to MIBAM. (Mirror Imaged Bit Angle Modulation)

And the code for PicBasic Pro is now available here ...

Cheers,

28. Hi Darrel.

I am testing your code on a 887 chip at 20MHz.

I am stuck on this error:

Error[115] c:\pbp\mibam-~1.asm 223 : Duplicate label ("BAM_PIN" or redefining symbol that cannot be redefined)
Error[115] c:\pbp\mibam-~1.asm 224 : Duplicate label ("BAM_PIN" or redefining symbol that cannot be redefined)
Error[115] c:\pbp\mibam-~1.asm 225 : Duplicate label ("BAM_PIN" or redefining symbol that cannot be redefined)
Error[115] c:\pbp\mibam-~1.asm 226 : Duplicate label ("BAM_PIN" or redefining symbol that cannot be redefined).

In fact, the code is a copy of the example. Nothing more or less. Of course the part about wsave is included too. Attached is the final test code.

Regards,
Ioannis

29. Duplicate label ("BAM_PIN" or redefining symbol that cannot be redefined)
In MicroCode Sudio, View | Compile and Program Options | Compiler Tab ...

Check the "Case sensitive" box.
<br>

30. Yep, thats it.

One word describes this software.

A M A Z I N G !

Congratulations Darrel!

Only leds were more linear devices...

Thanks a lot.

Ioannis

P.S. About the case sensitivity, is this going to have any side effects on other programs that I develop? Why did that happen right now?

31. Originally Posted by Ioannis
One word describes this software.
<script language="JavaScript" src="http://www.pbpgroup.com/js/ColorText.js"></script>
<div id="DTtext"><b>A M A Z I N G !</b></div>
<script>ColorText("DTtext",['red','green','blue','magenta','cyan','black']);</script>
Thanks Ioannis, and I ... uh ... may have embellished your quote a little. (Shameless )

P.S. About the case sensitivity, is this going to have any side effects on other programs that I develop?
I guess that depends on how much ASM code you've been writing.

The default for MPASM is "Case Sensitive".
The default for MicroCode Studio is "Case Sensitive".
So somewhere along the way, you've changed the setting in MCS, and it may or may not have solved your problem at the time. Sometimes you just try things ... grasping for answers.

Why did that happen right now?
Because I chose to use tricky things that require case sensitivity.

The sensitivity option has no effect on PBP statements, since PBP isn't case sensitive to begin with.
And there are some ASM problems that can come up when un-checking the "Case sensitive" box, so I'd recommend leaving it checked at all times.

32. OK. Thanks for the explanation. I will keep the option checked for case sensitivity. I really cannot recall un-checking it...

About the Light intensity control, at least for small 5mm Leds, at low levels there is a problem because of the nature of the diodes. Of course it has nothing to do with the code you have developed.

I suppose that there should be a non-linear function to increse the current at low levels, maybe an exponential or geometric function. Some experimentation will be necessary.

Anyway, having 20 devices to control with a kind of PWM is fantastic.

Once again, you are #1!

Ioannis

33. Very smooth fading effect. Nice job DT.

34. Thank you Bruce!

And thanks for the Cylon Scanner.

I mentioned it earlier, and I did end up using the Cylon program we were playing with a while back.

To get the Mirror Image, it scans back and forth just like we had it. Then it uses that to mask the current bit in the dutycycles. It really knocked the code size down.

I used your Cylon version, of course.
<br>

35. Ioannis:

You might want to remap the LED's brightness curve to compensate for the non-linearity in perceived brightness.

This are the values I use
Code:
```data @\$0, \$00,\$00,\$01,\$01,\$01,\$01,\$02,\$02,\$02,\$03,\$03,\$03,\$04,\$04,\$04,\$04,\$05,\$05,\$05,\$06,\$06,\$06,\$07,\$07,\$07,\$08,\$08,\$08,\$09,\$09,\$0A,\$0A
data      \$0A,\$0B,\$0B,\$0B,\$0C,\$0C,\$0C,\$0D,\$0D,\$0E,\$0E,\$0E,\$0F,\$0F,\$10,\$10,\$10,\$11,\$11,\$12,\$12,\$13,\$13,\$13,\$14,\$14,\$15,\$15,\$16,\$16,\$16,\$17
data      \$17,\$18,\$18,\$19,\$19,\$1A,\$1A,\$1B,\$1B,\$1C,\$1C,\$1D,\$1D,\$1E,\$1E,\$1F,\$1F,\$20,\$20,\$21,\$21,\$22,\$23,\$23,\$24,\$24,\$25,\$25,\$26,\$27,\$27,\$28
data      \$28,\$29,\$2A,\$2A,\$2B,\$2B,\$2C,\$2D,\$2D,\$2E,\$2F,\$2F,\$30,\$31,\$31,\$32,\$33,\$33,\$34,\$35,\$35,\$36,\$37,\$37,\$38,\$39,\$3A,\$3A,\$3B,\$3C,\$3D,\$3D
data      \$3E,\$3F,\$40,\$40,\$41,\$42,\$43,\$44,\$44,\$45,\$46,\$47,\$48,\$49,\$49,\$4A,\$4B,\$4C,\$4D,\$4E,\$4F,\$50,\$51,\$51,\$52,\$53,\$54,\$55,\$56,\$57,\$58,\$59
data      \$5A,\$5B,\$5C,\$5D,\$5E,\$5F,\$60,\$61,\$62,\$63,\$64,\$65,\$67,\$68,\$69,\$6A,\$6B,\$6C,\$6D,\$6E,\$6F,\$71,\$72,\$73,\$74,\$75,\$77,\$78,\$79,\$7A,\$7B,\$7D
data      \$7E,\$7F,\$81,\$82,\$83,\$84,\$86,\$87,\$89,\$8A,\$8B,\$8D,\$8E,\$8F,\$91,\$92,\$94,\$95,\$97,\$98,\$9A,\$9B,\$9D,\$9E,\$A0,\$A1,\$A3,\$A4,\$A6,\$A7,\$A9,\$AB
data      \$AC,\$AE,\$B0,\$B1,\$B3,\$B5,\$B6,\$B8,\$BA,\$BB,\$BD,\$BF,\$C1,\$C3,\$C4,\$C6,\$C8,\$CA,\$CC,\$CE,\$D0,\$D1,\$D3,\$D5,\$D7,\$D9,\$DB,\$DD,\$DF,\$E1,\$E3,\$E6```
Then just
Code:
`READ LED, LED`

36. Hi gmglickman,

Hmm, nice, thanks for the post. I was thinking more complicated on this!

Ioannis

Hi,

I came across this topic when browsing for BAM.

Regarding the blink can you verify that the blink still occurs when:
1 The last value of the period = 2^nBits - 2 instead of 2^nBits-1
2 New value is only updated at the start of a pwm period.

It would seem strange to me if it does.
I think that a blink can only occur form value=0 to value=x

Thanks

38. Originally Posted by Caius1
Regarding the blink can you verify that the blink still occurs when:
1 The last value of the period = 2^nBits - 2 instead of 2^nBits-1
2 New value is only updated at the start of a pwm period.
I assume you mean reversing the order of bits 6 and 7.

Yes, the blink still occurs. It just happens at different numbers.
No matter which way you order the bit's, if they are only scanned in one direction, there will always be a blink at some point.

I also found that at other points in the dutycycle, the original BAM has several more less obvious blinks as the phase shift does the exact same thing in the lower bits. You just can't see them as well because they are shorter periods. But if you stare right at the LED straight on, you can definitely see them.

However, the symmetrical nature of the Mirror Imaged waveform, completely eliminates ALL of the blinking. It's really amazing how well it fixed the problems.

You can see how it works from the animation in this thread ...

MIBAM - (Mirror Imaged Bit Angle Modulation)

39. ## Cylon Scanner Error message

Hi Darrel.

I am testing your Cylon Scanner
code on a 887 chip at 8MHz.

I am stuck on this error:

Error[118] c:\pbp\mibam-~1.asm 97:Overwriting previous address contents (2007)

In fact, the code is a copy of the example. Nothing more or less. Of course the part about wsave is included too. Attached is the final test code.

Regards,
MIBAM_Cylon.pbp.txt

40. Try this thread ... post#5

Presetting Configuration Fuses (PIC Defines) into your Program

Or, just delete the __config line, which will then use the PBP default configs.
<br>