Skip to content

Commit 30177c3

Browse files
committed
Incorporating updates to the Servo library by Michael Margolis.
1 parent af7c83a commit 30177c3

File tree

2 files changed

+147
-43
lines changed

2 files changed

+147
-43
lines changed

Servo.cpp

Lines changed: 106 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,24 @@
4545
#include <avr/interrupt.h>
4646
#include <WProgram.h>
4747

48-
4948
#include "Servo.h"
5049

51-
#define TICKS_PER_uS (clockCyclesPerMicrosecond() / 8) // number of timer ticks per microsecond with prescale of 8
50+
#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
51+
#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
5252

53-
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
54-
#define TRIM_DURATION (SERVOS_PER_TIMER/2) // compensation ticks to trim adjust for digitalWrite delays
5553

56-
#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
54+
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
5755

58-
static servo_t servos[MAX_SERVOS]; // static array of servo structures
59-
static volatile int8_t Channel[NBR_TIMERS]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
60-
#if defined(__AVR_ATmega1280__)
61-
typedef enum { _timer5, _timer1, _timer3, _timer4 } servoTimer_t; // this is the sequence for timer utilization on mega
62-
#else
63-
typedef enum { _timer1 } servoTimer_t; // this is the sequence for timer utilization on other controllers
64-
#endif
56+
//#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
57+
58+
static servo_t servos[MAX_SERVOS]; // static array of servo structures
59+
static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
6560

6661
uint8_t ServoCount = 0; // the total number of attached servos
6762

63+
6864
// convenience macros
69-
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((servoTimer_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
65+
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
7066
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
7167
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
7268
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
@@ -76,7 +72,7 @@ uint8_t ServoCount = 0; // the total number
7672

7773
/************ static functions common to all instances ***********************/
7874

79-
static inline void handle_interrupts(servoTimer_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
75+
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
8076
{
8177
if( Channel[timer] < 0 )
8278
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
@@ -93,64 +89,112 @@ static inline void handle_interrupts(servoTimer_t timer, volatile uint16_t *TCNT
9389
}
9490
else {
9591
// finished all channels so wait for the refresh period to expire before starting over
96-
if( (unsigned)*TCNTn < (((unsigned int)REFRESH_INTERVAL * TICKS_PER_uS) + 4) ) // allow a few ticks to ensure the next OCR1A not missed
97-
*OCRnA = (unsigned int)REFRESH_INTERVAL * TICKS_PER_uS;
92+
if( (unsigned)*TCNTn < (usToTicks(REFRESH_INTERVAL) + 4) ) // allow a few ticks to ensure the next OCR1A not missed
93+
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
9894
else
9995
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
10096
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
10197
}
10298
}
10399

100+
#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
101+
// Interrupt handlers for Arduino
102+
#if defined(_useTimer1)
104103
SIGNAL (TIMER1_COMPA_vect)
105104
{
106105
handle_interrupts(_timer1, &TCNT1, &OCR1A);
107106
}
107+
#endif
108108

109-
#if defined(__AVR_ATmega1280__)
109+
#if defined(_useTimer3)
110110
SIGNAL (TIMER3_COMPA_vect)
111111
{
112112
handle_interrupts(_timer3, &TCNT3, &OCR3A);
113113
}
114+
#endif
115+
116+
#if defined(_useTimer4)
114117
SIGNAL (TIMER4_COMPA_vect)
115118
{
116119
handle_interrupts(_timer4, &TCNT4, &OCR4A);
117120
}
121+
#endif
122+
123+
#if defined(_useTimer5)
118124
SIGNAL (TIMER5_COMPA_vect)
119125
{
120126
handle_interrupts(_timer5, &TCNT5, &OCR5A);
121127
}
122128
#endif
123129

124-
static void initISR(servoTimer_t timer)
130+
#elif defined WIRING
131+
// Interrupt handlers for Wiring
132+
#if defined(_useTimer1)
133+
void Timer1Service()
134+
{
135+
handle_interrupts(_timer1, &TCNT1, &OCR1A);
136+
}
137+
#endif
138+
#if defined(_useTimer3)
139+
void Timer3Service()
140+
{
141+
handle_interrupts(_timer3, &TCNT3, &OCR3A);
142+
}
143+
#endif
144+
#endif
145+
146+
147+
static void initISR(timer16_Sequence_t timer)
125148
{
149+
#if defined (_useTimer1)
126150
if(timer == _timer1) {
127151
TCCR1A = 0; // normal counting mode
128152
TCCR1B = _BV(CS11); // set prescaler of 8
129153
TCNT1 = 0; // clear the timer count
130-
#if defined(__AVR_ATmega8__)
154+
#if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
131155
TIFR |= _BV(OCF1A); // clear any pending interrupts;
132-
TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
156+
TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
133157
#else
158+
// here if not ATmega8 or ATmega128
134159
TIFR1 |= _BV(OCF1A); // clear any pending interrupts;
135160
TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
136-
#endif
161+
#endif
162+
#if defined(WIRING)
163+
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
164+
#endif
137165
}
138-
#if defined(__AVR_ATmega1280__)
139-
else if(timer == _timer3) {
166+
#endif
167+
168+
#if defined (_useTimer3)
169+
if(timer == _timer3) {
140170
TCCR3A = 0; // normal counting mode
141171
TCCR3B = _BV(CS31); // set prescaler of 8
142172
TCNT3 = 0; // clear the timer count
173+
#if defined(__AVR_ATmega128__)
174+
TIFR |= _BV(OCF3A); // clear any pending interrupts;
175+
ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt
176+
#else
143177
TIFR3 = _BV(OCF3A); // clear any pending interrupts;
144178
TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
179+
#endif
180+
#if defined(WIRING)
181+
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
182+
#endif
145183
}
146-
else if(timer == _timer4) {
184+
#endif
185+
186+
#if defined (_useTimer4)
187+
if(timer == _timer4) {
147188
TCCR4A = 0; // normal counting mode
148189
TCCR4B = _BV(CS41); // set prescaler of 8
149190
TCNT4 = 0; // clear the timer count
150191
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
151-
TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
152-
}
153-
else if(timer == _timer5) {
192+
TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
193+
}
194+
#endif
195+
196+
#if defined (_useTimer5)
197+
if(timer == _timer5) {
154198
TCCR5A = 0; // normal counting mode
155199
TCCR5B = _BV(CS51); // set prescaler of 8
156200
TCNT5 = 0; // clear the timer count
@@ -160,7 +204,32 @@ static void initISR(servoTimer_t timer)
160204
#endif
161205
}
162206

163-
static boolean isTimerActive(servoTimer_t timer)
207+
static void finISR(timer16_Sequence_t timer)
208+
{
209+
//disable use of the given timer
210+
#if defined WIRING // Wiring
211+
if(timer == _timer1) {
212+
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
213+
TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
214+
#else
215+
TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
216+
#endif
217+
timerDetach(TIMER1OUTCOMPAREA_INT);
218+
}
219+
else if(timer == _timer3) {
220+
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
221+
TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
222+
#else
223+
ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
224+
#endif
225+
timerDetach(TIMER3OUTCOMPAREA_INT);
226+
}
227+
#else
228+
//For arduino - in future: call here to a currently undefined function to reset the timer
229+
#endif
230+
}
231+
232+
static boolean isTimerActive(timer16_Sequence_t timer)
164233
{
165234
// returns true if any servo is active on this timer
166235
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
@@ -177,7 +246,7 @@ Servo::Servo()
177246
{
178247
if( ServoCount < MAX_SERVOS) {
179248
this->servoIndex = ServoCount++; // assign a servo index to this instance
180-
servos[this->servoIndex].ticks = DEFAULT_PULSE_WIDTH * TICKS_PER_uS; // store default values
249+
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009
181250
}
182251
else
183252
this->servoIndex = INVALID_SERVO ; // too many servos
@@ -197,7 +266,7 @@ uint8_t Servo::attach(int pin, int min, int max)
197266
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
198267
this->max = (MAX_PULSE_WIDTH - max)/4;
199268
// initialize the timer if it has not already been initialized
200-
servoTimer_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
269+
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
201270
if(isTimerActive(timer) == false)
202271
initISR(timer);
203272
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
@@ -208,12 +277,10 @@ uint8_t Servo::attach(int pin, int min, int max)
208277
void Servo::detach()
209278
{
210279
servos[this->servoIndex].Pin.isActive = false;
211-
212-
#ifdef FREE_TIMERS
213-
if(isTimerActive(SERVO_INDEX_TO_TIMER(servoIndex)) == false) {
214-
;// call to unimplimented function in wiring.c to re-init timer (set timer back to PWM mode) TODO?
280+
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
281+
if(isTimerActive(timer) == false) {
282+
finISR(timer);
215283
}
216-
#endif
217284
}
218285

219286
void Servo::write(int value)
@@ -238,7 +305,9 @@ void Servo::writeMicroseconds(int value)
238305
else if( value > SERVO_MAX() )
239306
value = SERVO_MAX();
240307

241-
value = (value-TRIM_DURATION) * TICKS_PER_uS; // convert to ticks after compensating for interrupt overhead
308+
value = value - TRIM_DURATION;
309+
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
310+
242311
uint8_t oldSREG = SREG;
243312
cli();
244313
servos[channel].ticks = value;
@@ -255,7 +324,7 @@ int Servo::readMicroseconds()
255324
{
256325
unsigned int pulsewidth;
257326
if( this->servoIndex != INVALID_SERVO )
258-
pulsewidth = (servos[this->servoIndex].ticks / TICKS_PER_uS) + TRIM_DURATION ;
327+
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009
259328
else
260329
pulsewidth = 0;
261330

Servo.h

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
The servos are pulsed in the background using the value most recently written using the write() method
2424
2525
Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
26-
Timers are siezed as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
26+
Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
27+
The sequence used to sieze timers is defined in timers.h
2728
2829
The methods are:
2930
@@ -46,18 +47,52 @@
4647

4748
#include <inttypes.h>
4849

50+
/*
51+
* Defines for 16 bit timers used with Servo library
52+
*
53+
* If _useTimerX is defined then TimerX is a 16 bit timer on the curent board
54+
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
55+
* _Nbr_16timers indicates how many 16 bit timers are available.
56+
*
57+
*/
58+
59+
// Say which 16 bit timers can be used and in what order
60+
#if defined(__AVR_ATmega1280__)
61+
#define _useTimer5
62+
#define _useTimer1
63+
#define _useTimer3
64+
#define _useTimer4
65+
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t ;
66+
67+
#elif defined(__AVR_ATmega32U4__)
68+
#define _useTimer3
69+
#define _useTimer1
70+
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;
71+
72+
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
73+
#define _useTimer3
74+
#define _useTimer1
75+
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;
76+
77+
#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
78+
#define _useTimer3
79+
#define _useTimer1
80+
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;
81+
82+
#else // everything else
83+
#define _useTimer1
84+
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;
85+
#endif
86+
4987
#define Servo_VERSION 2 // software version of this library
5088

5189
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
5290
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
5391
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
5492
#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
5593

56-
#if defined(__AVR_ATmega1280__)
57-
#define MAX_SERVOS 48 // the maximum number of servos (valid range is from 1 to 48)
58-
#else
59-
#define MAX_SERVOS 12 // this library supports up to 12 on a standard Arduino
60-
#endif
94+
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
95+
#define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
6196

6297
#define INVALID_SERVO 255 // flag indicating an invalid servo index
6398

0 commit comments

Comments
 (0)