Servo Library affects timer 2?

Hi all I'm developing a robot with Arduino Mega. I'm using timer 2 for interrupt handling to read out the encoders of the motors(2kHz sampling rate).

I'm using Servo Library to control one Servo for steering functions. During tests I detected strange tics in about a second cycle on the servo and found out when I deactivate my interrupt initiation routine (timer 2 initiation) the tics disappear. I could not find out in the library documentation that the timer 2 has been used by the servo library.

Can I change the used timer of the servo Library?

Thanks in advance for your answers

The Servo library defaults to Timer1, but appears to use any timer except Timer2. :(

Here's the "ServoTimers.h" file:-

/*
  Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
  Copyright (c) 2009 Michael Margolis.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*
 * Defines for 16 bit timers used with  Servo library
 *
 * If _useTimerX is defined then TimerX is a 16 bit timer on the current board
 * timer16_Sequence_t enumerates the sequence that the timers should be allocated
 * _Nbr_16timers indicates how many 16 bit timers are available.
 */

/**
 * AVR Only definitions
 * --------------------
 */

// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_ATmega32U4__)
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;

#else  // everything else
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif

How can the code of my interrupt routine affect the Servo timers?

void QuadratureEncoderInit(void)
{
 int16_t val;
 cli();
 //set timer2 interrupt at 2kHz
 TCCR2A = 0;// set entire TCCR2A register to 0
 TCCR2B = 0;// same for TCCR2B
 TCNT2  = 0;//initialize counter value to 0
 // set compare match register for 2khz increments
 OCR2A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
 // turn on CTC mode
 TCCR2A |= (1 << WGM21);
 // Set CS21 and CS20 bits for 64 prescaler
 TCCR2B |= (1 << CS21) | (1 << CS20);
 // enable timer compare interrupt
 TIMSK2 |= (1 << OCIE2A);

 val = 0;
 if (LT_PHASE_A)
   val = 3;
 if (LT_PHASE_B)
   val ^= 1;
 lastLt = val;
 encDeltaLt = 0;

 val = 0;
 if (RT_PHASE_A)
   val = 3;
 if (RT_PHASE_B)
   val ^= 1;
 lastRt = val;
 encDeltaRt = 0;

 encLt = 0;
 encRt = 0;
 sei();
 return;
}

int16_t QuadratureEncoderReadLt( void ) // read single step encoders
{
 int16_t val;
 cli();
 val = encDeltaLt;
 encDeltaLt = 0;
 sei();
 return val; // counts since last call
}

int16_t QuadratureEncoderReadRt( void ) // read single step encoders
{
 int16_t val;
 cli();
 val = encDeltaRt;
 encDeltaRt = 0;
 sei();
 return val; // counts since last call
}

How can the code of my interrupt routine affect the Servo timers?

I have no idea. Hopefully someone more knowledgable on timers can answer that. I was capable of checking the library files to see which timers are used, but that’s about it.

By the way, you almost got the code tags right, but need to use square brackets instead of <>, so it looks like this:-

[code]
// Put your code here
[/code]

Then it will appear like this:-

// Put your code here

It’s not too late to edit and do that.
It’ll make your code more readable for the next person who comes along to help. :slight_smile:

thanks

Wolfgang_Glueck: How can the code of my interrupt routine affect the Servo timers?

Nothing in your post is an interrupt (service) routine.

ok I agree, forgot to copy it

here the ISR

// Encoders
// *******************************************************************************************************************************

#define encoderRightA 29
#define encoderRightB 28
#define encoderLeftA 27
#define encoderLeftB 26

#define LT_PHASE_A digitalRead(encoderLeftA)
#define LT_PHASE_B digitalRead(encoderLeftB)
#define RT_PHASE_A digitalRead(encoderRightA)
#define RT_PHASE_B digitalRead(encoderRightB)
static volatile int16_t encDeltaLt, encDeltaRt;
static int16_t lastLt = 0, lastRt = 0;
int encLt = 0, encRt = 0;

ISR( TIMER2_COMPA_vect )
{
  int16_t val, diff;

  val = 0;
  if ( LT_PHASE_A )
    val = 3;
  if ( LT_PHASE_B )
    val ^= 1; // convert gray to binary
  diff = lastLt - val; // difference last - new
  if ( diff & 1 ) { // bit 0 = value (1)
    lastLt = val; // store new as next last
    encDeltaLt += (diff & 2) - 1; // bit 1 = direction (+/-)
  }

  val = 0;
  if ( RT_PHASE_A )
    val = 3;
  if ( RT_PHASE_B )
    val ^= 1; // convert gray to binary
  diff = lastRt - val; // difference last - new
  if ( diff & 1 ) { // bit 0 = value (1)
    lastRt = val; // store new as next last
    encDeltaRt += (diff & 2) - 1; // bit 1 = direction (+/-)
  }
  return;
}

Interrupts are OFF within an ISR. If your ISR takes a long time, or if it is short but called very frequently, it could be interfering with the interrupts that are used by the Servo library.

...R

the frequency of the ISR is 2 kHz and it has about 20 lines of code without loops the servo library is operating in 50 Hz? and produces PWM Pulses between 1 and 2 ms

is that to much for an Arduino Mega?

Interrupts are OFF within an ISR. If your ISR takes a long time, or if it is short but called very frequently, it could be interfering with the interrupts that are used by the Servo library.

Your ISR uses 4 digitalRead() calls which takes about 15 microseconds. http://jeelabs.org/2010/01/06/pin-io-performance/

You can speed up the ISR by using direct port readings instead of digitalRead(). https://www.arduino.cc/en/Reference/PortManipulation

How fast is your encoder rotating? If ypu change your encoder routine to one which is interrupt driven by pin changes, rather than at timer intervals, You might be able to reduce the frequency of interrupts.

ok, sounds great

I will try it out

first I can change the ISR to reading only one encoder, makes half of code. In addition move to D3/4 for the remaining encoder and change to Register D handling.

Is the following change correct?

// Encoders
// *******************************************************************************************************************************

//#define encoderRightA 4
//#define encoderRightB 3
//#define RT_PHASE_A digitalRead(encoderRightA)
//#define RT_PHASE_B digitalRead(encoderRightB)
#define RT_PHASE_A PIND && B00010000
#define RT_PHASE_B PIND && B00001000

I will report the result soon

Thanks

It seems to work, the tic has been disappeared

#define RT_PHASE_A PIND [color=red][b]&&[/b][/color] B00010000
#define RT_PHASE_B PIND [color=red][b]&&[/b][/color] B00001000

I'm pretty sure that those double && are not correct. should be single & if you want to mask. also you might want to add parenthesis around the defined formula to avoid priority errors

like if you have to do 2 * RT_PHASE_B somewhere that would be interpreted as (2*PIND) & B00001000 whereas you probably would want 2 * (PIND & B00001000)

so recommend doing:

#define RT_PHASE_A [color=green][b]([/b][/color]PIND [color=green][b]&[/b][/color] B00010000[color=green][b])[/b][/color]
#define RT_PHASE_B [color=green][b]([/b][/color]PIND [color=green][b]&[/b][/color] B00001000[color=green][b])[/b][/color]

hope this helps

Hello!

I am building a bicopter

I am having the same tic issue but i do not have enough experience to figure out way. I attach my code.

Any suggestion is more than welcome

Thanks in advance!!

Flight_Controller_test.ino (14.2 KB)