1

I am trying to use Timer2 on an Elegoo Nano to produce a "tick" interrupt every 10uS. My plan was to set Timer2 to CTC mode with a /8 prescaler (to get a timer clock of 2MHz from the 16MHz chip clock) and a compare value of 19 (to reset the timer every 20 counts) which should trigger the compareA ISR at 100KHz (every 10us). The problem is that only prescale values of 64 or greater work as expected. Setting the prescaler to any value lower than 64 actually results in the "tick" interval getting much longer (10 times the interval or more). I have carefully studied the ATmega628 datasheet to see if I am configuring every register correctly, but I don't see anything wrong with what I am doing. Here is my code...

void initTimer() {

    // ---Disable interrupts during timer initialization
    cli();

    // ---Counter compare value (make CTC interrupt fire every 10uS)
    OCR2A = 19;

    // ---Clear TCCR A register (not used)
    TCCR2A = 0;

    // ---Enable CTC mode with divide-by-8 prescaler
    TCCR2B = _BV( WGM22 ) | _BV( CS21 );

    // ---Enable Timer2 CTC interrupts for compare A match
    TIMSK2 |= _BV( OCIE2A );

    // ---Initialize timer 2 to zero (not really needed in my situation)
    TCNT2 = 0;

    // ---Turn interrupts back on
   sei();
}

SIGNAL( TIMER2_COMPA_vect ) {

    /*
    ** This should execute every 10uS, but for prescaler values
    ** below 64 the interval is many times longer than expected.
    */
}

Can anyone point out my mistake?

2

Can anyone point out my mistake?

Your mistake is in thinking that it's possible to do more than you can within a 10uS period.

At 16MHz each instruction takes 63ns (for single-clock instructions). 10nS gives you a maximum of (10,000 / 63) 156 assembly instructions. Into that you have to fit the preamble and postamble to store the registers to the stack and retrieve them again.

The remaining clock cycles (maybe no more than 100) won't give you much time to do complex things. And given that many of the Arduino API calls are quite heavyweight, even just something as "simple" as a digitalWrite() can overflow that many times over.

  • Thanks Majenko, I had considered that, but since my ISR just decrements a few countdown variables I figured I could probably get away with it. See the answer I posted to my own question... I was configuring the timer correctly but I was doing it in a way that it was happening before the Arduino boot setup code had run so my settings were being overwritten when the Arduino routines configured timer2. After I changed my code to call the my timer2 initialization from setup() instead, a 10uS ISR interval is working fine. – PhoenixRevealed Oct 1 '18 at 3:22
0

Ok, I figured it out. It wasn't my timer initialization that was wrong, it was when I was doing it. Although I didn't show it in my original code sample, my initialization function actually returns a dummy boolean value so I could call it automatically if the .cpp file containing the function and the ISR is included in the project, like this...

bool initTimer() {

    // ---Set up the timer for CTC interrupts with a 10uS period
    ---
    ---
    ---

    // ---This return value is necessary, but ignored
    return true;
}

bool dummy = initTimer();

That final line calls initTimer() during Arduino boot just by including this source file in the project. It's a nice way to "auto-configure" utility objects without needing to explicitly call an initialization function. The boolean dummy return value from initTimer() is needed since C/C++ compilers choke on calling functions this way without storing a return value.

void initTimer() {

    // ---Do stuff...
}

// ---The compiler can't digest this...
initTimer();

Anyway, I have used this technique many times over several decades in desktop and mobile applications, so I did it in this Arduino project without giving it too much thought, but I failed to consider that it would execute the timer2 initialization BEFORE the Arduino setup routines. Anything I did to timer2 was being overwritten by the Arduino boot code which ran after my initTimer() function. My initialization was having some effect on the operation of timer2 because the Arduino boot setup assumes the timer2 config registers are starting off empty (zeroed) so it just sets config bits without clearing everything first. Any bits I turn on stay on, but Arduino boot up sets additional bits so the resulting timer configuration is unpredictable. The solution was simple... call the initTimer() function from the standard Arduino setup() function instead to ensure it executes LAST.

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.