Skip to content

Commit b848ab2

Browse files
authored
Merge pull request #21 from daniel-mohr/master
fixed imprecisse timing on SAMD21 (Arduino Zero)
2 parents 14739c9 + b1407f3 commit b848ab2

File tree

6 files changed

+82
-33
lines changed

6 files changed

+82
-33
lines changed

.arduino-ci.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
compile:
2+
platforms:
3+
- uno
4+
- due
5+
- zero
6+
- leonardo
7+
- m4
8+
- esp32
9+
#- esp8266
10+
- mega2560
11+
- nano_every

.github/workflows/arduino-lint.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
name: arduino-lint
3+
4+
on: [push, pull_request]
5+
6+
jobs:
7+
lint:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
# https://github.com/actions/checkout
12+
- uses: arduino/arduino-lint-action@v1
13+
# https://github.com/arduino/arduino-lint-action
14+
with:
15+
library-manager: update
16+
compliance: strict

.github/workflows/arduino_ci.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
name: arduino_ci
3+
4+
on: [push, pull_request]
5+
6+
jobs:
7+
arduino_ci:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
# https://github.com/actions/checkout
12+
- uses: Arduino-CI/action@stable-1.x
13+
# https://github.com/marketplace/actions/arduino_ci

contributors.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Naguissa - https://github.com/Naguissa
22
svlPanelMaker - https://github.com/svlPanelMaker - SAMD21 timing issue fix
33
Raf (Raffaele Rialdi) - https://github.com/raffaeler - ESP32 hardware timer (better precission than ticker library)
4+
Daniel Mohr - https://github.com/daniel-mohr - SAMD21 timing issue fix

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=1.7.1
2+
version=1.7.2
33
author=Naguissa <naguissa@foroelectro.net>
44
maintainer=Naguissa <naguissa@foroelectro.net>
55
sentence=Tiny and cross-device compatible timer library

src/hardware/uTimerLib.SAMD21.cpp

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,41 @@
5252
5353
Prescaler:
5454
Prescalers: GCLK_TC, GCLK_TC/2, GCLK_TC/4, GCLK_TC/8, GCLK_TC/16, GCLK_TC/64, GCLK_TC/256, GCLK_TC/1024
55-
Base frequency: 84MHz
55+
Base frequency: 48MHz
5656
5757
We will use TCC2, as there're some models with only 3 timers (regular models have 5 TCs)
5858
5959
REMEMBER! 16 bit counter!!!
6060
6161
6262
Name Prescaler Freq Base Delay Overflow delay
63-
GCLK_TC 1 48MHz 0,020833333us 1365,333333333us; 1,365333333333ms
64-
GCLK_TC/2 2 24MHz 0,041666667us 2730,666666667us; 2,730666666667ms
65-
GCLK_TC/4 4 12MHz 0,083333333us 5461,333333333us; 5,461333333333ms
66-
GCLK_TC/8 8 6MHz 0,166666667us 10922,666666667us; 10,922666666667ms
67-
GCLK_TC/16 16 3MHz 0,333333333us 21845,333333333us; 21,845333333333ms
68-
GCLK_TC/64 64 750KHz 1,333333333us 87381,333311488us; 87,381333311488ms
69-
GCLK_TC/256 256 187,5KHz 5,333333333us 349525,333311488us; 349,525333311488ms
70-
GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s
63+
GCLK_TC 1 48MHz ~0,020833333us 1365,3125us; 1,3653125ms
64+
GCLK_TC/2 2 24MHz ~0,041666667us 2730,625us; 2,730625ms
65+
GCLK_TC/4 4 12MHz ~0,083333333us 5461,25us; 5,46125ms
66+
GCLK_TC/8 8 6MHz ~0,166666667us 10922,5us; 10,9225ms
67+
GCLK_TC/16 16 3MHz ~0,333333333us 21845us; 21,845ms
68+
GCLK_TC/64 64 750KHz ~1,333333333us 87380us; 87,380ms
69+
GCLK_TC/256 256 187,5KHz ~5,333333333us 349520us; 349,52ms
70+
GCLK_TC/1024 1024 46.875kHz ~21,333333333us 1398080us; 1398,08ms; 1,39808s
71+
72+
In general:
73+
freq = 48 MHz / prescaler
74+
base_delay = 1 / freq
75+
overflow_delay = UINT16_MAX * base_delay
7176
7277
Will be using:
7378
GCLK_TC/16 for us
7479
GCLK_TC/1024 for s
80+
81+
GCLK_TC/16:
82+
freq = 48 MHz / prescaler = 48 MHz / 16 = 3 MHz
83+
base_delay = 1 / freq = 1 / 3e6 s = 1/3 us ~= 0.333333333 us
84+
overflow_delay = UINT16_MAX * base_delay = 65535 / 3 us = 21845 us
85+
86+
GCLK_TC/1024:
87+
freq = 48 MHz / prescaler = 48 MHz / 1024 = 46.875 kHz = 46875 Hz
88+
base_delay = 1 / freq = 1 / 46875 s = ~= 21.333333333us
89+
overflow_delay = UINT16_MAX * base_delay = 65535 / 46875 s = 1.39808 s
7590
*/
7691

7792
// Enable clock for TC
@@ -82,23 +97,23 @@
8297
_TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
8398
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
8499

85-
// Set Timer counter Mode to 16 bits + Set TC as normal Normal Frq + Prescaler: GCLK_TC/16
86-
_TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV16);
100+
// Set Timer counter Mode to 16 bits + Set TC as normal Match Frq + Prescaler: GCLK_TC/16
101+
_TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_MFRQ + TC_CTRLA_PRESCALER_DIV16);
87102
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
88103

89104
if (us > 21845) {
90-
__overflows = _overflows = us / 21845.333333333;
91-
__remaining = _remaining = ((us - (21845.333333333 * _overflows)) / 0.333333333) + 0.5; // +0.5 is same as round
105+
__overflows = _overflows = us / 21845.0;
106+
__remaining = _remaining = (us - (21845 * _overflows)) * 3 - 1;
92107
} else {
93108
__overflows = _overflows = 0;
94-
__remaining = _remaining = (us / 0.333333333) + 0.5; // +0.5 is same as round
109+
__remaining = _remaining = us * 3 - 1;
95110
}
96111

97112
if (__overflows == 0) {
98113
_loadRemaining();
99114
_remaining = 0;
100115
} else {
101-
_TC->CC[0].reg = 65535;
116+
_TC->CC[0].reg = UINT16_MAX;
102117
_TC->INTENSET.reg = 0; // disable all interrupts
103118
_TC->INTENSET.bit.OVF = 1; // enable overfollow
104119
// Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
@@ -126,7 +141,7 @@
126141
}
127142

128143
/*
129-
GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s
144+
GCLK_TC/1024 1024 46.875kHz ~21,333333333us 1398080us; 1398,08ms; 1,39808s
130145
*/
131146

132147
// Enable clock for TC
@@ -137,23 +152,23 @@
137152
_TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
138153
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
139154

140-
// Set Timer counter Mode to 16 bits + Set TC as normal Normal Frq + Prescaler: GCLK_TC/1024
141-
_TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV1024);
155+
// Set Timer counter Mode to 16 bits + Set TC as normal Match Frq + Prescaler: GCLK_TC/1024
156+
_TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_MFRQ + TC_CTRLA_PRESCALER_DIV1024);
142157
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
143158

144159
if (s > 1) {
145-
__overflows = _overflows = s / 1.398101333333333;
146-
__remaining = _remaining = ((s - (1.398101333333333 * _overflows)) / 0.000021333333333) + 0.5; // +0.5 is same as round
160+
__overflows = _overflows = s / 1.39808;
161+
__remaining = _remaining = ((s * 100000) % 139808) * 480 / 1024 - 1; // for integer s this is always an integer
147162
} else {
148163
__overflows = _overflows = 0;
149-
__remaining = _remaining = (s / 0.000021333333333) + 0.5; // +0.5 is same as round
164+
__remaining = _remaining = s * 46875 - 1;
150165
}
151166

152167
if (__overflows == 0) {
153168
_loadRemaining();
154169
_remaining = 0;
155170
} else {
156-
_TC->CC[0].reg = 65535;
171+
_TC->CC[0].reg = UINT16_MAX;
157172
_TC->INTENSET.reg = 0; // disable all interrupts
158173
_TC->INTENSET.bit.OVF = 1; // enable overfollow
159174
// Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
@@ -174,7 +189,6 @@
174189
* Note: This is device-dependant
175190
*/
176191
void uTimerLib::_loadRemaining() {
177-
_TC->COUNT.reg = 0; // Reset to 0
178192
_TC->CC[0].reg = _remaining;
179193
_TC->INTENSET.reg = 0; // disable all interrupts
180194
_TC->INTENSET.bit.MC0 = 1; // enable compare match to CC0
@@ -217,28 +231,22 @@
217231
if (_type == UTIMERLIB_TYPE_TIMEOUT) {
218232
clearTimer();
219233
} else if (_type == UTIMERLIB_TYPE_INTERVAL) {
220-
if (__overflows == 0) {
221-
_remaining = __remaining;
222-
_loadRemaining();
223-
_remaining = 0;
224-
} else {
234+
if (__overflows != 0) {
225235
_overflows = __overflows;
226236
_remaining = __remaining;
227237

228-
_TC->COUNT.reg = 0; // Reset to 0
229238
_TC->INTENSET.reg = 0; // disable all interrupts
230239
_TC->INTENSET.bit.OVF = 0; // enable overfollow
231240
_TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0
232-
_TC->CC[0].reg = 65535;
241+
_TC->CC[0].reg = UINT16_MAX;
233242
}
234243
}
235244
_cb();
236245
} else if (_overflows > 0) { // Reload for SAMD21
237-
_TC->COUNT.reg = 0; // Reset to 0
238246
_TC->INTENSET.reg = 0; // disable all interrupts
239247
_TC->INTENSET.bit.OVF = 0; // enable overfollow
240248
_TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0
241-
_TC->CC[0].reg = 65535;
249+
_TC->CC[0].reg = UINT16_MAX;
242250
}
243251
}
244252

0 commit comments

Comments
 (0)