EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Precision PWM in microcontroller

Started by The Mind Factory INC December 28, 2003
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.


On Sun, 28 Dec 2003 20:46:40 -0500, "The Mind Factory INC"
<rsloan2003@hotmail.com> wrote in comp.arch.embedded:

> 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.
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 FAQs for comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
The Mind Factory INC wrote:
> 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. > >
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
The Mind Factory INC wrote:

> 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....
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
Thad Smith <thad@ionsky.com> writes:

> 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.
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() { accu += incr; /* check the MSB of accu */ if (accu & (1 << 31)) OUTBIT = 1; else OUTBIT = 0; } --- The output frequency depends on the interrupt frequency and the overflow value. For a 32-bit integer, the output frequency is: f_out = f_intr * incr / 2^32 Or, as usually the increment is required:: incr = 2^32 * f_out / f_intr This gives a very high resolution. In some cases it is possible to use a shorter accumulator (e.g., 16 bits). Making a software DDS is simple, but there are a few things which have to be taken into account: - While the frequency and duty cycle accuracy in the long run is extremely good, there is a lot of jitter due to the limited sampling frequency. A single cycle may have a very bad duty cycle (1:2 in the worst case). RMS jitter is sqrt(1/12) of the base cycle time, IIIC (if I integrated correctly). So, if the interrupt frequency is 50 kHz, maximum jitter is 10 us, and RMS jitter around 6 us. - This jitter cannot be made any smaller by using a f/f. (Using a f/f is the same as halving the output frequency.) - Increasing the base frequency decreases jitter and resolution. Usually the resolution is not a problem, so using as high base frequency as possible is a good idea. - In order to preserve spectral purity and avoid peaks, it is highly advisable to use only odd increments. This makes the period longest possible (2^32 cycles). A DDS is simple enough to be made with a CPLD or even discrete logic. Using a CPLD makes rather high base clock frequencies possible (sacrificing the low power consumption and cost, though). In case something else than a square wave is required, the use of a simple look-up table and a MML DAC (Mickey Mouse Logic DAC, a discrete resistor R/2R) may fulfill the requirements. - Ville -- Ville Voipio, Dr.Tech., M.Sc. (EE)
The Mind Factory INC wrote:
> 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. >
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 << 1Hz resolution ) is maybe doable in a co-operative uC, but 1Hz step is into a new device/power space (probably FPGA) ( so you need to be really sure your system _needs_ this :) This simple divider has nominally zero added jitter - you can get better AVERAGE or apparent resolution, at lower Fclk by allowing jitter. For this look into Rate Multipliers, and Direct Digital Synthesis (DDS) eg imagine the 40MHz system set for 19.99KHz for 9 of every 10 cycles, and 20.00 for 1 of every 10, you will measure 19.999KHz on a freq counter. == Rate Multiplier 'fractional interpolation' -jg
Ville Voipio wrote:
> > Thad Smith <thad@ionsky.com> writes: > > > 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. > > In case of a uC, this is easy to do in s/w.
<code snipped> Good point. I should have thought of that. The tradeoffs between hw/sw are basically low cost vs. low jitter.
> Making a software DDS is simple, but there are a few things > which have to be taken into account: > > - While the frequency and duty cycle accuracy in the long run > is extremely good, there is a lot of jitter due to the limited > sampling frequency. A single cycle may have a very bad duty > cycle (1:2 in the worst case). RMS jitter is sqrt(1/12) of > the base cycle time, IIIC (if I integrated correctly). So, if > the interrupt frequency is 50 kHz, maximum jitter is 10 us, > and RMS jitter around 6 us. > > - This jitter cannot be made any smaller by using a f/f. (Using > a f/f is the same as halving the output frequency.)
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).
> - In order to preserve spectral purity and avoid peaks, it is > highly advisable to use only odd increments. This makes the > period longest possible (2^32 cycles).
For a given fixed interrupt frequency and output frequency, though, the increment is fixed.
> > A DDS is simple enough to be made with a CPLD or even discrete > logic. Using a CPLD makes rather high base clock frequencies > possible (sacrificing the low power consumption and cost, though).
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
Thad Smith <thadsmith@acm.org> writes:

> Good point. I should have thought of that. The tradeoffs between hw/sw > are basically low cost vs. low jitter.
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.
> There is a refinement, though, that will reduce jitter: compute the > timer interval, based on the number of timer reference cycles per output > cycle.
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...)
> > - In order to preserve spectral purity and avoid peaks, it is > > highly advisable to use only odd increments. This makes the > > period longest possible (2^32 cycles). > > For a given fixed interrupt frequency and output frequency, though, the > increment is fixed.
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 :)
> 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.
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. http://www.analog.com/ - Ville -- Ville Voipio, Dr.Tech., M.Sc. (EE)
Ville Voipio wrote:
> > Thad Smith <thadsmith@acm.org> writes: > > > There is a refinement, though, that will reduce jitter: compute the > > timer interval, based on the number of timer reference cycles per output > > cycle. > > 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.
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.
> > > - In order to preserve spectral purity and avoid peaks, it is > > > highly advisable to use only odd increments. This makes the > > > period longest possible (2^32 cycles). > > > > For a given fixed interrupt frequency and output frequency, though, the > > increment is fixed. > > 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 :)
That should be sufficient. ;-) Thad
Thad Smith <thadsmith@acm.org> writes:

> 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
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.)
> 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.
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.
> 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.
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)

The 2024 Embedded Online Conference