8

I'm trying to check the frequency of Timer3 using a counter. The value of the counter, declared as volatile, is incremented in the ISR and every second the sum is shown in the main loop and the value reset to zero.

The timer has been set up correctly. (If I choose a 3Hz timer I can see the led blinking)

The problem

The counter isn't incremented. Here is the output:

Setup Completed
tick: 1
tick: 0
tick: 0
tick: 0

CODE

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B = 20; // 800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();

  Serial.println("Setup completed");
}

void loop()
{
  if (millis() % 1000 == 0)
  {
    Serial.print(" tick: ");
    Serial.println(cont);
    cont = 0;
  }
}

ISR(TIMER3_COMPB_vect)
{
  //digitalWrite(13, digitalRead(13) ^ 1);
  cont++;
}

EDIT This timer is used to read an anlog value from an accelerometer and store it in an array of float. But at the moment I'm stuck on this update issue.

SOLUTION 1 Thanks to Gerben

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3A = 20; // 20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  delay(1000);
  Serial.println(cont);
  cont = 0;
}

ISR(TIMER3_COMPB_vect)
{
  cont++;
}

SOLUTION 2 Thanks to BrettM

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B =  20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  //TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  Serial.println(cont); 
  cont = 0;
  delay(1000);

}

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}
  • And if you uncomment the digitalWrite line you see the LED blink about once per second (every 0.66s)? – Ricardo Dec 11 '14 at 11:40
  • Yes, If I uncomment digitalWrite and set OCR3B = 5; the led blinks at approximately that frequency. – UserK Dec 11 '14 at 11:46
  • Then it's a mistery. Have you tried commenting out the cont = 0; inside the loop? What happens then? – Ricardo Dec 11 '14 at 11:49
  • 1
    Try increasing the frequency. I think your if statement may be clearing the counter more often than the interrupt is called, somehow. But then you should see more ones in the output. Also let if run for longer (say 1 minute) and paste the results. Also, when you update the question, leave the old output so your question makes sense (without the edit history). – Ricardo Dec 11 '14 at 11:59
  • 1
    I suspect that the interrupt routine is being called only once and then it is disabled. I've read somewhere that the interrupts are disabled when an interrupt code is running, and in some cases you have to re-enable it, but I'm really not sure if that's the case. Hopefully someone more knowledgeable will come to our rescue... – Ricardo Dec 11 '14 at 12:41
5

In CTC mode the top is OCR3A, not OCR3B!

After that TIMSK3 |= (1 << OCIE3B); should also be changed to TIMSK3 |= (1 << OCIE3A);, and ISR(TIMER3_COMPB_vect) to ISR(TIMER3_COMPA_vect)

For 3Hz, OCR3A should be 5208, not 20.

Technically TCCR3B |= (1 << WGM12); should be TCCR3B |= (1 << WGM32);

  • With your configuration the counter is not updated and every second the "Setup completed" sentence, (written in the setup() function!) is shown. Really weird behaviour. – UserK Dec 11 '14 at 21:37
  • Solved using TIMSK3 |= (1 << OCIE3B);. Thank you Gerben! Please modify your answer and I'll accept it as solution. – UserK Dec 11 '14 at 21:41
  • 1
    I forgot the mention you also need the change the ISR vector. ISR(TIMER3_COMPB_vect) should be ISR(TIMER3_COMPA_vect). If an ISR isn't defined, the AVR will reset itself, like you were experiencing. Glad you got it working. – Gerben Dec 12 '14 at 14:04
3

It seems my answer to this question was previously incomplete, thanks for pointing out that CTC mode only works with OCR3A Gerben. I apologize for not testing an answer before I post it.

Given the information only in this question Gerben's answer is complete, but since your other question implies that you cannot use OCR3A due to the Servo library I'll add a bit. (I've also edited that answer)

you can emulate the behavior of CTC mode by setting TCNT3 to 0 in your interrupt routine. Remember to remove the line that turns on CTC mode in your code.

I've tested your code with this ISR:

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

and this configuration of the timer registers

OCR3B = 5208; // 800Hz 5; // 3 Hz
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);

This might be a bit less accurate at high frequencies than CTC, I'm not sure, but at 3Hz it worked perfectly. Notice that 5208 was the correct OCR value, not 20 (again thanks to Gerben).

  • I've tried your code but the counter isn't incremented. I've added the TCNT3=0; in the ISR() and removed //TCCR3B |= (1 << WGM32); in the setup() as you said. I've also tried commenting out the cont=0; line but nothing changed – UserK Dec 11 '14 at 21:56
  • 1
    Make sure the code matches what is posted in the question in every other way. Try changing your loop to just println(cont); delay(1000);. Also you are still including the bits with cli() and TCCR3A etc correct? – BrettAM Dec 11 '14 at 22:06
  • Ok thanks. At 800 Hz is still accurate! – UserK Dec 11 '14 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.