# 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. ## work MIBAM with hserin (16f628a)

Hallo
will work mibam with hserin on 16F828?

8. Originally Posted by talatsahim
will work mibam with hserin on 16F828?
Yes it will.

9. ## thanks

Originally Posted by Darrel Taylor
Yes it will.
Sorry, my very poor english.
Im new pbp user.
can you help me why not work my code?
Device 16F628

Code:
```DEFINE OSC 20
CLEAR

;_________________________Interrupt Context save locations]_________________

wsave       var byte    \$20     SYSTEM      ' location for W if in bank0
wsave1      VAR BYTE    \$A0     SYSTEM      ' location for W if in bank1
wsave2      VAR BYTE    \$120    SYSTEM      ' location for W if in bank2
ssave       VAR BYTE    BANK0   SYSTEM      ' location for STATUS register
psave       VAR BYTE    BANK0   SYSTEM      ' location for PCLATH register
;----[ MIBAM Setup ]--------------------------------------------------------
BAM_COUNT CON 3                     ; How many BAM Pins are used?
INCLUDE "MIBAM.pbp"                 ; Mirror Image BAM module

BAM_FREQ    CON 100
DEFINE BAM_INFO 1
DEFINE HSER_BAUD 250000
DEFINE HSER_CLROERR 1
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h

KANAL       CON 3
BREAKTIME   VAR BYTE
DMXFLAG     VAR BIT
STARTBYTE   VAR BYTE
RVAL        VAR BYTE
GVAL        VAR BYTE
BVAL        VAR BYTE
YVAL        VAR BYTE
X           VAR BYTE
DUMMY       VAR BYTE
i           VAR BYTE

'*****************  MIBAM  ***************************************************
RED         VAR BYTE
GREEN       VAR BYTE
BLUE        VAR BYTE

ASM
BAM_LIST  macro                     ; Define PIN's to use for BAM
BAM_PIN (PORTB,5, RED)         ;   and the associated Duty variables
BAM_PIN (PORTB,6, GREEN)
BAM_PIN (PORTB,7, BLUE)
endm
BAM_INIT  BAM_LIST                ; Initialize the Pins
ENDASM
'*****************************************************************************
TRISA=%00111001
TRISB=%00000010

ScopeSync   VAR     PORTB.2
RXT         VAR     PORTB.1
ERR         VAR     PORTB.4

CMCON=7
VRCON=0
OPTION_REG.7 =0
INTCON =%11000000

START:
PAUSE 100
DUMMY=0
RED=50
GREEN=100
BLUE=180
ERR=0
GOTO LOOP
'--------->>>>>>>>

DMXBAK:
i=i+1
IF i> 200 THEN RETURN
BREAKTIME =1:DMXFLAG = 0
pulsin  RXT,0,BREAKTIME

if BREAKTIME = 0 then return
if BREAKTIME < 30 then DMXBAK

PIE1.5=1
RCREG = dummy
RCREG = dummy '
SPBRG = 0
TXSTA.2 = 0
TXSTA.4 = 0
RCSTA.7 = 1
RCSTA.6 = 0
RCSTA.4 = 0
RCSTA.4 = 1

while RCIF = 0:wend
STARTBYTE = RCREG
if STARTBYTE = 0 then

for x = 1 to ADR
while RCIF = 0:WEND
dummy = RCREG
next x

DATAAL:
RVAL= RCREG
RCREG = 0
RCREG = 0
GVAL= RCREG
RCREG = 0
RCREG = 0
BVAL= RCREG
ENDIF
RCSTA.7 = 0
DMXFLAG=1
return

LOOP:
IF DMXFLAG=1 THEN
RED= RVAL
GREEN=GVAL
BLUE=BVAL
ENDIF
GOSUB DMXBAK
IF i>200 THEN
ERR=0
ELSE
ERR=1
ENDIF
i=0
DUMMY=0

GOTO LOOP

END```

10. Originally Posted by talatsahim
can you help me why not work my code?
Yes I can ...
1. HSER defines only work with HSERIN/HSEROUT. If you are reading RCREG manually, the baud rate will not have been set by PBP and you will have to do that manually as well.<br><br>
2. pulsin RXT,0,BREAKTIME, PULSIN does not work with interrupts. The timing will be wrong and you'll almost never see a Break pulse that way. Fortunately, the USART does it for you. Look for an FERR flag (framing error) which happens on every Break.<br><br>
3. INTCON =%11000000, interrupts are controlled by the MIBAM routines. Don't change any interrupt registers.<br><br>
4. PIE1.5=1, you've enabled the USART receive Interrupt ... don't do that.<br><br>
5. RCREG = dummy, RCREG is a Read-Only register. Don't know what you were trying to do there.<br><br>
6. SPBRG = 0, it's unlikely that you would want to put SPBRG (Baud Rate Generator Register) to 0 for any reason.<br><br>
7. TXSTA.2 = 0, It's unlikely that you would want to put the USART in Low Speed mode when running at 250Kbaud.<br><br>
8. TXSTA.4 = 0, OK, it's not synchronous mode .... but what is it?<br><br>
9. I have no idea what you are trying to do here. RCREG is read-only, and you're reading 3-bytes from a maximum 2-byte buffer, without checking to see if anything is there.
Code:
```DATAAL:
RVAL= RCREG
RCREG = 0
RCREG = 0
GVAL= RCREG
RCREG = 0
RCREG = 0
BVAL= RCREG
ENDIF
RCSTA.7 = 0
DMXFLAG=1
return```

Back to the Drawing Board.

11. ## thanks again

"RCREG=DUMMY" was copy-paste from a sample code
how can I set receive port with correct commands?
and how sense break signal with FERR ?

[QUOTE=Darrel Taylor;80570]Yes I can ...

1. DEFINE OSC 20
CLEAR
;_________________________Interrupt Context save locations]_________________

wsave var byte \$20 SYSTEM ' location for W if in bank0
wsave1 VAR BYTE \$A0 SYSTEM ' location for W if in bank1
wsave2 VAR BYTE \$120 SYSTEM ' location for W if in bank2
ssave VAR BYTE BANK0 SYSTEM ' location for STATUS register
psave VAR BYTE BANK0 SYSTEM ' location for PCLATH register
;----[ MIBAM Setup ]--------------------------------------------------------
BAM_COUNT CON 3 ; How many BAM Pins are used?
INCLUDE "MIBAM.pbp" ; Mirror Image BAM module

BAM_FREQ CON 100
DEFINE BAM_INFO 1
' MUST BE HERE DEFINE USART PARAMETER?

KANAL CON 3 'my dmx adress, 3.byte red, 4. byte green, 5. byte blue
BREAKTIME VAR BYTE
DMXFLAG VAR BIT
STARTBYTE VAR BYTE
RVAL VAR BYTE
GVAL VAR BYTE
BVAL VAR BYTE
YVAL VAR BYTE
X VAR BYTE
DUMMY VAR BYTE
i VAR BYTE

'***************** MIBAM ************************************************** *
RED VAR BYTE
GREEN VAR BYTE
BLUE VAR BYTE

ASM
BAM_LIST macro ; Define PIN's to use for BAM
BAM_PIN (PORTB,5, RED) ; and the associated Duty variables
BAM_PIN (PORTB,6, GREEN)
BAM_PIN (PORTB,7, BLUE)
endm
BAM_INIT BAM_LIST ; Initialize the Pins
ENDASM
'************************************************* ****************************
TRISA=%00111001
TRISB=%00000010

ScopeSync VAR PORTB.2
RXT VAR PORTB.1
ERR VAR PORTB.4

CMCON=7
VRCON=0
OPTION_REG.7 =0

START:
PAUSE 100
DUMMY=0
RED=50
GREEN=100
BLUE=180
ERR=0
GOTO LOOP
'--------->>>>>>>>

DMXBAK:
i=i+1
IF i> 200 THEN RETURN
BREAKTIME =1MXFLAG = 0
pulsin RXT,0,BREAKTIME ' I DONT KNOW HOW USE FERR THIS POINT

if BREAKTIME = 0 then return
if BREAKTIME < 30 then DMXBAK

BRGH=1 ' 250000 BAUD ?
SPBRG = 4 ' 250000 BAUD ?
'AND HOW CAN I "DEFINE HSER_CLROERR 1" WITHOUT DEFINE?

RCSTA.7 = 1
RCSTA.6 = 0
RCSTA.4 = 0
RCSTA.4 = 1

while RCIF = 0:wend
STARTBYTE = RCREG
if STARTBYTE = 0 then

for x = 1 to ADR 'MY ADRESS 3, SKIP 2 BYTE
while RCIF = 0:WEND
dummy = RCREG
next x

DATAAL:
RVAL= RCREG ' 3.BYTE, START OF MY DATA STREAM, RED VALUE
GVAL= RCREG '4 BYTE.. GREEN VALUE
BVAL= RCREG '5. BYTA BLUE VALUE
ENDIF
RCSTA.7 = 0
DMXFLAG=1
return

LOOP:
IF DMXFLAG=1 THEN
RED= RVAL
GREEN=GVAL
BLUE=BVAL
ENDIF
GOSUB DMXBAK
IF i>200 THEN
ERR=0
ELSE
ERR=1
ENDIF
i=0
GOTO LOOP

END
Last edited by talatsahim; - 9th November 2009 at 02:06. Reason: careless

12. ## Re: Bit Angle Modulation (BAM) in a PIC

Hi there !
Can anybody mail me a code for charliplexing more than 20 or even 20 LEDs with 16F886 in a C listing file ?

13. ## Re: Bit Angle Modulation (BAM) in a PIC

There are several posts encompassing a 20 LED charlie and at least one using only 4 PIC pins.

I doubt though you'll find any of them in C and I guarantee you no one will do it for you.