45
45
#include < avr/interrupt.h>
46
46
#include < WProgram.h>
47
47
48
-
49
48
#include " Servo.h"
50
49
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
52
52
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
55
53
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
57
55
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)
65
60
66
61
uint8_t ServoCount = 0 ; // the total number of attached servos
67
62
63
+
68
64
// 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
70
66
#define SERVO_INDEX_TO_CHANNEL (_servo_nbr ) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
71
67
#define SERVO_INDEX (_timer,_channel ) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
72
68
#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
76
72
77
73
/* *********** static functions common to all instances ***********************/
78
74
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)
80
76
{
81
77
if ( Channel[timer] < 0 )
82
78
*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
93
89
}
94
90
else {
95
91
// 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) ;
98
94
else
99
95
*OCRnA = *TCNTn + 4 ; // at least REFRESH_INTERVAL has elapsed
100
96
Channel[timer] = -1 ; // this will get incremented at the end of the refresh period to start again at the first channel
101
97
}
102
98
}
103
99
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)
104
103
SIGNAL (TIMER1_COMPA_vect)
105
104
{
106
105
handle_interrupts (_timer1, &TCNT1, &OCR1A);
107
106
}
107
+ #endif
108
108
109
- #if defined(__AVR_ATmega1280__ )
109
+ #if defined(_useTimer3 )
110
110
SIGNAL (TIMER3_COMPA_vect)
111
111
{
112
112
handle_interrupts (_timer3, &TCNT3, &OCR3A);
113
113
}
114
+ #endif
115
+
116
+ #if defined(_useTimer4)
114
117
SIGNAL (TIMER4_COMPA_vect)
115
118
{
116
119
handle_interrupts (_timer4, &TCNT4, &OCR4A);
117
120
}
121
+ #endif
122
+
123
+ #if defined(_useTimer5)
118
124
SIGNAL (TIMER5_COMPA_vect)
119
125
{
120
126
handle_interrupts (_timer5, &TCNT5, &OCR5A);
121
127
}
122
128
#endif
123
129
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)
125
148
{
149
+ #if defined (_useTimer1)
126
150
if (timer == _timer1) {
127
151
TCCR1A = 0 ; // normal counting mode
128
152
TCCR1B = _BV (CS11); // set prescaler of 8
129
153
TCNT1 = 0 ; // clear the timer count
130
- #if defined(__AVR_ATmega8__)
154
+ #if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
131
155
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
133
157
#else
158
+ // here if not ATmega8 or ATmega128
134
159
TIFR1 |= _BV (OCF1A); // clear any pending interrupts;
135
160
TIMSK1 |= _BV (OCIE1A) ; // enable the output compare interrupt
136
- #endif
161
+ #endif
162
+ #if defined(WIRING)
163
+ timerAttach (TIMER1OUTCOMPAREA_INT, Timer1Service);
164
+ #endif
137
165
}
138
- #if defined(__AVR_ATmega1280__)
139
- else if (timer == _timer3) {
166
+ #endif
167
+
168
+ #if defined (_useTimer3)
169
+ if (timer == _timer3) {
140
170
TCCR3A = 0 ; // normal counting mode
141
171
TCCR3B = _BV (CS31); // set prescaler of 8
142
172
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
143
177
TIFR3 = _BV (OCF3A); // clear any pending interrupts;
144
178
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
145
183
}
146
- else if (timer == _timer4) {
184
+ #endif
185
+
186
+ #if defined (_useTimer4)
187
+ if (timer == _timer4) {
147
188
TCCR4A = 0 ; // normal counting mode
148
189
TCCR4B = _BV (CS41); // set prescaler of 8
149
190
TCNT4 = 0 ; // clear the timer count
150
191
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) {
154
198
TCCR5A = 0 ; // normal counting mode
155
199
TCCR5B = _BV (CS51); // set prescaler of 8
156
200
TCNT5 = 0 ; // clear the timer count
@@ -160,7 +204,32 @@ static void initISR(servoTimer_t timer)
160
204
#endif
161
205
}
162
206
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)
164
233
{
165
234
// returns true if any servo is active on this timer
166
235
for (uint8_t channel=0 ; channel < SERVOS_PER_TIMER; channel++) {
@@ -177,7 +246,7 @@ Servo::Servo()
177
246
{
178
247
if ( ServoCount < MAX_SERVOS) {
179
248
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
181
250
}
182
251
else
183
252
this ->servoIndex = INVALID_SERVO ; // too many servos
@@ -197,7 +266,7 @@ uint8_t Servo::attach(int pin, int min, int max)
197
266
this ->min = (MIN_PULSE_WIDTH - min)/4 ; // resolution of min/max is 4 uS
198
267
this ->max = (MAX_PULSE_WIDTH - max)/4 ;
199
268
// 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);
201
270
if (isTimerActive (timer) == false )
202
271
initISR (timer);
203
272
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)
208
277
void Servo::detach ()
209
278
{
210
279
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);
215
283
}
216
- #endif
217
284
}
218
285
219
286
void Servo::write (int value)
@@ -238,7 +305,9 @@ void Servo::writeMicroseconds(int value)
238
305
else if ( value > SERVO_MAX () )
239
306
value = SERVO_MAX ();
240
307
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
+
242
311
uint8_t oldSREG = SREG;
243
312
cli ();
244
313
servos[channel].ticks = value;
@@ -255,7 +324,7 @@ int Servo::readMicroseconds()
255
324
{
256
325
unsigned int pulsewidth;
257
326
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
259
328
else
260
329
pulsewidth = 0 ;
261
330
0 commit comments