Timer2 prescaler/frequency

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

So, I've been experimenting with AVR timers for a soon-to-be Arduino project and I've been setting up an RTC using timer2. Everything is working, but not the way I expect.

 

I popped off the external oscillator for an Arduino Pro Mini and replaced it with a 32.768khz crystal. I set the clock fuse bits to use the internal 8Mhz clock, then set the code to use the 32.768khz crystal for timer2 in asynchronus mode.

 

ISR(TIMER2_OVF_vect) {

  RTC_OVF++;
  if (RTC_OVF >= 1) { //128 overflows = 1 second? But setting it to one overflow produces the expected result instead
    PORTB ^= (1 << PB5);
    RTC_OVF = 0;
  }
}

void setup() {
  DDRB |= (1 << DDB5);
  PORTB = 0;

  TIMSK2 = 0; //Clear interrupt mask
  ASSR |= (1 << AS2); //Set ansychronous clock
  TCNT2 = 0;  //Clear timer counter
  while (ASSR & ((1 << TCN2UB) | (1 << TCR2BUB))); //clear a bunch of busy flags?
  TCCR2B |= 0x00; //(1 << CS20); //Set prescaler to 1?
  TIFR2 = (1 << TOV2);  //Set overflow interrupt
  TIMSK2 |= (1 << TOIE2); //Set overflow interupt mask
}

 

This works, but the problem is one overflow is apparently taking a full second. That's ultimately what I want but by my math it should take 128 overflows to get to a full second. I suspect it has something to do with the prescaler. It seems that gives it a prescaler of 256 while setting TCCR2B to 0 gives it a prescaler of 128. It should be prescaler of 1 and disconnect the clock, respectively.

 

Anybody know this is happening?

Last Edited: Tue. Mar 13, 2018 - 12:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SuperMechaCow wrote:
TCCR2B |= 0x00; //(1 << CS20); //Set prescaler to 1?

Which AVR model?  Mega328 on a Pro Mini?

 

|= 0 does nothing.

 

Is this an Arduino sketch?  Don't they have default setup for the timers?  Get rid of the |= and set up the timer "from scratch".  If TCCR2B is really 0 then the timer is not running.

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

Just add some accurate comments:

void setup() {
  DDRB |= (1 << DDB5);
  PORTB = 0;

  TIMSK2 = 0; //Clear interrupt mask
  ASSR |= (1 << AS2); //Set ansychronous clock
  TCNT2 = 0;  //Clear timer counter
  while (ASSR & ((1 << TCN2UB) | (1 << TCR2BUB))); //clear a bunch of busy flags?
  TCCR2B |= 0x00; //(1 << CS20); //does NOTHING
  TIFR2 = (1 << TOV2);  //CLEARS ANY PENDING overflow interrupt
  TIMSK2 |= (1 << TOIE2); //Set overflow interupt mask
  // GLOBAL INTERRUPTS HAVE NOT BEEN ENABLED
}

It is always wise to use = rather than |= when initialising whenever appropriate.

 

It is also wise to report your actual fuse values.   And your programming method.

Most Arduino bootloaders are safe.    Some bootloaders leave the AVR is an undetermined state.

 

David.

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

It would help if you posted a complete sketch that demos the problem, as shown, t2 should not run at all with the CS bits set to zero.

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

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

david.prentice wrote:
// GLOBAL INTERRUPTS HAVE NOT BEEN ENABLED
Doesn't the presence of setup() mean "Arduino" ? I thought, because it uses things like timers itself, it already did an sei() on the way into setup()/loop(). Or are you saying it's after setup() and before loop()?

 

EDIT: yup I thought so:

// main.cpp
int main(void)
{
	init();

	initVariant();

// wiring.c
void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();

Actually I'm astonished that Arduino does it's own sei() before it gets into setting up its timers and so on!

Last Edited: Tue. Mar 13, 2018 - 01:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW later in wiring.c I see it doing:

	// set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
	sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
	sbi(TCCR2B, CS22);
//#else
	// Timer 2 not finished (may not be present on this CPU)
#endif

	// configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
	sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
	sbi(TCCR2A, WGM20);
//#else
	// Timer 2 not finished (may not be present on this CPU)
#endif

So Arduino is already using Timer2 for it's own purposes. Therefore I would be especially careful in resetting EVERY bit in EVERY register if "taking over" as you don't want to end up inheriting some settings! As such this line is more dangerous than it looks....

  TCCR2B |= 0x00; //(1 << CS20); //Set prescaler to 1?

Even if we assume that the 0x00 is just "temporary testing" then if the real line is supposed to say:

  TCCR2B |= (1 << CS20); //Set prescaler to 1?

Then the |= in this is going to mix with:

	sbi(TCCR2B, CS22);

so no wonder the timer is going MUCH slower than OP expected!!

 

Lesson here - NEVER ever use |= unless you absolutely, positively know what you are doing and are sure of the setting of every other existing bit in the register.

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

Oops.   I had not noticed it said setup() and not main()

 

You can run regular C code on Arduino hardware.    If you had used main(),   you would not need a setup() and loop().

However,  if you are linking with a regular Arduino core,   you need both setup() AND loop().

 

The moral of the story is.    Post a complete program.   Provide any necessary information.

e.g.  a Pro Mini is often used with an external programmer.

e.g.  a Pro Mini needs an external USB/RS232 adapter if it uses the Arduino bootloader.

 

David.

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

david.prentice wrote:
I had not noticed it said setup

Well, just because there is a function called setup() doesn't necessarily mean Arduino environment.  But it sure is a clue and would explain some of the symptoms given the |=

 

 

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, guys!

 

The confusion was when I moved from AVR C to Arduino I expected TCCR2B to be set to 0x00 by default as per the datasheet.

 

The reason for this wonky line is I often forget the code, so I use a lot of comments in case I need to undo and experiment.

TCCR2B |= 0x00; //(1 << CS20); //Set prescaler to 1?

I thought this was leaving TCCR2B at 0, and if I wanted to set it back to 0x01 I could just erase the 0x00 and uncomment the (1 << CS20).

 

Where things got messed up is the register is set to 0x05 by the Arduino build process where I was expecting a default to be 0x00.

 

TL;DR: As many people pointed out, I used |= instead of =.

Thank you everyone for your help! It works now!

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

As I say the lesson here is to be very sparing with your use of |=. Only ever use it if you are definite you know the state of every other bit in the register.

 

We see tons of threads here where beginners basically do ALL their register setups with |=. This is just plain wrong.

 

Sure, later, when you have set ADCSRA (say) and now you want to trigger an ADC conversion it's quite possibly to just OR the ADSC bit into it to get things started. You might even do the same with a timer - once everything else is set you might OR the CSnn bits into it to finally start it running - but these things are the exceptions, not the rule.

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

We see tons of threads here where beginners basically do ALL their register setups with |=. This is just plain wrong.

I did mean to change it but it got missed. I usually use |= when I don't know what else is in the register by default. Again, if this code was in AVR C and not Arduino it would have worked. Sloppy but functional.

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

SuperMechaCow wrote:
Again, if this code was in AVR C and not Arduino it would have worked. Sloppy but functional.

"Worked"  -- I guess; under certain conditions.  >>IF<< your AVR arrives at that line due to an AVR reset, then you'd have an expectation that it will "work".  What if your AVR arrives at word 0 without doing a reset?

 

Never attempt to teach a pig to sing; it wastes your time and annoys the pig.

In this case, the annoyed pig is the RMW  sequence required to implement your method.  Besides introducing possible RMW problems, instead of a two-word LDI/OUT sequence at best it will be IN/ORI/OUT.

 

As Cliff dug out by example, if you are going to transition to Arduino (and nothing wrong with that) then you need to be aware that there is "stuff" done to prepare that environment. 

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:
there is "stuff"
Most "stuff" in:

 

\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino

 

in particular a lot of code in wiring.c in that directory.

 

Don't be afraid to explore "inside" the Arduino support code - the more you know about what it's doing the less likely you are to "bump into" things. Consider for example that for analogWrite() it will be cranking up PWM modes on timers and for Serial.print() it will be winding up the UARTs and so on.

Last Edited: Tue. Mar 13, 2018 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Consider for example that for analogWrite() it will be cranking up PWM modes on timers

I seem to recall that all timers are started in PWM mode?  Whatever.

 

https://www.avrfreaks.net/commen...

theusch wrote:
As I am fond of saying: https://www.avrfreaks.net/comment... For some reason, many posters on this site have a love affair with |=. There must be a sale on "|" in full-reel quantities.

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.