Software PWM using binary code modulation

Flenser

Senior Member
I've seen a couple of questions about software PWM on this forum. I'd never heard of using binary code modulation to do PWM before so when I clicked through to this link http://www.batsocks.co.uk/readme/art_bcm_1.htm. I thought I'd post it here where others will be able to find it. I also tried it out to see how well it worked for me.

I won't go into a lot of detail, you click through to the link to get that, I'll just sketch it out.

If the PWM value is 0x01010101 (decimal 85) then the common method we see for PWM is to put the output high for 65 units of time and then low for 170 units of time. The problem doing this on a PICAXE is that you have to do something 255 times every time through the PWM cycle in order to be able to adjust the PWM output for every possible value of 1 to 255.

With binary code modulation you only need to make 8 changes to the output in the same PWM cycle.
- Output the value of bit 1 and wait for 1 unit of time
- Output the value of bit 2 and wait for 2 units of time
- Output the value of bit 3 and wait for 4 units of time
- Output the value of bit 4 and wait for 8 units of time
- Output the value of bit 5 and wait for 16 units of time
- Output the value of bit 6 and wait for 32 units of time
- Output the value of bit 7 and wait for 64 units of time
- Output the value of bit 8 and wait for 128 units of time

So for my example PWM value of 0x01010101 the output is high for 1, low for 2, high for 4, low for 8, high for 16, low for 32, high for 64 and low for 128.
- High for 1+4+16+64 = 85
- Low for 2+8+32+128 = 170

You can also setup the values for multiple PWM pins ahead of time in variables. This enables you to do multiple channels of PWM at the same time just by writing the right variable to the ouput port at these eight times.

The first thing I did was get an idea whether it was going to be possible to get a reasonable PWM frequency. On an 08M at 8MHz this code gave a pulse train that was high for 0.2ms and low for 0.32ms (i.e. the 0.32ms is the time for the outpins + the time for the goto).


setfreq m8
dirs = %00000010
b0 = %00000000
b1 = %00000001

main: outpins = b0
outpins = b1
goto main​


So if I set the value of bit1 and then change it to the value of bit2 the bit1 output has been set for 0.2ms. The PWM period will be 255 x 0.2ms = 51ms which is a freq of 19.6 Hz. 20 Hz seems too low.
- I could use a faster PICAXE. The same calculation for the 08M2 at 32 MHz would come in at 78.4 Hz but I don't have an 08M2 yet.
- The other alternative is to use less bits. If I only ouput the high 6 bits of the PWM value, instead of the full 8 bits, then it works out at the same 78.4 Hz on an 08M at 8 Mhz.

This was good enough to give it a go and it works!

Attached is the complete code for a simple RGB fader that runs on an 08M.
View attachment RGB LED Fader.bas
- The 78.4 Hz PWM freq seems fine, I couldn't seen any variation in the LED when using the same code to continually display a fixed set of 3 RGB values.
- The fading is not too bad with just 6 bits and on any PICAXE that runs at 32 MHz you'd be able to do 8 bits.
- I am still getting a bit of intermittent flickering, so it's not perfect, but I was pretty happy with the result. If anyone can spot the bug pls let me know.
- The delays probably need to be close to the right values to get smooth colour changes. I tuned the delay for each bit time using an oscilliscope.
- I tried using the pause command but it isn't accurate enough at very low values.
 
Last edited:

John West

Senior Member
Just a note:
Unless the pulsing is the intended purpose, LED flicker can typically be resolved with the right value of capacitor across the leads. Sometimes a hardware fix is the best fix.
 
Last edited:

Andrew Cowan

Senior Member
^^ Although this doesn't always work.

If the LED needs 3v to turn on, and you're pulsing it at 5% duty at 5v, it could be that a capacitor would lower the average level to below 3v - that would stop the LED being on at all.

Just a thought.

A
 

John West

Senior Member
True. The method may not produce light with every different pulse pattern. You have to experiment with the different pulse patterns to determine which will produce the range of "off to on" output brightness control you want, then implement only those patterns as your range of control. But a capacitor can make up for a lot of PICAXE timing limitations when it comes to driving LED's.
 
Last edited:

womai

Senior Member
As far as I can see this approach will not really help. You still need to switch as fast as before (and have equally precise timing) for the least significant bitinary weighing only works if your timing accuracy is better than about half an LSB. Otherwise you're just kidding yourself. Or am I missing something?
 

Flenser

Senior Member
Womai,

Using the usual PWM method you can't do 3 channels of software PWM on an 08M at anywhere near 80Hz. Using bit code modulation you can, although at a reduced 6 bits of brightness.

You need to swtich as fast as before
In the usual PWM method you have to switch 255 times per PWM period and the time between these switchings are all the same. i.e. PWM period/255

With binary code modulation you only have to switch 8 times in the PWM period because these delay of these 8 switchings are doubled for each bit. So yes, you do need to switch as fast as the usual PWM method for the first bit but you delay twice as long for the 2nd bit, 4 times as long for the 3rd bit, etc. By the time you get to the 6th bit the delay is PWM period x 32/255 and for the 8th bit the delay is PWM period x 128/255.

only works if your timing accuracy is better than about half an LSB
This is trivially easy to do for the low order bits:

Code:
outpins b0

outpins b1
outpins b1

outpins b2
outpins b2
outpins b2
outpins b2
but harder for the high order bits. Attached are two dpscope screen dumps I took when tuning these timings. My 6 bits of brightness are bits 2-7 so bit 2 is the low order bit.
RGB LED Fader - bits 2-5.JPGRGB LED Fader - bits 6-7.JPG

It's difficult for me to tell if the timings of the high order bits is within that half an LSB requirement, and perhaps that's why I get an intermittent glitch in the light produced by my fader code.

What I discovered was that the "stand alone" commands I was using all seemed to take exactly the same duration, which was pretty close to 0.2ms. This meant that I could use the code that was calculating the new PWM values as the delay between the OUTPINS commands, instead of wasting bytes using the repeated outpins commands as in the simple example above. It also meant that tuning the length of a delay can be done by adding or removing dummy LET commands. You see this where I've assigned the same value to DELAYVAL variable several times before calling the delay subroutine.
 

womai

Senior Member
If you only need 6 bits of resolution then you only need yo increment 64 times with "normal" PWM either. To use the standard wraparound of a 8-bit variable just increment in steps of 4 instead of steps of 1.

BTW, I like the scope you use :)
 

premelec

Senior Member
@Flenser & womai - I don't follow completely what has been suggested here but having spent too much time in the past trying to get multiple PWM out from an 08M and giving up and putting in an 8 channel DAC to control current to LEDs and get it's settings from the 08M I'm intrigued that there may be a method to do it with higher frequency and pulsouts or simply selected HIGH LOWs for each pin... I'll study this some more... though the 14M2 has pretty well cured the problem I think - :)
 
Top