3
\$\begingroup\$

I'm interested in generating a PWM signal in software on a micro (it is not possible to use hardware PWM in this case). It is simple to use (for example) a loop with a counter that counts to 255 and wraps around, and transitions high-low when the counter hits N and low-high when it wraps around, for an N out of 255 pulse.

However, because this PWM is rather slow, I would like to smooth it out, as follows: if the output is (for example) high for 2 out of 255 counts, I would like the output to be high during the the 0th and 127th count, not the 0th and 1st. If it is 127 out of 255, I would like to transition low-high and high-low every count, instead of staying high for the first 127 and low for the last 128.

In other words, the lows and highs should be as evenly spread out as possible. I realize when the PWM is near either extreme of the range it would still have a large ripple, but this will reduce ripple a lot near the middle of the range. How to do this in an efficient way?

EDIT: It seems like I have rediscovered Pulse Density Modulation. I'm still not sure how to do this in practice, especially in a fast loop.

\$\endgroup\$
5
\$\begingroup\$

The following algorithm will do what you want:

period = 256;
on_time = 34; // Or whatever you want
off_time = period-on_time;
count = 0;
while (1);
{
    if (count >= 0) {
        count -= off_time;
        output_high();
    } else {
        count += on_time;
        output_low();
    }
    wait_for_next_cycle();
}

I did something like this to generate a 44100 Hz sample clock with a non-simple ratio from the master clock, but your question motivated me to generalize it, thanks.

\$\endgroup\$
4
\$\begingroup\$

What you are describing, if you think about it a moment, is quite simple. Whereas normally in PWM you keep the frequency the same but vary the pulse width, what you are describing is effectively to keep the pulse width the same but vary the frequency.

For a duty cycle of 1/256 you have one pulse every 256 counts.

For a duty cycle of 2/256 you have two pulses (traditionally joined together into one 2x width pulse) every 256 counts.

2/256 can be reduced to 1/128 (simple maths, yes?), so 2 pulses every 256 is the same as 1 pulse every 128 counts.

128/256 (50% duty) can be reduced to 1/2, which is one pulse every 2 counts, or a rapid on-off square wave.

So keep your pulse width at just 1 count (turn it on at 0 and turn it off at 1) and just change the value you're counting up to.

\$\endgroup\$
  • \$\begingroup\$ This is true. What about 127/256 though? That would be 1/2 except for one 1/3 pulse. 126/256 would have two 1/3 pulses which (ideally) are spaced 128 apart, etc. I am not sure how to produce output like that. \$\endgroup\$ – Alex I May 26 '15 at 3:23
  • 1
    \$\begingroup\$ Keep an accumulator and produce a pulse when the accumulator overflows. This is how most delta-sigma modulators are constructed. \$\endgroup\$ – alex.forencich May 26 '15 at 3:59
3
\$\begingroup\$

Sounds like you want a delta-sigma modulator instead of 'regular' PWM. A delta-sigma modulator emits a pulse density modulated output, moving the noise mostly to high frequencies so it is easier to filter out. Generally this is done with dedicated hardware to get a very high output rate, though I suppose there is no reason why you could not build one in software.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.