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.

VE7JRO
  • 2,497
  • 15
  • 24
  • 29
UserK
  • 559
  • 1
  • 11
  • 24
  • Do you use the servo library in your progam or not? – jfpoilpret Dec 09 '14 at 05:34
  • 2
    Servo.cpp probable does also **ISR(TIMER3_COMPA_vect)** – TMa Dec 09 '14 at 06:53
  • @jfpoilpret yes, I'm using motors. I will add the lines in the question. I've read that the servo library uses timer1 on the atmega328. – UserK Dec 09 '14 at 08:57
  • @jfpoilpret Maybe changing the timer will solve the problem. – UserK Dec 09 '14 at 08:58
  • 1
    Just use Timer1, 4 or 5 instead. – Gerben Dec 09 '14 at 17:09
  • 1
    Servo defines interrupt functions for timers 1,3,4 and 5 on megas for COMPA. How about using COMPB? – BrettAM Dec 09 '14 at 17:35
  • Haven't tried it yet, I'll do it asap. How many timers are available considering that I'm using functions like `millis()`, `micros()`, servo, serial and i2c communication? – UserK Dec 09 '14 at 18:01
  • @Gerben Thx, I think I would get the same issue using timer1 since it is used by the servo library as well – UserK Dec 09 '14 at 18:03
  • 1
    [You are right](https://github.com/arduino/Arduino/blob/master/libraries/Servo/Servo.h#L60-64). 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 Dec 09 '14 at 19:58
  • @BrettM I've tried with COMPB. It compiles but the timer doesn't work. Should I set te output Compare Register OCR3B to 625 instead of OCR3A? – UserK Dec 10 '14 at 13:34
  • You will need to load ORC3B instead of ORC3A yes. Also you need to enable the Compare B interrupt in TIMSK3 (change OCIE3A to OCIE3B) – BrettAM Dec 10 '14 at 18:54
  • @BrettM Could you please answer the question with the suggestions provided – UserK Dec 11 '14 at 00:05

1 Answers1

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.

BrettAM
  • 4,361
  • 1
  • 12
  • 26
  • Ok thanks! Any advice on the incrementation of the [counter](http://arduino.stackexchange.com/questions/5431/how-to-update-a-variable-in-an-isr-using-timers)? – UserK Dec 11 '14 at 00:57