3

Running the code below, when I send any character to the Arduino from the Serial Monitor, the Arduino does not print "a" back. I think it's something wrong with the timer1 code, but it should work because this code was given to me by my teacher in C class.

void setup() {
    Serial.begin(115200);
    
    // http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
    noInterrupts();
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 1000000hz increments with 8 bits prescaler
    OCR1A = 1;// = (16*10^6) / (1000000*8) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler. Each timer has a different bit
    // code to each prescaler
    TCCR1B |= (1 << CS11);  
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
    interrupts();
}

void loop() {
    if (Serial.available()) {
        Serial.println("a");
    }
}

See also: http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
Sitepor500.com.br
  • 388
  • 1
  • 5
  • 11

5 Answers5

15

Side Note: your code comment about 8 bits prescaler is misleading. It is not an 8-bit prescaler, rather, it is simply a prescaler of 8, meaning the decimal value 8. All that means is the timer's clock tick rate is 8x slower than the main clock, since you divide the main clock frequency by the prescaler to get the timer's clock frequency.

Now for my answer:

The way you set TCCR1A and TCCR1B is all correct.

However, you have 2 major problems, 1 minor problem, and 1 recommendation.

See the 660-pg ATmega328 datasheet pgs. 132~135 for more help & info if you want to know where to look from now on for low-level help.

Update: the new ATmega328 sales page is here: https://www.microchip.com/wwwproducts/en/ATmega328. Its new datasheet is available here: https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf. So, the page numbers I mention above and below will likely no longer quite match since I was using an older version of the datasheet when I wrote this.

Here are the 2 major problems which are completely breaking your code:

  1. Since you are enabling the Timer Compare Match 1A interrupt (TIMSK1 |= (1 << OCIE1A);), you MUST also define the Interrupt Service Routine (ISR) which will be called when this happens, or else you will have run-time (but not compile-time) problems. Namely, if you do not define the ISR for Output Compare Match A, once the Output Compare A interrupt occurs, the processor will get stuck in an infinite, empty, dummy ISR created for you by the compiler, and your main loop will not progress (see code below for proof of this).

    Add this to the bottom of your code:

    ISR(TIMER1_COMPA_vect)
    {
      // insert your code here that you want to run every time the counter
      // reaches OCR1A
    }
    
  2. It takes a couple microseconds to step into an ISR, and a couple microseconds to step out of an ISR, plus whatever time is required to run your code IN the ISR, you need to use an OCR1A value that is large enough that the ISR even has time to execute, rather than being continually called so quickly that you never exit the ISR (this would lock up your code essentially into an infinite loop....which is happening in your case as well).

    I recommend you call an ISR no more often than every 10us. Since you are using CTC mode (Clear Timer on Compare match), with a prescaler of 8, I recommend setting OCR1A to nothing less than 20 or so. OCR1A = 20 would call the ISR every 10us. (A prescaler of 8 means that each Timer1 tick take 0.5us, and so OCR1A = 20 would call the ISR every 20*0.5 = 10us).

If you set OCR1A = 20, and add the ISR code as described above, your code will run just fine.

1 Minor problem:

It is good practice to set OCR1A after you configure the rest of the timer, or else under some situations the timer may not start counting. See "Thorsten's" comment here (emphasis added):

Thorsten said...

Thanks for explaining this matter so extensively! I was looking for a way to generate 1 MHz on one of the Arduino-pins. Your post helped me a great deal to accomplish that.

The reason I am writing this comment is the following: It took me almost 6 hours till I found out (mainly in sheer desperation) that the order of setting the timer control registers TCCR2* and the output compare registers OCR2* seems to matter! If you assign an OCR before setting the corresponding TCCR the timer simply doesn't start counting.

February 13, 2011 at 11:47 AM

So, move OCR1A = 20; to after your last TCCR1B line and before your TIMSK1 line.

1 recommendation:

Get rid of your calls to noInterrupts() and interrupts(). They are not needed here.

Functional code:

Now, here is some functional code I wrote which will better demonstrate what you're trying to do, and what I'm talking about:

/*
timer1-arduino-makes-serial-not-work.ino
- a demo to help out this person here: 
  http://stackoverflow.com/questions/28880226/timer1-arduino-makes-serial-not-work

By Gabriel Staples
http://electricrcaircraftguy.blogspot.com/

5 March 2015
- using Arduino 1.6.0
*/

// Note: ISR stands for Interrupt Service Routine

// Global variables
volatile unsigned long numISRcalls = 0; // number of times the ISR is called

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

  // http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS

//  noInterrupts(); // Not necessary

  TCCR1A = 0; // set entire TCCR1A register to 0
  TCCR1B = 0; // same for TCCR1B
  TCNT1  = 0; // initialize counter value to 0
  
  // better to put this line AFTER configuring TCCR1A and TCCR1B below, but in
  // Arduino 1.6.0 it appears to be ok here (may crash code in older versions),
  // see comment by "Thorsten" here:
  // http://www.righto.com/2009/07/secrets-of-arduino-pwm.html?showComment=1297626476152#c2692242728647297320
  OCR1A = 20; 
  // SETTING OCR1A TO 1 OR 2 FOR SURE BREAKS THE CODE, as it calls the interrupt
  // too often to even allow the main loop to run at all.
  // OCR1A = 1;
  
  // turn on CTC mode [Clear Timer on Compare match---to make timer restart at
  // OCR1A; see datasheet pg. 133]
  TCCR1B |= (1 << WGM12); 
  // Set CS11 bit for 8 prescaler [0.5us ticks, datasheet pg. 135]. Each timer
  // has a different bit code to each prescaler
  TCCR1B |= (1 << CS11);
  // enable timer compare match 1A interrupt; NOW YOU *MUST* SET UP THE
  // CORRESPONDING ISR OR THIS LINE BREAKS THE CODE

  // IT IS RECOMMENDED TO SET OCR1A HERE, *after* first configuring both the
  // TCCR1A and TCCR1B registers, INSTEAD OF ABOVE! Like this:
  // OCR1A = 20; 

  TIMSK1 |= (1 << OCIE1A);

//  interrupts(); // Not necessary

  Serial.println("setup done, input a character");
}

void loop() 
{
  if (Serial.available()) 
  {
    // read and throw away the first byte in the incoming serial buffer (or else
    // the next line will get called every loop once you send the Arduino a
    // single char)
    Serial.read(); 
    Serial.println("a");
    
    // also print out how many times OCR1A has been reached by Timer 1's counter 
    noInterrupts(); // turn off interrupts while reading non-atomic (> 1 byte) 
                    // volatile variables that could be modified by an ISR at
                    // any time--incl while reading the variable itself.
    unsigned long numISRcalls_copy = numISRcalls;
    interrupts();
    Serial.print("numISRcalls = "); Serial.println(numISRcalls_copy);
  }
    
//  Serial.println("test");
//  delay(1000);
}

// SINCE YOU ARE ENABLING THE COMPARE MATCH 1A INTERRUPT ABOVE, YOU *MUST*
// INCLUDE THIS CORRESPONDING INTERRUPT SERVICE ROUTINE CODE
ISR(TIMER1_COMPA_vect)
{
  // insert your code here that you want to run every time the counter reaches
  // OCR1A
  numISRcalls++;
}

Run it and see what you think.

Proof that "Major Problem 1" above is real

(at least as far as I understand it--and based on tests on an Arduino Nano, using IDE 1.6.0):

This code below compiles, but will not continue to print the "a" (it may print it once, however). Note that for simplicity-sake I commented out the portion waiting for serial data, and simply told it to print an "a" every half second:

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

    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B
    TCNT1  = 0; // initialize counter value to 0
    
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler. Each timer has a different bit code to each
    // prescaler
    TCCR1B |= (1 << CS11);

    OCR1A = 20;

    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
}

void loop() {
    //if (Serial.available()) {
    //    Serial.println("a");
    //}
    
    Serial.println("a");
    delay(500);
}

// ISR(TIMER1_COMPA_vect)
// {
//   // insert your code here that you want to run every time the counter reaches
//   // OCR1A
// }

This code below, on the other hand, works, and the "a" will continue to print out. The only difference between this one and the one just above is that this one has the ISR declaration uncommented at the bottom:

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

    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B
    TCNT1  = 0; // initialize counter value to 0
    
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler. Each timer has a different bit code to each
    // prescaler
    TCCR1B |= (1 << CS11);

    OCR1A = 20;

    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
}

void loop() {
    //if (Serial.available()) {
    //    Serial.println("a");
    //}
    
    Serial.println("a");
    delay(500);
}

ISR(TIMER1_COMPA_vect)
{
  // insert your code here that you want to run every time the counter reaches
  // OCR1A
}

If this answer solves your problem, please upvote it and accept it as the correct answer. Thanks!

Extra Resources:

  1. I keep a running list of the most helpful Arduino resources I come across at the bottom of an article I wrote here: http://electricrcaircraftguy.blogspot.com/2014/01/the-power-of-arduino.html. Check them out.
    1. Especially look at the first links, under the "Advanced" section, by Ken Shirriff and Nick Gammon. They are excellent!
  2. Nick Gammon's answer here
  3. [my answer] Which Arduinos support ATOMIC_BLOCK? And how can I duplicate this concept in C with __attribute__((__cleanup__(func_to_call_when_x_exits_scope))) and in C++ with class constructors and destructors?
  4. [my own Question and answer] C++ decrementing an element of a single-byte (volatile) array is not atomic! WHY? (Also: how do I force atomicity in Atmel AVR mcus/Arduino)
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • Well, the compiler points all interrupt vectors that you haven't written an ISR for to a dummy ISR, so not defining the ISR isn't a problem. – user2973 Apr 07 '15 at 17:38
  • As far as compiling goes, you are correct, but the problem is in run-time. Once that TCNT1 reaches OCR1A, it leads the processor into a dummy ISR, created by the compiler, which never exits. So, the end result is that the loop() code will not progress, and when you send serial data in, the "a" will never be printed. – Gabriel Staples Apr 07 '15 at 21:39
  • Ben Voigt says the same thing in the comments above, and I have verified this on an Arduino. I'll post the code in my main response. Ben Voigt: "Also, where's your interrupt handler? If you don't acknowledge the interrupt, the handler will run infinitely, and your main loop where the serial code is will never make progress. – Ben Voigt Mar 5 at 18:51" – Gabriel Staples Apr 07 '15 at 21:40
  • 1
    I just checked the output of my avr-gcc 4.7.2 and the __bad_interrupt handler simply contains a jump to the reset vector, so you are right it won't work, the sketch will restart indefinitely as long as the interrupt keeps triggering. I had the idea that it simply returned. – user2973 Apr 08 '15 at 05:53
  • As for the interrupt entry / exit the entry is 4 cycles to push return address on stack + 3 cycles to jump from the vector to routine. The exit is 4 cycles to pop return address from stack. On top of this comes register pushes / pops added by the compiler. See atmega328 datasheet section 7.7.1 – user2973 Apr 08 '15 at 06:28
  • 1
    Just to point it out, if you misspell ISR name, no errors will be generated, but uC will still go into reset loop. – Cem Kalyoncu Dec 02 '18 at 17:19
2

Gabriel Staples is quite correct, the reason you are not seeing the "a" is because you have not provided an ISR handler for the interrupt. Thus, the compiler-generated code jumps back to address 0x0000 and your sketch restarts.

An alternative to providing the "empty" ISR handler is this:

EMPTY_INTERRUPT (TIMER1_COMPA_vect);

With the EMPTY_INTERRUPT handler there I got a response (the "a") with OCR1A as low as 1:

OCR1A = 1;

Although, one has to wonder why you enable interrupts if you aren't planning to do anything with them.

More information about interrupts on the Arduino.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
Nick Gammon
  • 1,173
  • 10
  • 22
1

You wrote this register 2 times:

TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);

while I think that it could probably be:

TCCR1A |= (1 << WGM12);
TCCR1B |= (1 << CS11);

Probably the only mistake is there, because you forgot to set TCCR1A and you set the other one 2 times.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
1

Depending on what the program needs to do with such a fast interrupt, e.g. generating a high-speed clock on an output pin, one can set it in hardware using COM bits in TCCR1A (out of my memory the 4 most significant bits) to toggle the output on a pin associated with the timer without the need to write any ISR() callback to handle the timer interrupt in software.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
0

TCCR1A |= (1 << WGM12); is a bitwise operation (bitwise OR). In this particular case is setting only one bit of TCCR1A, the one in position WGM12.

TCCR1B |= (1 << CS11); is setting a different bit in position CS11.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265