ATmega2560 fast pwm as frequency generator OCRnA only 10 bits?

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

Hi,

 

I am trying to use fast pwm (mode 15) as a (variable) frequency generator. For some reason, OCRnA only accepts 10 bits, if I put in larger values, they get clipped to 10 bits. This is contrary to what the datasheet says:

 

"The PWM resolution for fast PWM can be fixed to 8-bit, 9-bit, or 10-bit, or defined by either ICRn or OCRnA. The minimum resolution allowed is 2-bit (ICRn or OCRnA set to 0x0003), and the maximum resolution is 16-bit (ICRn or OCRnA set to MAX)."

 

Code:

	TIMSK1 = 0;
	TCNT1H = 0;
	TCNT1L = 0;
	TCCR1A = _BV(COM4A0) | _BV(WGM41) | _BV(WGM40); // toggle OCnA on match
//	OCR1A = 1024; // same as setting to zero
	OCR1A = 1023; // works and outputs expected freq
	TCCR1B = _BV(WGM43) | _BV(WGM42) | 1;

 

If I use mode 14 and ICRn for TOP, this problem is not seen (i.e. values above 1023 work as expected), but the output toggle mode is only available when using mode 15. I might try CTC mode, but that doesn't feature the OCRnA double-buffering feature, unfortunately.

Am I doing something wrong, or what's going on? I am using an oscilloscope to verify the output, btw...

 

Cheers...

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

So do you want PWM or not?

 

What is the frequency range you are trying to generate?  If fairly slow, I don't see where the double-buffering is all that important as you can "race" the change doing it at overflow.  And if fast -- say, ~1MHz -- then what difference does it make if you have a runt or extended pulse between many many fast pulses?

 

I'll have to get back to the datasheet about mode 14/15 differences.  Can't remember any; must not have been important in my apps.

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

I don't want pwm, but I like the double-buffering feature.. I need a frequency range of sub-Hz to several (or tens) of kHz, and I want to try to avoid using an overflow/match ISR, which is why double-buffering comes in handy.

 

My question was not so much about a work-around, I just want to understand why mode 15 doesn't appear to work as documented and have that verified, then I'll take the work-arounds from there..

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

hooverphonique wrote:
I don't want pwm,

Then I'd use CTC.

 

hooverphonique wrote:
and I want to try to avoid using an overflow/match ISR, which is why double-buffering comes in handy.

 

At those low frequencies an ISR each "hit" shouldn't be much of a problem cycle-wise.  That would be plan A.  Plan B would be to enable the ISR invocation only when a change is needed.  The ISR can turn itself off.  Plan C would be to poll the overflow flag when a change is needed.  (be sure to clear the interrupt flag  before enabling plan B or C)

 

So, then, besides the frequency range you gave the above brings up the next question:  How often will the setpoint be changed?

 

 

 

hooverphonique wrote:
I just want to understand why mode 15 doesn't appear to work as documented ...

 

Tell me how you are verifying that larger values of OCR1A don't "take".

 

Interesting use of Timer4 bit names for Timer1 setup, but indeed AFAIK timers 1,3,4,5 are identical?

 

Is that a typo in the "toggle" section -- is OCnA intended instead of OC1A etc?

 

[edit] Sanity check:  Peek at the chip-include definitions of the bit names to make sure there is no typo there with the various WGM... defines?

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.

Last Edited: Fri. Nov 4, 2016 - 02:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Peek at the chip-include definitions of the bit names to make sure there is no typo there with the various WGM... defines?

If WGM43 in your posted code isn't correct, then that might indeed turn mode 15 into mode 7 and explain your symptoms?

 

Tell you what -- post the .LSS or equivalent for your toolchain (have you told us toolchain and version?) fragment for the timer register setting to see the actual values.

 

And another sanity check -- TCCR1B not touched anywhere else?

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.

Last Edited: Fri. Nov 4, 2016 - 03:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
C:\SysGCC\avr\avr\include\avr>grep WGM iomxx0_1.h | sort
#define WGM00   0
#define WGM01   1
#define WGM02   3

#define WGM10   0
#define WGM11   1
#define WGM12   3
#define WGM13   4

#define WGM20   0
#define WGM21   1
#define WGM22   3

#define WGM30   0
#define WGM31   1
#define WGM32   3
#define WGM33   4

#define WGM40   0
#define WGM41   1
#define WGM42   3
#define WGM43   4

#define WGM50   0
#define WGM51   1
#define WGM52   3
#define WGM53   4

A quick peek at the datasheet seems to suggest that is all correct. This was in:

C:\SysGCC\avr\avr\include\avr>grep #define version.h
#define _AVR_VERSION_H_
#define __AVR_LIBC_VERSION_STRING__ "2.0.0"
#define __AVR_LIBC_VERSION__        20000UL
#define __AVR_LIBC_DATE_STRING__    "20150208"
#define __AVR_LIBC_DATE_            20150208UL
#define __AVR_LIBC_MAJOR__          2
#define __AVR_LIBC_MINOR__          0
#define __AVR_LIBC_REVISION__       0

Maybe OP has an older version? (this is an avr-gcc 5.3 with AVR-Libc 2.0.0)

 

EDIT: grouped the WGMs to make it more obvious.

Last Edited: Fri. Nov 4, 2016 - 03:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
EDIT: grouped the WGMs to make it more obvious.

Do we even know if OP is using GCC?

 

(As a wild guess, there is code somewhere else that might be changing the prescaler (in TCCR1B) for a different range and using an "old" mode...)

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

Well I suppose another C compiler may have borrowed the _BV() macro he's using - but I kind of doubt it. So yes. ;-)

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

There is a reason that I usually ask for a complete test program that demonstrates the symptoms. ;)  That gives us enough clues.  But I didn't do that here -- until  now.

 

 

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

theusch wrote:

So, then, besides the frequency range you gave the above brings up the next question:  How often will the setpoint be changed?

 

The setpoint will change quite often - several times per second.

 

theusch wrote:

Tell me how you are verifying that larger values of OCR1A don't "take".

 

when using values above 1023, it is clear from the resulting frequency that the value is truncated at 10 bits.

 

theusch wrote:

Interesting use of Timer4 bit names for Timer1 setup, but indeed AFAIK timers 1,3,4,5 are identical?

 

Is that a typo in the "toggle" section -- is OCnA intended instead of OC1A etc?

[/theusch]

 

I think it must be a typo; the whole sentence is sort of gibberish.. anyway, I tried timers 1,3,4 and 5, and got the same result on all.

 

I am using avr-gcc from the latest (2010 vintage) winavr build (4.3.3). The bit definitions look solid..

 

After some more fooling around, I discovered that it will produce the correct frequency when OCRnA is larger than 1023, but *only* if I write to OCRnA *after* I set TCCRnB, so the lesson learned is, that the WGM bits must be set correctly *before* writing to OCRnA. If WGMn3:2 are zero (mode 3, TOP=0x3FF) when OCRnA is written, it apparently gets truncated devil

 

 

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

hooverphonique wrote:
The setpoint will change quite often - several times per second.

In microcontroller terms, that's not too bad.  The reason for the question is plan C -- polling for the overflow bit.  At, say, 1kHz that is only about a millisecond a few times a second -- not bad.  And one doesn't have to "hard" poll in a tight loop; other things could be done.  But at that point I'd use plan B.

 

hooverphonique wrote:
After some more fooling around, I discovered that it will produce the correct frequency when OCRnA is larger than 1023, but *only* if I write to OCRnA *after* I set TCCRnB, so the lesson learned is, that the WGM bits must be set correctly *before* writing to OCRnA. If WGMn3:2 are zero (mode 3, TOP=0x3FF) when OCRnA is written, it apparently gets truncated

Hmmm -- I guess it was starting in a different mode?  And "latches" the compare value?  Dunno.  Since starting with AVRs 15+ years ago, I [almost] always use the CodeVision Wizard order of register initialization; e.g.

 

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000.000 kHz
// Mode: Fast PWM top=0xFF
// OC0A output: Non-Inverted PWM
// OC0B output: Disconnected
// Timer Period: 0.256 ms
// Output Pulse(s):
// OC0A Period: 0.256 ms Width: 0.256 ms
TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0x00;
OCR0A=0xFF;
OCR0B=0x00;
...
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

But that order has always bothered me as well -- the timer will start with OCRs at 0 and create some kind of weird cycle along with undoubtedly setting a compare match bit.  In most apps it doesn't matter.

 

I have a controller series that uses your AVR family and use several timers, but no PWM.

 

If I had to guess your sequence might also "fail" on e.g. Mega328 family?  Dunno--that '640 family is pretty old as AVRs go so that timer hole might have been closed.

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

theusch wrote:
Hmmm -- I guess it was starting in a different mode?

 

You'd think nothing much would happen without the timer starting.  And why only a problem in mode 15 and not 14?  Is it GCC?  Did you peek at the LSS fragment?  As the register assignments are volatile I wouldn't think it would be changing statement order.

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

theusch wrote:

 

You'd think nothing much would happen without the timer starting.  And why only a problem in mode 15 and not 14?  Is it GCC?  Did you peek at the LSS fragment?  As the register assignments are volatile I wouldn't think it would be changing statement order.

 

 

That's because there are no fixed resolution modes when using ICRn for defining TOP. If the WGM bits are set to a fixed resolution mode when you write OCRnA, apparently it gets truncated (WGM modes 5/6/7), so the solution is to set WGM first, with a prescaler value of zero to prevent the timer from running, then set OCRnA, then set the desired prescaler bits without changing the WGM bits. This of course only applies to the first time you set up OCRnA before starting the timer - after things are running, you can change OCRnA to your hearts content.

 

 

Last Edited: Fri. Nov 4, 2016 - 07:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	TIMSK1 = 0;
	TCNT1H = 0;
	TCNT1L = 0;
	TCCR1A = _BV(COM4A0) | _BV(WGM41) | _BV(WGM40); // toggle OCnA on match Here you set mode 3
//	OCR1A = 1024; // same as setting to zero
	OCR1A = 1023; // works and outputs expected freq
	TCCR1B = _BV(WGM43) | _BV(WGM42) | 1;           //                      Here you change to mode 15

 

 

While the timer compare logic >>could<< have been designed to simply ignore the higher bits when in these fixed lower-res modes, that is not the case.  In these modes, the higher bits are masked to zero when they are written to OCRnx, even if the timer isn't clocked.

 

This has bitten others in the past, including myself ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]