Precision PWM in microcontroller

Looking for a 1hz resolution PWM in a small micro.... 0-20Khz preferred duty cycle is 50/50 but can be off this a bit....

Any ideas, have searched high and low and found nothing.

Richard.

Reply to
The Mind Factory INC
Loading thread data ...

On Sun, 28 Dec 2003 20:46:40 -0500, "The Mind Factory INC" wrote in comp.arch.embedded:

Look at:

TI 24xx DSPs. TI 28xx DSPs. Motorola HS12 micros.

Without double checking, I think all of these can do what you want.

--
Jack Klein
Home: http://JK-Technology.Com
 Click to see the full signature
Reply to
Jack Klein

Hi,

Let me see if I get this right.

You want a frequency of 0-20Khz with a 50/50 duty cycle.

A 25uSec square wave is 40Khz. Feeding a flip-flop (i.e. 7474) the Q side of the 7474 would be at 20Khz with a 50% duty cycle.

So any micro that can generate a 40Khz square wave and a 7474 will do what you want.

Unless I did not get this right.

hamilton

Reply to
hamilton

This request is confusing. If you want to perform Pulse Width Modulation (PWM), then the duty cycle is going to vary from 0 to 100%, but the frequency is usually constant.

Are you wanting to generate different frequencies? If so, an external Direct Digital Synthesizer (DDS) will do what you want. These can be programmed to generate an accurate frequency. They require an external reference frequency.

Thad

Reply to
Thad Smith

In case of a uC, this is easy to do in s/w. The interrupt frequency has to be more than double the highest output frequency. The algorithm itself is simple:

--
uint32_t accu, incr;

interrupt timer_int()
 Click to see the full signature
Reply to
Ville Voipio

PWM - Pulse Width Modulation Usually this is defined in Nominal Freq, and range of duty cycle ( eg 10KHz, 0..100%) If you define 0..20KHz and 1Hz resolution, that's sounding like it's actually a frequency synthesiser you are after. You should also separate resolution from step size - they are not always the same thing.

Most small uC generate PWM by prescale and then a fixed counter/compare. Some of the newer/better ones also allow the counter/compare ceiling to be non binary ( eg 100, 200, 487 etc rather than 256/512 ) - this can help with the PWM aspect, but not so much the Freq Synthesis.

If you take a non-jitter divider path, your Fi is set by

19.999KHz and 20.000KHz being one divide unit appart.

Starting coarser, to get the trend :

19KHz step to 20Khz is 1 part in 20, or 400KHz Fclk 19.9KHz step to 20.0Khz is 1 part in 200, or 4MHz Fclk 19.99KHz step to 20.00Khz is 1 part in 2000, or 40MHz Fclk 19.999KHz step to 20.000Khz is 1 part in 20,000, or 400MHz Fclk (!)

So you can see 10Hz steps ( with

Reply to
jim granville

Good point. I should have thought of that. The tradeoffs between hw/sw are basically low cost vs. low jitter.

There is a refinement, though, that will reduce jitter: compute the timer interval, based on the number of timer reference cycles per output cycle. By carrying over fractions of a cycle, like you do in the fixed interrupt frequency case, you will, in general, alternate between two consecutive values for the interrupt duration. The max jitter, then, would be one timer unit, plus whatever variation there is in interrupt response (greatly affected by other interrupts of equal or higher priority interrupts or disabled sections).

For a given fixed interrupt frequency and output frequency, though, the increment is fixed.

OK. If you aren't otherwise using the CPLD and need the HW solution, though, an off-the-shelf DDS is probably easier, cheaper, lower power.

Thad

Reply to
Thad Smith

Plus low power consumption and small size in the case of a uC. You can make some rather funny things even with a small uC, if you do not need a high frequency. I once made a simple synthesizer with a small AVR ('2313) and a bunch of resistors. Four simultaneous waveforms were possible.

You are right. However, as then the update frequency changes, it becomes rather difficult to maintain accurate frequency and duty cycle in the long run. I think it is better either use a pure DDS or a simple frequency divider (possibly with fractional divisor adjustments). Mixing the two sounds rather difficult. (But no, I've never calculated it through...)

It is. But in case you have enough resolution, this is not a problem. With 50 kHz update frequency and a 32-bit increment, the smallest frequency step is around 12 uHz... So, if you sacrifice the last bit, then the resolution is 24 uHz. Don't look at the crystal, as the heating effect of your glance will shift the frequency :)

I don't know. If you need only a digital DDS signal, then the CPLD solution may be very competitive. Depending on your control system, a

64-cell CPLD should be able to make a 20-bit CPLD. The cost is a few euros/dollars, and the maximum speed hundreds of MHz with a low- power chip (such as Xilinx XC2-family or Lattice 4000Z). If you can store the increment in external shift registers, then a 32-cell CPLD is enough for a 32-bit DDS. The program is extremely simple.

However, if you need phase control, sinusoidal output, or any other radioish features, then the integrated solutions are certainly better.

formatting link

- Ville

--
Ville Voipio, Dr.Tech., M.Sc. (EE)
Reply to
Ville Voipio

It's not hard. The main issue is updating the timer on the fly. The easy way is stop timer timer = timer - ((next interval) - offset) start timer

where offset is the number of timer increments missed while the timer is disabled.

By adding the interval to the timer, rather than reloading it, you compensate for the variable latency in servicing the timer interrupt.

To get an accurate long-term frequency, the next interval is determined for each interrupt. You can use fixed point arithmetic, such as your earlier example, to determine when the go to the next higher timer count, or you can use Bresenham's method. With Bresenham's method, you will get no bias, as long as you can exactly represent the number of timer ticks per second and the frequency, in Hz, in the integer type used for the accumulator variable. For practical purposes, the fixed point arithmetic would be fine, and produces simpler code in the interrupt routine.

That should be sufficient. ;-)

Thad

Reply to
Thad Smith

This wasn't the hard part... (IIRC, I have had to do something like this with MCS51 processors and their limited automatic reload capa- bility.)

I started thinking about this after my earlier post. You are right, a simple division is just fine. Something like this:

steps = (accu / incr) + 1; accu -= steps * incr;

This should give the number of steps required for the next overflow (carry-around). However, for computational reasons this might be better calculated by:

steps = (accu / incr) + 1; accu = (accu % incr) - incr;

as the division operation should give the remainder, as well. If the compiler is bright enough to notice this, that is. Or, I guess, it is probably better write the operation in assembly to make it quicker. There seems to be some space for optimization.

This operation should be fast enough for the 20 kHz with a simple processor. And the jitter goes down to one cycle plus interrupt latency. Even the latency can be avoided but it requires some interesting interrupt code.

Bresenham sounds like an interesting candidate, because it does not require the division. And in this case there is no need for the complicated "which octant" thinking. However, I could not find a reason why it should preserve the duty cycle. By thinking of a graphics analogy, it is possible to make it go 2:3:2:3:2:3:2:3...

- Ville

--
Ville Voipio, Dr.Tech., M.Sc. (EE)
Reply to
Ville Voipio

Silly me. Seems that I've already used all brain capacity reserved for this year...

Once again... With a few lines of modulo calculations, a much simpler algorithm is revealed. The division can be made beforehand to avoid calculations.

rembase = ofvalue % incr; stepbase = ofvalue / incr;

where ofvalue is the overflow value of the accumulator. It may be rather handy to choose it so that a single step is, say, 100 uHz.

Each interrupt carries the following calculations:

OUTPUT = !OUTPUT; rem = rem + rembase; steps = stepbase; if (rem >= incr) { rem = rem - incr; steps = steps + 1; }

And that's it. Fast, simple, and can use smaller integers in many cases. (And familiar, see Bresenham :)

In practice, the counter can be preloaded with "stepbase" and then adjusted by one when necessary.

... and this can be avoided by the choice of the overflow value and the increment. The same problems apply to the DDS with certain overflow values and increments, as the algorithm is the same.

- Ville

--
Ville Voipio, Dr.Tech., M.Sc. (EE)
Reply to
Ville Voipio

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.