Issue with Timer2 in CTC mode on the arduino uno board

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

Hi everyone,

First, sorry for my english, it's not my maternal langage smiley-wink.

I try to configure the Timer2 of the atmega328 microcontroler in CTC mode.
For this, I defined the OCR2A register but, at the execution of the above code, I always get
the same values on my counter when I print it on the Serial port (in the loop statement). Normaly,
more the value of OCR2A is lower, more the value of my counter should be greater. Also, I tried many prescalers, same problem.

Here my code :

static volatile  unsigned long timerr = 0;
void setup() {
  Serial.begin(9600);
  
  //timer2 setup
  OCR2A = 255; // <-- if i change this value, the timerr values are always the same at the execution
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;
  TCCR2A |= (1 << WGM21); // Configure timer 2 for CTC mode 
  TIMSK2 |= (1 << OCIE2A);

   TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                   //1024 prescaler
 
  sei(); 

  timerr=0;
}     

void loop() {
 
  delay(4000);
  Serial.println(timerr); // <-- produce always the same values
  
}

ISR (TIMER2_COMPA_vect)
{    
  timerr += 1;    
}

Can you explain that ?

Thanks in advance.[/code]

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

Your code looks absolutely fine to me. i.e. CTC mode with div1024.

You will get a match every 256 ticks (OCR2A+1)
Each tick is 1024/F_CPU seconds e.g. 64us
So match every 16.384ms.

I will try it for myself!

David.

Edit. It produces the same for any OCR2A:

62244
124750
187256
249762
312268
374774
437280
499786
562292
624798
...

I would expect 244, 488, 732, ... i.e 244 matches in 4000ms.

AFIK, the Arduino system timer housekeeping uses Timer0 rather than Timer2. But I would have to check.

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

Thanks David !

I've got exactly the same results ! I will try with the timer 0 as soon as possible.
Anyway, keep me informed if you have more results.

Regards,
Yves

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
62244 
124750 
187256 

Regardless the first value (because initialization of the time in setup()), the difference between 187256 and 124750 gives me 62506. It corresponds to the calculation :

4000/(1/16000000*1024* 1000 * 1)

where 4000 is the delay time in the loop statement in ms, 1024 the prescaler, 1000 is the multiplier to have ms and 1 is the value of OCR2A. Therefore I have always this results as if OCR2A is always setted to '1' value.

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

Don't ask me why.

I just re-wrote setup() in my style:

void setup() 
{
    Serial.begin(9600);
    TCCR2A = (1 << WGM21);     // CTC
    TCCR2B = (7 << CS20);      //div 1024 
    OCR2A = 255;
    TIMSK2 |= (1 << OCIE2A);
}     

and sure enough, it does 244, 488, 732, ... for OCR2A=255
and 625, 1250, 1875, ... for 99

David.

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

Great !

You're my saviour ;)

Thanks a lot

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

Ok. Now tell me what was different with your code.

Your |= was perfectly correct.
Your sei() was unnecessary.
The position of the OCR2A assignment should be irrelevant.

David.

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

I think you're right. The documentation is not very clear
about this kind of processes in background. The order of instructions to set up the timer seems important.

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

I am not sure whether you are using the arduino framework or just an arduino board.

be aware that the arduino framework uses timer0.
http://forum.arduino.cc/index.php?topic=43021.0

regards
Greg

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

Thanks Greg but I Think I will stay with the Timer 2 because in the case I want to use Arduino library, the Timer 0 is used for delay() millis() et micro() functions, Timer 1 is generally used for servo motors and the Timer 2 is used for the tone function. So tone() function is the least important.

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

Ah-ha. I built a minimal test:

#include "portab_mcu.h"

ISR (TIMER2_COMPA_vect)
{   
    static int count = 0;
    if (++count >= 100) {
        count = 0;
        PORTB ^= (1<<5);
    }
} 

void setup() 
{
    DDRB |= (1<<5);
    OCR2A = 255; // <-- if i change this value, the timerr values are always the same at the execution
    TCCR2A = (1 << WGM21); // Configure timer 2 for CTC mode
    TCCR2B = (7 << CS20);                   //1024 prescaler
    TIMSK2 |= (1 << OCIE2A);
}

void loop()
{
}

void main()
{
    SEI();
	setup();
	while(1) {
	    loop();
    }
}

I can build a standalone program in AS4, CV, ...
Or just put the ISR(), setup() and loop() into an Arduino sketch.

The Arduino versions did not set OCR2A correctly even though the ASM generated for setup() was identical.

When I simulated the Arduino version, setup() was entered with Timer2 in mode#1, div64.

This explains why OCR2A is not loaded because PWM mode#1 does not update until TOP.
If you clear the PWM mode first, OCR2A will update immediately.

So my 'style' just happened to do things in the right order.

I am using Arduino v1.0.5 so this may be different to other versions. It is still a mystery why init() should start PWM#1 on Timer2 in the first place.

David.

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

Ok,

So, it's the dark side of Arduino apparently.
I have a question, because I'm currently a beginner.
Which simulator do you use to debug the code? It could be help me a lot imo.

Thanks in advance David

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

I used Simulator2 in AS4.
You need to Open the hidden Arduino ELF file from the Project Wizard.

I chose to do this rather than build through AS6 because I just wanted to see what the IDE had done.

Quite honestly, you can debug Arduino sketches perfectly well with Serial.print() statements. e.g. I could have simply asked Serial.print(TCCR2A) to discover that TCCR2A was not in its power-up default state.

Of course, OCR2A might have updated itself by the time the print statement had completed.

So you could have diagnosed the problem even if the symptom disappeared in the process!

My advice is: sit down with pencil and paper when you design a sketch.
You will naturally set TCCR2A, TCCR2B, OCR2A, TIMSK2 in an intuitive order. Or possibly TCCR2B=0, TCCR2A, OCR2A, TIMSK2, TCCR2B since TCCR2B is the register that actually starts/stops the clock.

David.

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

Ok I'm trying to bear in mind your advices. I have the intuition that I will need you in a short future ;)

Regards,
Yves

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

david.prentice wrote:
It is still a mystery why init() should start PWM#1 on Timer2 in the first place.
Unless reconfigured by the user or another library, all three timers are prepared for PWM output (by init() as you've noted). Only the prescaler and timer mode are configured. The compare mode for each PWM output is configured by analogWrite() and digitalWrite() when called.

TIMER 0 is configured for mode 3 to simplify the timing functions (millis(), etc.) while TIMER1 and TIMER2 are configured for mode 1 (phase-correct PWM).

Quote:
Ah-ha. I built a minimal test:
I've been unable to reproduce your results. Perhaps the AS4 simulator doesn't quite reflect the real hardware w.r.t OCRnx latching?

dzives wrote:

TCCR2A |= (1 << WGM21); // Configure timer 2 for CTC mode 

The problem is that you're using |= instead of =

Since Arduino pre-configures TIMER2 for mode 1, TCCR2A already equals (1<<WGM20). When you |= with (1<<WGM21) you are selecting mode 3 which is a fast PWM mode with a fixed resolution of 8-bits. Changing OCR2A will not change the resolution of the timer, only the duty cycle of the OC2A PWM output (if configured), and the phase relationship between OCF2A and TOV2.

If you simply change |= to = when setting TCCR2A and TCCR2B, your code should work.

JJ

"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]

 

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

@Joey,

Look at the listing in the original post. He clears TCCR2A before using |=

I normally use the Arduino hardware but with any other Tools. So I have often set up Timers from 'power-up'

However, I have often written 'hybrid' Arduino sketches that use Timer1 and Timer2. I avoid Timer0 because it is handy to use the millis() function.

So I had never given thought to the Arduino initialising anything more than Timer0.

I think the moral of the story is: If the startup is a 'black-box', initialise your Timers by killing PWM first.

David.

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

david.prentice wrote:
He clears TCCR2A before using |=
So he does! My mistake...

david.prentice wrote:
I think the moral of the story is: If the startup is a 'black-box', initialise your Timers by killing PWM first.
Indeed.

david.prentice wrote:
This explains why OCR2A is not loaded because PWM mode#1 does not update until TOP.
I'm still not able to reproduce your results.

Perhaps I misunderstood. Are you saying: if a timer is already configured for a PWM mode, first changing an OCRnx register before reconfiguring the timer for a non-PWM mode will cause the change to OCRnx to be lost (unless the timer reaches TOP before the configuration change)?

// Arduino preconfigures TCCR2A = (1<<WGM20); TCCR2B = (1<<WGM22);
void setup() {
  volatile uint8_t ocr2a;
  OCR2A = 123;
  TCCR2A = (1 << WGM21);
  ocr2a = OCR2A;
  Serial.begin(9600);
  Serial.print("OCR2A == ");
  Serial.println(ocr2a);
}

void loop() {
}

Nope, OCR2A is in fact reflecting the change:

OCR2A == 123

Quote:
If you clear the PWM mode first, OCR2A will update immediately.
OK, so doing it the 'wrong' way:
// Arduino preconfigures TCCR2A = (1<<WGM20); TCCR2B = (1<<WGM22);
void setup() {
  volatile uint8_t ocr2a;
  OCR2A = 123;
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = (1 << WGM21);
  TCCR2B = (1 << CS22);
  ocr2a = OCR2A;
  Serial.begin(9600);
  Serial.print("OCR2A == ");
  Serial.println(ocr2a);
}

void loop() {
}

Nope, still works:

OCR2A == 123

I'm certain I've misunderstood, or composed the above tests incorrectly. What am I missing?

JJ

"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]

 

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

Quote:

or composed the above tests incorrectly.

Well, if this is a Mega328 (I've lost track), then consider your comments on the code fragment...

You say that WGM20 & WGM22 are set coming in. Verified? Let's assume that is right.

Then you do "TCCR2A = (1 << WGM21);". So now you have '21 and '22 set for selecting the mode. This isn't a valid mode for timer2 on a '328.

I've never had any particular problems with order of operations on timer setup in scores of production apps over the past dozen+ years.

About reaching TOP -- In general (always?) the [AVR8] timer reaches TOP. But may well not reach MAX to trip TOV.

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 say that WGM20 & WGM22 are set coming in.
Crap. Copy/paste error. Sorry (I know better!). Should read:
Arduino preconfigures TCCR2A = (1<<WGM20); TCCR2B = (1<<CS22);

Quote:
About reaching TOP -- In general (always?) the [AVR8] timer reaches TOP. But may well not reach MAX to trip TOV.
Yes, but the sequence in question (I think?) is:
    1) configure timer for a PWM mode 2) timer tick away towards TOP (phase-correct PWM modes) and a wrap to BOTTOM (fast PWM modes)
    3) OCRnx is loaded with a non-reset-default (i.e. non-zero) value
    4) OCRnx is held in an internal temp register accessible to the CPU for reading, but is not yet latched by the compare match logic
    5) timer has yet to reach TOP/BOTTOM and latch the new OCRnx when we...:
    6) reconfigure timer for a non-PWM mode
    7) read OCRnx (which should now reference the un-buffred register, not the temp register)
I thought the proposal was that the held-in-temp value for OCRnx written in step 3) is discarded by the timer logic between steps 6) and 7).

It seems (from my tests, despite commenting errors :() that this is not the case. It seems there is a step 6.5) where the held-in-temp value from the last write to OCRnx is latched into the unbuffered compare-match register as a consequence of the mode change.

David's test with the AS4 simulator seemed to suggest that this post-mode-change latching does not occur, and I was wondering if the flaw was in the simulator or in my head ;)

All of this is of course moot if the programmer is sensible and configures from scratch whenever there is any question. I'm just curious.

JJ

"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]

 

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

@Joey,

Yes, your sketch shows 123.

Try the sketch from the original post.

Or even try my minimal LED blink on digital#13

David.

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

david.prentice wrote:
Try the sketch from the original post.

Or even try my minimal LED blink on digital#13

Ah. That's even stranger.

I hadn't considered it, but it looks like OCR2A is reading the correct value (i.e. the value written), but the compare match logic never latches it, even after the timer mode is changed. Neither has the previously written value been discarded.

I would have expected that a failure to latch would be reflected in a read of OCR2A, but that seems not to be the case. IOW a discontinuity has arisen between the value of OCR2A as available to the CPU via a read of the I/O register, and the internally latched value used by the comparator.

My expectation arose from this passage:

In the datasheet, Atmel wrote:
The OCR2x Register access may seem complex, but this is not case. When the double buffering is enabled, the CPU has access to the OCR2x Buffer Register, and if double buffering is disabled the CPU will access the OCR2x directly.
From this I formed this image:
                    +--------------+
  CPU access in --->| OCR2x buffer |
   PWM modes        |   register   |
                    +--------------+
                           |
                           v
  Trigger at        +--------------+
  TOP/BOTTOM ------>|    Latch     |
    in PWM          |              |
  modes only        +--------------+
                           |
                           v
                    +--------------+
  CPU access in --->|    OCR2x     |
  non-PWM modes     |   register   |
                    +--------------+
                           |
                           v
                    +--------------+
                    |    8-bit     |
                    |  comparator  |
                    +--------------+
                           |
                           v
                    +--------------+
                    |     OC2x     |
                    |    output    |
                    +--------------+

From the behaviour observed, it would seem as though the picture is more like:

                    +--------------+
  CPU access in --->| OCR2x buffer |
  all modes         |   register   |
                    +--------------+
                           |
                           v                  Trigger on
  Trigger at        +--------------+         write strobe
  TOP/BOTTOM ------>|    Latch     |<------  (caused by a
    in PWM          |              |        write to OCR2x)
     modes          +--------------+        in non-PWM modes
                           |
                           v
                    +--------------+
  NO CPU ACCESS --->|    OCR2x     |
                    |   register   |
                    +--------------+
                           |
                           v
                    +--------------+
                    |    8-bit     |
                    |  comparator  |
                    +--------------+
                           |
                           v
                    +--------------+
                    |     OC2x     |
                    |    output    |
                    +--------------+

Again, this is just a brain-worm. I've probably taken this OT far enough already... ;)

JJ

"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]