4
4
* Timers used by microcontroller
5
5
* Atmel AVR: Timer2 (3rd timer)
6
6
* STM32: Timer3 (3rd timer)
7
+ * SAM (Due): TC3 (Timer1, channel 0)
7
8
*
8
9
* @copyright Naguissa
9
10
* @author Naguissa
@@ -100,6 +101,9 @@ int uTimerLib::setTimeout_s(void (* cb)(), unsigned long int s) {
100
101
* @param unsigned long int us Desired timing in microseconds
101
102
*/
102
103
void uTimerLib::_attachInterrupt_us (unsigned long int us) {
104
+ if (us == 0 ) { // Not valid
105
+ return ;
106
+ }
103
107
#ifdef ARDUINO_ARCH_AVR
104
108
unsigned char CSMask = 0 ;
105
109
// For this notes, we asume 16MHz CPU. We recalculate 'us' if not:
@@ -126,23 +130,23 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
126
130
if (us >= 16384 ) {
127
131
CSMask = (1 <<CS22) | (1 <<CS21) | (1 <<CS20);
128
132
_overflows = us / 16384 ;
129
- _remaining = 256 - round ((us % 16384 ) / 64 );
133
+ _remaining = 256 - ((us % 16384 ) / 64 + 0.5 ); // + 0.5 is round for positive numbers
130
134
} else {
131
135
if (us >= 4096 ) {
132
136
CSMask = (1 <<CS22) | (1 <<CS21) | (1 <<CS20);
133
- _remaining = 256 - round (us / 64 );
137
+ _remaining = 256 - (us / 64 + 0.5 ); // + 0.5 is round for positive numbers
134
138
} else if (us >= 2048 ) {
135
139
CSMask = (1 <<CS22) | (1 <<CS21);
136
- _remaining = 256 - round (us / 16 );
140
+ _remaining = 256 - (us / 16 + 0.5 ); // + 0.5 is round for positive numbers
137
141
} else if (us >= 1024 ) {
138
142
CSMask = (1 <<CS22) | (1 <<CS20);
139
- _remaining = 256 - round (us / 8 );
143
+ _remaining = 256 - (us / 8 + 0.5 ); // + 0.5 is round for positive numbers
140
144
} else if (us >= 512 ) {
141
145
CSMask = (1 <<CS22);
142
- _remaining = 256 - round (us / 4 );
146
+ _remaining = 256 - (us / 4 + 0.5 ); // + 0.5 is round for positive numbers
143
147
} else if (us >= 128 ) {
144
148
CSMask = (1 <<CS21) | (1 <<CS20);
145
- _remaining = 256 - round (us / 2 );
149
+ _remaining = 256 - (us / 2 + 0.5 ); // + 0.5 is round for positive numbers
146
150
} else if (us >= 16 ) {
147
151
CSMask = (1 <<CS21);
148
152
_remaining = 256 - us * 2 ;
@@ -163,6 +167,7 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
163
167
// Clean counter in normal operation, load remaining when overflows == 0
164
168
if (__overflows == 0 ) {
165
169
_loadRemaining ();
170
+ _remaining = 0 ;
166
171
} else {
167
172
TCNT2 = 0 ; // Clean timer count
168
173
}
@@ -188,6 +193,66 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
188
193
#endif
189
194
190
195
196
+
197
+ // SAM, Arduino Due
198
+ #ifdef ARDUINO_ARCH_SAM
199
+ /*
200
+ Prescalers: MCK/2, MCK/8, MCK/32, MCK/128
201
+ Base frequency: 84MHz
202
+
203
+ Available Timers:
204
+ ISR/IRQ TC Channel Due pins
205
+ TC0 TC0 0 2, 13
206
+ TC1 TC0 1 60, 61
207
+ TC2 TC0 2 58
208
+ TC3 TC1 0 none
209
+ TC4 TC1 1 none
210
+ TC5 TC1 2 none
211
+ TC6 TC2 0 4, 5
212
+ TC7 TC2 1 3, 10
213
+ TC8 TC2 2 11, 12
214
+
215
+ We will use TC1, as it has no associated pins. We will choose Channel 0, so ISR is TC3
216
+
217
+ REMEMBER! 32 bit counter!!!
218
+
219
+
220
+ Name Prescaler Freq Base Delay Overflow delay
221
+ TC_CMR_TCCLKS_TIMER_CLOCK1 2 42MHz 0,023809524us 102261126,913327104us, 102,261126913327104s
222
+ TC_CMR_TCCLKS_TIMER_CLOCK2 8 10.5MHz 0,095238095us 409044503,35834112us, 409,04450335834112s
223
+ TC_CMR_TCCLKS_TIMER_CLOCK3 32 2.625MHz 0,380952381us 1636178017,523809524us, 1636,178017523809524s
224
+ TC_CMR_TCCLKS_TIMER_CLOCK4 128 656.25KHz 1,523809524us 6544712070,913327104us, 6544,712070913327104s
225
+
226
+ For simplify things, we'll use always TC_CMR_TCCLKS_TIMER_CLOCK32,as has enougth resolution for us.
227
+
228
+
229
+ */
230
+ if (us > 1636178017 ) {
231
+ __overflows = _overflows = us / 1636178017.523809524 ;
232
+ __remaining = _remaining = (us - (1636178017.523809524 * _overflows)) / 0.380952381 + 0.5 ; // +0.5 is same as round
233
+ } else {
234
+ __overflows = _overflows = 0 ;
235
+ __remaining = _remaining = (us / 0.380952381 + 0.5 ); // +0.5 is same as round
236
+ }
237
+ pmc_set_writeprotect (false ); // Enable write
238
+ pmc_enable_periph_clk ((uint32_t ) TC3_IRQn); // Enable TC1 - channel 0 peripheral
239
+ TC_Configure (TC1, 0 , TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK3); // Configure clock; prescaler = 32
240
+
241
+ if (__overflows == 0 ) {
242
+ _loadRemaining ();
243
+ _remaining = 0 ;
244
+ } else {
245
+ TC_SetRC (TC1, 0 , 4294967295 ); // Int on last number
246
+ }
247
+
248
+ TC_Start (TC1, 0 );
249
+ TC1->TC_CHANNEL [0 ].TC_IER = TC_IER_CPCS;
250
+ TC1->TC_CHANNEL [0 ].TC_IDR = ~TC_IER_CPCS;
251
+ NVIC_EnableIRQ (TC3_IRQn);
252
+ #endif
253
+
254
+
255
+
191
256
}
192
257
193
258
@@ -199,6 +264,9 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
199
264
* @param unsigned long int s Desired timing in seconds
200
265
*/
201
266
void uTimerLib::_attachInterrupt_s (unsigned long int s) {
267
+ if (s == 0 ) { // Not valid
268
+ return ;
269
+ }
202
270
// Arduino AVR
203
271
#ifdef ARDUINO_ARCH_AVR
204
272
unsigned char CSMask = 0 ;
@@ -224,9 +292,9 @@ void uTimerLib::_attachInterrupt_s(unsigned long int s) {
224
292
// Anti-Overflow trick:
225
293
if (s > 16384 ) {
226
294
unsigned long int temp = floor (s / 16384 ) * 16384 ;
227
- _remaining = 256 - round ((((s - temp) * 1000000 ) % 16384 ) / 64 );
295
+ _remaining = 256 - ((((s - temp) * 1000000 ) % 16384 ) / 64 + 0.5 ); // + 0.5 is round for positive numbers
228
296
} else {
229
- _remaining = 256 - round (((s * 1000000 ) % 16384 ) / 64 );
297
+ _remaining = 256 - (((s * 1000000 ) % 16384 ) / 64 + 0.5 ); // + 0.5 is round for positive numbers
230
298
}
231
299
232
300
__overflows = _overflows;
@@ -264,6 +332,43 @@ void uTimerLib::_attachInterrupt_s(unsigned long int s) {
264
332
Timer3.resume ();
265
333
#endif
266
334
335
+
336
+ // SAM, Arduino Due
337
+ #ifdef ARDUINO_ARCH_SAM
338
+ /*
339
+
340
+ See _ms functions for detailed info; here only selected points
341
+
342
+ Name Prescaler Freq Base Delay Overflow delay
343
+ TC_CMR_TCCLKS_TIMER_CLOCK4 128 656.25KHz 1,523809524us 6544712070,913327104us, 6544,712070913327104s
344
+
345
+ For simplify things, we'll use always TC_CMR_TCCLKS_TIMER_CLOCK32,as has enougth resolution for us.
346
+ */
347
+ if (s > 6544 ) {
348
+ __overflows = _overflows = s / 6544.712070913327104 ;
349
+ __remaining = _remaining = (s - (6544.712070913327104 * _overflows) / 0.000001523809524 + 0.5 ); // +0.5 is same as round
350
+ } else {
351
+ __overflows = _overflows = 0 ;
352
+ __remaining = _remaining = (s / 0.000001523809524 + 0.5 ); // +0.5 is same as round
353
+ }
354
+
355
+ pmc_set_writeprotect (false ); // Enable write
356
+ // pmc_enable_periph_clk((uint32_t) TC3_IRQn); // Enable TC1 - channel 0 peripheral
357
+ pmc_enable_periph_clk (ID_TC3); // Enable TC1 - channel 0 peripheral
358
+ TC_Configure (TC1, 0 , TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4); // Configure clock; prescaler = 128
359
+
360
+ if (__overflows == 0 ) {
361
+ _loadRemaining ();
362
+ _remaining = 0 ;
363
+ } else {
364
+ TC_SetRC (TC1, 0 , 4294967295 ); // Int on last number
365
+ }
366
+
367
+ TC1->TC_CHANNEL [0 ].TC_IER =TC_IER_CPCS;
368
+ TC1->TC_CHANNEL [0 ].TC_IDR =~TC_IER_CPCS;
369
+ NVIC_EnableIRQ (TC3_IRQn);
370
+ TC_Start (TC1, 0 );
371
+ #endif
267
372
}
268
373
269
374
@@ -279,6 +384,10 @@ void uTimerLib::_loadRemaining() {
279
384
#endif
280
385
281
386
// STM32: Not needed
387
+
388
+ #ifdef ARDUINO_ARCH_SAM
389
+ TC_SetRC (TC1, 0 , _remaining);
390
+ #endif
282
391
}
283
392
284
393
/* *
@@ -297,6 +406,12 @@ void uTimerLib::clearTimer() {
297
406
#ifdef _VARIANT_ARDUINO_STM32_
298
407
Timer3.pause ();
299
408
#endif
409
+
410
+ // SAM, Arduino Due
411
+ #ifdef ARDUINO_ARCH_SAM
412
+ NVIC_DisableIRQ (TC3_IRQn);
413
+ #endif
414
+
300
415
}
301
416
302
417
/* *
@@ -309,27 +424,40 @@ void uTimerLib::_interrupt() {
309
424
if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen
310
425
return ;
311
426
}
427
+
312
428
if (_overflows > 0 ) {
313
429
_overflows--;
314
430
}
315
431
if (_overflows == 0 && _remaining > 0 ) {
316
- // Load remaining count to counter
317
- _loadRemaining ();
318
- // And clear remaining count
319
- _remaining = 0 ;
432
+ // Load remaining count to counter
433
+ _loadRemaining ();
434
+ // And clear remaining count
435
+ _remaining = 0 ;
320
436
} else if (_overflows == 0 && _remaining == 0 ) {
321
437
if (_type == UTIMERLIB_TYPE_TIMEOUT) {
322
438
clearTimer ();
323
439
} else if (_type == UTIMERLIB_TYPE_INTERVAL) {
324
440
if (__overflows == 0 ) {
441
+ _remaining = __remaining;
325
442
_loadRemaining ();
443
+ _remaining = 0 ;
326
444
} else {
327
445
_overflows = __overflows;
328
446
_remaining = __remaining;
447
+ #ifdef ARDUINO_ARCH_SAM
448
+ TC_SetRC (TC1, 0 , 4294967295 );
449
+ #endif
329
450
}
330
451
}
331
452
_cb ();
332
453
}
454
+ #ifdef ARDUINO_ARCH_SAM
455
+ // Reload for SAM
456
+ else if (_overflows > 0 ) {
457
+ TC_SetRC (TC1, 0 , 4294967295 );
458
+ }
459
+ #endif
460
+
333
461
}
334
462
335
463
/* *
@@ -361,3 +489,11 @@ uTimerLib TimerLib = uTimerLib();
361
489
}
362
490
#endif
363
491
492
+
493
+ #ifdef ARDUINO_ARCH_SAM
494
+ void TC3_Handler () {
495
+ TC_GetStatus (TC1, 0 ); // reset interrupt
496
+ TimerLib._interrupt ();
497
+ }
498
+ #endif
499
+
0 commit comments