Skip to content

Commit b241e27

Browse files
committed
Version 0.3.0:
- Added SAM (Arduino DUE) compatibility - Some timing fixes - Examples more correct (added volatile to variable used in ISR)
1 parent 98c4b27 commit b241e27

File tree

9 files changed

+166
-19
lines changed

9 files changed

+166
-19
lines changed

examples/uTimerLib_setInterval_s_example_led/uTimerLib_setInterval_s_example_led.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313

14-
bool status = 0;
14+
volatile bool status = 0;
1515

1616
void timed_function() {
1717
status = !status;

examples/uTimerLib_setInterval_us_example_led/uTimerLib_setInterval_us_example_led.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919

20-
bool status = 0;
20+
volatile bool status = 0;
2121

2222
void timed_function() {
2323
status = !status;

examples/uTimerLib_setTimeout_s_example_led/uTimerLib_setTimeout_s_example_led.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313

14-
bool status = 0;
14+
volatile bool status = 0;
1515

1616
void timed_function() {
1717
status = !status;

examples/uTimerLib_setTimeout_us_example_led/uTimerLib_setTimeout_us_example_led.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313

14-
bool status = 0;
14+
volatile bool status = 0;
1515

1616
void timed_function() {
1717
status = !status;
Binary file not shown.

extras/data sources.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
AVR Timer2:
22
- https://hetpro-store.com/TUTORIALES/arduino-timer/
33
- https://playground.arduino.cc/Main/TimerPWMCheatsheet
4+
5+
Arduino DUE (SAM):
6+
- https://forum.arduino.cc/index.php?topic=130423.0
7+
- http://2manyprojects.net/timer-interrupts
8+
9+

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=uTimerLib
2-
version=0.2.1
2+
version=0.3.0
33
author=Naguissa <naguissa@foroelectro.net>
44
maintainer=Naguissa <naguissa@foroelectro.net>
55
sentence=Tiny and cross-device compatible timer library

src/uTimerLib.cpp

Lines changed: 148 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Timers used by microcontroller
55
* Atmel AVR: Timer2 (3rd timer)
66
* STM32: Timer3 (3rd timer)
7+
* SAM (Due): TC3 (Timer1, channel 0)
78
*
89
* @copyright Naguissa
910
* @author Naguissa
@@ -100,6 +101,9 @@ int uTimerLib::setTimeout_s(void (* cb)(), unsigned long int s) {
100101
* @param unsigned long int us Desired timing in microseconds
101102
*/
102103
void uTimerLib::_attachInterrupt_us(unsigned long int us) {
104+
if (us == 0) { // Not valid
105+
return;
106+
}
103107
#ifdef ARDUINO_ARCH_AVR
104108
unsigned char CSMask = 0;
105109
// For this notes, we asume 16MHz CPU. We recalculate 'us' if not:
@@ -126,23 +130,23 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
126130
if (us >= 16384) {
127131
CSMask = (1<<CS22) | (1<<CS21) | (1<<CS20);
128132
_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
130134
} else {
131135
if (us >= 4096) {
132136
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
134138
} else if (us >= 2048) {
135139
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
137141
} else if (us >= 1024) {
138142
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
140144
} else if (us >= 512) {
141145
CSMask = (1<<CS22);
142-
_remaining = 256 - round(us / 4);
146+
_remaining = 256 - (us / 4 + 0.5); // + 0.5 is round for positive numbers
143147
} else if (us >= 128) {
144148
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
146150
} else if (us >= 16) {
147151
CSMask = (1<<CS21);
148152
_remaining = 256 - us * 2;
@@ -163,6 +167,7 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
163167
// Clean counter in normal operation, load remaining when overflows == 0
164168
if (__overflows == 0) {
165169
_loadRemaining();
170+
_remaining = 0;
166171
} else {
167172
TCNT2 = 0; // Clean timer count
168173
}
@@ -188,6 +193,66 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
188193
#endif
189194

190195

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+
191256
}
192257

193258

@@ -199,6 +264,9 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
199264
* @param unsigned long int s Desired timing in seconds
200265
*/
201266
void uTimerLib::_attachInterrupt_s(unsigned long int s) {
267+
if (s == 0) { // Not valid
268+
return;
269+
}
202270
// Arduino AVR
203271
#ifdef ARDUINO_ARCH_AVR
204272
unsigned char CSMask = 0;
@@ -224,9 +292,9 @@ void uTimerLib::_attachInterrupt_s(unsigned long int s) {
224292
// Anti-Overflow trick:
225293
if (s > 16384) {
226294
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
228296
} 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
230298
}
231299

232300
__overflows = _overflows;
@@ -264,6 +332,43 @@ void uTimerLib::_attachInterrupt_s(unsigned long int s) {
264332
Timer3.resume();
265333
#endif
266334

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
267372
}
268373

269374

@@ -279,6 +384,10 @@ void uTimerLib::_loadRemaining() {
279384
#endif
280385

281386
// STM32: Not needed
387+
388+
#ifdef ARDUINO_ARCH_SAM
389+
TC_SetRC(TC1, 0, _remaining);
390+
#endif
282391
}
283392

284393
/**
@@ -297,6 +406,12 @@ void uTimerLib::clearTimer() {
297406
#ifdef _VARIANT_ARDUINO_STM32_
298407
Timer3.pause();
299408
#endif
409+
410+
// SAM, Arduino Due
411+
#ifdef ARDUINO_ARCH_SAM
412+
NVIC_DisableIRQ(TC3_IRQn);
413+
#endif
414+
300415
}
301416

302417
/**
@@ -309,27 +424,40 @@ void uTimerLib::_interrupt() {
309424
if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen
310425
return;
311426
}
427+
312428
if (_overflows > 0) {
313429
_overflows--;
314430
}
315431
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;
320436
} else if (_overflows == 0 && _remaining == 0) {
321437
if (_type == UTIMERLIB_TYPE_TIMEOUT) {
322438
clearTimer();
323439
} else if (_type == UTIMERLIB_TYPE_INTERVAL) {
324440
if (__overflows == 0) {
441+
_remaining = __remaining;
325442
_loadRemaining();
443+
_remaining = 0;
326444
} else {
327445
_overflows = __overflows;
328446
_remaining = __remaining;
447+
#ifdef ARDUINO_ARCH_SAM
448+
TC_SetRC(TC1, 0, 4294967295);
449+
#endif
329450
}
330451
}
331452
_cb();
332453
}
454+
#ifdef ARDUINO_ARCH_SAM
455+
// Reload for SAM
456+
else if (_overflows > 0) {
457+
TC_SetRC(TC1, 0, 4294967295);
458+
}
459+
#endif
460+
333461
}
334462

335463
/**
@@ -361,3 +489,11 @@ uTimerLib TimerLib = uTimerLib();
361489
}
362490
#endif
363491

492+
493+
#ifdef ARDUINO_ARCH_SAM
494+
void TC3_Handler() {
495+
TC_GetStatus(TC1, 0); // reset interrupt
496+
TimerLib._interrupt();
497+
}
498+
#endif
499+

src/uTimerLib.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,14 @@
4848
static uTimerLib *_instance;
4949

5050
unsigned long int _overflows = 0;
51-
unsigned char _remaining = 0;
5251
unsigned long int __overflows = 0;
53-
unsigned char __remaining = 0;
52+
#ifdef ARDUINO_ARCH_AVR
53+
unsigned char _remaining = 0;
54+
unsigned char __remaining = 0;
55+
#else
56+
unsigned long int _remaining = 0;
57+
unsigned long int __remaining = 0;
58+
#endif
5459
void (*_cb)() = NULL;
5560
unsigned char _type = UTIMERLIB_TYPE_OFF;
5661

0 commit comments

Comments
 (0)