10

I would like to set up a timer in order to call a function 800 times per second. I'm using the Arduino Mega and Timer3 with a prescaler of 1024. To choose the prescaler factor I've considered the following steps:

  • CPU freq: 16MHz
  • Timer resolution: 65536 (16 bits)
  • Divide CPU freq by the chosen prescaler: 16x10^6/1024=15625
  • Divide the rest through the desired freq 62500/800=19.
  • Put the result + 1 in OCR3 register.

I've used the following table to set registers of TCCR3B:

enter image description here

The error

It is impossible to compile the code. This is the error returned by the compiler:

Servo\Servo.cpp.o: In function '__vector_32': C:\Program Files (x86)\Arduino\libraries\Servo/Servo.cpp:110: multiple definition of '__vector_32' AccelPart1_35.cpp.o:C:\Program Files (x86)\Arduino/AccelPart1_35.ino:457: first defined here c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions

The code

volatile int cont = 0;
unsigned long aCont = 0;
void setup()
{
 [...]
  // initialize Timer3
  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;
  // 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 << OCIE3A);
  // enable global interrupts:
  sei();
}

void loop()
{
 // Print every second the number of ISR invoked -> should be 100
 if ( millis() % 1000 == 0)
 {
   Serial.println();
   Serial.print(" tick: ");
   Serial.println(contatore);
   contatore = 0;
 }
}

[...]

// This is the 457-th line
ISR(TIMER3_COMPA_vect)
{
    accRoutine();
    contatore++;
}

void accRoutine()
{
  // reads analog values
}

How to solve the conflict with the servo library?

SOLUTION

Conflict solved using the following code. It compiles but the counter associated with the 800Hz timer doesn't increment its value.

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  // 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;
  // 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)
{
  cont++;
}

Since the main problem has been solved, I've created another question here related to the problem of the counter incrementation.

12
  • Do you use the servo library in your progam or not?
    – jfpoilpret
    Commented Dec 9, 2014 at 5:34
  • 2
    Servo.cpp probable does also ISR(TIMER3_COMPA_vect)
    – TMa
    Commented Dec 9, 2014 at 6:53
  • 1
    Just use Timer1, 4 or 5 instead.
    – Gerben
    Commented Dec 9, 2014 at 17:09
  • 1
    Servo defines interrupt functions for timers 1,3,4 and 5 on megas for COMPA. How about using COMPB? Commented Dec 9, 2014 at 17:35
  • 1
    You are right. They are just hogging all timers. I guess you have to alter the library slightly by removing the #define _useTimer3 line, or try putting a #undef _useTimer3 right after the include.
    – Gerben
    Commented Dec 9, 2014 at 19:58

1 Answer 1

3

Unfortunately, The Servo library reserves output compare A (OCR*A) on timers 1,3,4, and 5 when loaded on an arduino mega. Each can only have one ISR, so you will not be able to define your own TIMER*_COMPA_vect while you use Servo without modifying the library.

However, each hardware timer is equipped with 2 output compare registers. Servo does not claim any TIMER*_COMPB_vect interrupts, so those are free to use, and work exactly the same.

You should watch out for the Servo libraries activities, it could change the configuration of your timer. The default order is on megas is 5,1,3,4 and to give each 12 servos. It only configures the timer once it needs it, so you should be fine using timer 3 until you add that 25th servo.

To change your code, use OCR3B instead of OCR3A (the Output Compare Registers) and set bit OCIE3B instead of OCIE3A in TIMSK3 (the Output Compare Interrupt Enable bits). Then you to change your ISR function to ISR(TIMER3_COMPB_vect){}

CTC mode only works with OCR3A, but if you set TCNT3 to 0 in your interrupt function you can get similar behavior. Remember to remove the line that turns CTC mode on using WGM12.

1
  • Ok thanks! Any advice on the incrementation of the counter?
    – UserK
    Commented Dec 11, 2014 at 0:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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