Device suggestion: Flexible PWM (freq, duty variable?)

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would like to have 3 timers make a synchronized digital pattern; unfortunately I need to have control of both the frequency and duty cycle of each of them. Fastest one is about 400kHz.

It looks like the ATMEGA allows this kind of thing only on TIMER1 using the ICR1 register; both timer0 and timer2 are fixed frequency (aside from the prescaler).

Is there an AVR device that allows this? In other words, a device that has ICR0 and ICR2?

Other methods/workarounds?

(I did try bitbanging two of them using an interrupt and manually counting, but it's not fast enough.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Take a look at the xmega devices

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It looks like the ATMEGA allows this kind of thing only on TIMER1 using the ICR1 register;

This will depend on the particular model of Mega.

On a Mega88, for example, the 8-bit timers have a variable TOP using OCRnA. (Then the B channel must be used for the output.) Of course, you will then have much more limited selection of period than with a 16-bit timer.

Other Mega models have multiple 16-bit timers.

If this is the primary thrust of the app, have you considered AT90PWM3xx?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks! The xmega looks like a reasonable option, and I'm surprised the prices are comparable. (ATXMEGA32)

I was originally designing for an ATMEGA328, which has the same counter scheme as the ATMEGA88. However, changing TOP alone only alters duty cycle; it won't allow me to change the frequency (except through prescaling). Control of frequency and duty together seems to be only possible in Timer1, which has the ICR1 setting. Am I mistaken?

(I don't need them to be 16 bit, but it doesn't hurt!)

The AT90PWM3xx looks interesting but I need more than 16k (32k would be nice).

I have experience designing to ATTINY and ATMEGA, but these other chip series are new to me.

The primary important task is indeed this waveform output (replacing a CPLD), and it also drives an LCD, runs I2C, a couple UARTS, and programs a DSP (thus the flash need). Nothing unusual.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

However, changing TOP alone only alters duty cycle; it won't allow me to change the frequency (except through prescaling). Control of frequency and duty together seems to be only possible in Timer1, which has the ICR1 setting. Am I mistaken?

Are you mistaken? Yes.

The mode(s) with OCR0A/OCR2A as TOP correspond to the mode(s) with OCR1A as TOP.

When OCR0A/OCR2A are TOP, then you have the restriction on not using OC0A/OC2A as a "usable" PWM output. And you will be limited in range and precision, given that it is an 8-bit timer. 400kHz PWM frequency is quite fast for an AVR8 anyway. Lessee--at 20MHz that is 50 steps, right? So each count of duty cycle would be 2%, 8-bit or 16-bit timer.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, this is helpful - can you please clarify? Maybe I don't have to switch chips after all.

Currently Timer1 uses ICR1 and OCR1A to set frequency and duty cycle. For example, ICR1=50, OCR1A=25, per your example, to create a 50% duty cycle at 400kHz.

How would I do the same with TIMER0 and TIMER2? For each output pin, I only have one degree of freedom: OCR0A for example. How would I control both duty cycle and frequency independently, as I can with TIMER1?

(I'm fine with the low resolution in this case, as long as I can sync all three timers.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Both timer 0 and timer 2 can use OCRA for frequency and OCRB for duty cycle (using mode 7 or mode 5).

Quote:
(I'm fine with the low resolution in this case, as long as I can sync all three timers.)
This might be a bigger problem. Timer 0 and timer 1 share a prescaler, so synchronizing should be easy. Timer 2 has a separate prescaler, so it would be more difficult to sync it with the other two.

Regards,
Steve A.

The Board helps those that help themselves.

Last Edited: Tue. May 6, 2014 - 02:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 20000.000 kHz
// Mode: Fast PWM top=OCR0A
// OC0A output: Disconnected
// OC0B output: Non-Inverted PWM
// Timer Period: 2.5 us
// Output Pulse(s):
// OC0B Period: 2.5 us Width: 0.81633 us
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00);
TCCR0B=(1<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0x00;
OCR0A=0x31;
OCR0B=0x10;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 20000.000 kHz
// Mode: Fast PWM top=OCR2A
// OC2A output: Disconnected
// OC2B output: Non-Inverted PWM
// Timer Period: 2.5 us
// Output Pulse(s):
// OC2B Period: 2.5 us Width: 1.6327 us
ASSR=(0<<EXCLK) | (0<<AS2);
TCCR2A=(0<<COM2A1) | (0<<COM2A0) | (1<<COM2B1) | (0<<COM2B0) | (1<<WGM21) | (1<<WGM20);
TCCR2B=(1<<WGM22) | (0<<CS22) | (0<<CS21) | (1<<CS20);
TCNT2=0x00;
OCR2A=0x31;
OCR2B=0x20;

Make OC0B and OC2B outputs. OCnA sets the period; OCnB sets the duty. Just like timer1.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Synchronizing is left as an exercise for the reader. :twisted: See GTCCR and TSM. I'm not real familiar with that.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are awesome, thanks. I have much to learn.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Or are there other settings to worry about that are special for TIMER1?

Well, the quickie answer is: What does the datasheet say? (and that will depend on the particular AVR8 model, though timer1 on most Megas is pretty much (if not totally) the same.

So, I go back to the "Table nn-m. Waveform Generation Mode Bit Description" table for each timer. See the correspondences?

Remember that if you use OCRnA as TOP, then you can't use OCnA output for your PWM.

Going back to the beginning,

Quote:

I would like to have 3 timers make a synchronized digital pattern; unfortunately I need to have control of both the frequency and duty cycle of each of them.

Now, if the frequencies of these waveforms are different--then they aren't going to be "synchronized" after the first period. I'm guessing that they really are the same frequency? If so (or if two of them are) then timer1 can support two (or more depending on model) PWM outputs with varying duty cycle.

Or by "synchronized" do you mean one of the phase-correct modes?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. Got it all working; there was just one extra flag (WGM13) to set for TIMER1 (silly oversight, that's why I deleted my post).

All of the signals are based on the same "base" frequency, so they do align. This did require a little klugdging, however, since the OCRxA settings required for alignment weren't exact multiples of each other, even if my PWM frequencies were. For example, if I had OCR1A=20, I needed to set OCR2A=125 (instead of 120) to make them sync for a 6x multiple. Not quite sure why this is, but there are probably some counting subtleties described in the datasheet. (Resetting the counter takes a cycle or something like that.)

The timers were easy to sync with GTCCR:


GTCCR = (1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); // halt all timers
TCNT0 = offset0; // set timer0 to its offset
TCNT1H = 0; // set timer1 high byte to 0
TCNT1L = 0; // set timer1 low byte to 0
TCNT2 = offset2; // set timer2 to its offset
GTCCR = 0; // release all timers

(found elsewhere online)

Halt them, set their relative offsets that I wanted, and restart. Very straightforward it seems.

Can TIMER1 support two PWM outputs with the same frequency and duty cycle, but shifted (offset) from each other in time? Not a big deal but it would save me a timer to use elsewhere.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

For example, if I had OCR1A=20, I needed to set OCR2A=125 (instead of 120)

Notice in my example posted code, for 50 counts (400kHz at 20MHz) I set the TOP register to 0x31 = 49. Not 50. You count 0,1,2,3,...,n-1,n,0,1,... So if TOP is 49, then it is 50 counts.

So if you want 6x 21 counts (1/6 the frequency), then you need to set TOP to 126 counts, which would be 125.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.