Skip to content

Commit

Permalink
Merge pull request #21 from daniel-mohr/master
Browse files Browse the repository at this point in the history
fixed imprecisse timing on SAMD21 (Arduino Zero)
  • Loading branch information
Naguissa authored Sep 29, 2023
2 parents 14739c9 + b1407f3 commit b848ab2
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 33 deletions.
11 changes: 11 additions & 0 deletions .arduino-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
compile:
platforms:
- uno
- due
- zero
- leonardo
- m4
- esp32
#- esp8266
- mega2560
- nano_every
16 changes: 16 additions & 0 deletions .github/workflows/arduino-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: arduino-lint

on: [push, pull_request]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# https://github.com/actions/checkout
- uses: arduino/arduino-lint-action@v1
# https://github.com/arduino/arduino-lint-action
with:
library-manager: update
compliance: strict
13 changes: 13 additions & 0 deletions .github/workflows/arduino_ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: arduino_ci

on: [push, pull_request]

jobs:
arduino_ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# https://github.com/actions/checkout
- uses: Arduino-CI/[email protected]
# https://github.com/marketplace/actions/arduino_ci
1 change: 1 addition & 0 deletions contributors.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Naguissa - https://github.com/Naguissa
svlPanelMaker - https://github.com/svlPanelMaker - SAMD21 timing issue fix
Raf (Raffaele Rialdi) - https://github.com/raffaeler - ESP32 hardware timer (better precission than ticker library)
Daniel Mohr - https://github.com/daniel-mohr - SAMD21 timing issue fix
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=uTimerLib
version=1.7.1
version=1.7.2
author=Naguissa <[email protected]>
maintainer=Naguissa <[email protected]>
sentence=Tiny and cross-device compatible timer library
Expand Down
72 changes: 40 additions & 32 deletions src/hardware/uTimerLib.SAMD21.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,41 @@
Prescaler:
Prescalers: GCLK_TC, GCLK_TC/2, GCLK_TC/4, GCLK_TC/8, GCLK_TC/16, GCLK_TC/64, GCLK_TC/256, GCLK_TC/1024
Base frequency: 84MHz
Base frequency: 48MHz
We will use TCC2, as there're some models with only 3 timers (regular models have 5 TCs)
REMEMBER! 16 bit counter!!!
Name Prescaler Freq Base Delay Overflow delay
GCLK_TC 1 48MHz 0,020833333us 1365,333333333us; 1,365333333333ms
GCLK_TC/2 2 24MHz 0,041666667us 2730,666666667us; 2,730666666667ms
GCLK_TC/4 4 12MHz 0,083333333us 5461,333333333us; 5,461333333333ms
GCLK_TC/8 8 6MHz 0,166666667us 10922,666666667us; 10,922666666667ms
GCLK_TC/16 16 3MHz 0,333333333us 21845,333333333us; 21,845333333333ms
GCLK_TC/64 64 750KHz 1,333333333us 87381,333311488us; 87,381333311488ms
GCLK_TC/256 256 187,5KHz 5,333333333us 349525,333311488us; 349,525333311488ms
GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s
GCLK_TC 1 48MHz ~0,020833333us 1365,3125us; 1,3653125ms
GCLK_TC/2 2 24MHz ~0,041666667us 2730,625us; 2,730625ms
GCLK_TC/4 4 12MHz ~0,083333333us 5461,25us; 5,46125ms
GCLK_TC/8 8 6MHz ~0,166666667us 10922,5us; 10,9225ms
GCLK_TC/16 16 3MHz ~0,333333333us 21845us; 21,845ms
GCLK_TC/64 64 750KHz ~1,333333333us 87380us; 87,380ms
GCLK_TC/256 256 187,5KHz ~5,333333333us 349520us; 349,52ms
GCLK_TC/1024 1024 46.875kHz ~21,333333333us 1398080us; 1398,08ms; 1,39808s
In general:
freq = 48 MHz / prescaler
base_delay = 1 / freq
overflow_delay = UINT16_MAX * base_delay
Will be using:
GCLK_TC/16 for us
GCLK_TC/1024 for s
GCLK_TC/16:
freq = 48 MHz / prescaler = 48 MHz / 16 = 3 MHz
base_delay = 1 / freq = 1 / 3e6 s = 1/3 us ~= 0.333333333 us
overflow_delay = UINT16_MAX * base_delay = 65535 / 3 us = 21845 us
GCLK_TC/1024:
freq = 48 MHz / prescaler = 48 MHz / 1024 = 46.875 kHz = 46875 Hz
base_delay = 1 / freq = 1 / 46875 s = ~= 21.333333333us
overflow_delay = UINT16_MAX * base_delay = 65535 / 46875 s = 1.39808 s
*/

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

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

if (us > 21845) {
__overflows = _overflows = us / 21845.333333333;
__remaining = _remaining = ((us - (21845.333333333 * _overflows)) / 0.333333333) + 0.5; // +0.5 is same as round
__overflows = _overflows = us / 21845.0;
__remaining = _remaining = (us - (21845 * _overflows)) * 3 - 1;
} else {
__overflows = _overflows = 0;
__remaining = _remaining = (us / 0.333333333) + 0.5; // +0.5 is same as round
__remaining = _remaining = us * 3 - 1;
}

if (__overflows == 0) {
_loadRemaining();
_remaining = 0;
} else {
_TC->CC[0].reg = 65535;
_TC->CC[0].reg = UINT16_MAX;
_TC->INTENSET.reg = 0; // disable all interrupts
_TC->INTENSET.bit.OVF = 1; // enable overfollow
// Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
Expand Down Expand Up @@ -126,7 +141,7 @@
}

/*
GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s
GCLK_TC/1024 1024 46.875kHz ~21,333333333us 1398080us; 1398,08ms; 1,39808s
*/

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

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

if (s > 1) {
__overflows = _overflows = s / 1.398101333333333;
__remaining = _remaining = ((s - (1.398101333333333 * _overflows)) / 0.000021333333333) + 0.5; // +0.5 is same as round
__overflows = _overflows = s / 1.39808;
__remaining = _remaining = ((s * 100000) % 139808) * 480 / 1024 - 1; // for integer s this is always an integer
} else {
__overflows = _overflows = 0;
__remaining = _remaining = (s / 0.000021333333333) + 0.5; // +0.5 is same as round
__remaining = _remaining = s * 46875 - 1;
}

if (__overflows == 0) {
_loadRemaining();
_remaining = 0;
} else {
_TC->CC[0].reg = 65535;
_TC->CC[0].reg = UINT16_MAX;
_TC->INTENSET.reg = 0; // disable all interrupts
_TC->INTENSET.bit.OVF = 1; // enable overfollow
// Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
Expand All @@ -174,7 +189,6 @@
* Note: This is device-dependant
*/
void uTimerLib::_loadRemaining() {
_TC->COUNT.reg = 0; // Reset to 0
_TC->CC[0].reg = _remaining;
_TC->INTENSET.reg = 0; // disable all interrupts
_TC->INTENSET.bit.MC0 = 1; // enable compare match to CC0
Expand Down Expand Up @@ -217,28 +231,22 @@
if (_type == UTIMERLIB_TYPE_TIMEOUT) {
clearTimer();
} else if (_type == UTIMERLIB_TYPE_INTERVAL) {
if (__overflows == 0) {
_remaining = __remaining;
_loadRemaining();
_remaining = 0;
} else {
if (__overflows != 0) {
_overflows = __overflows;
_remaining = __remaining;

_TC->COUNT.reg = 0; // Reset to 0
_TC->INTENSET.reg = 0; // disable all interrupts
_TC->INTENSET.bit.OVF = 0; // enable overfollow
_TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0
_TC->CC[0].reg = 65535;
_TC->CC[0].reg = UINT16_MAX;
}
}
_cb();
} else if (_overflows > 0) { // Reload for SAMD21
_TC->COUNT.reg = 0; // Reset to 0
_TC->INTENSET.reg = 0; // disable all interrupts
_TC->INTENSET.bit.OVF = 0; // enable overfollow
_TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0
_TC->CC[0].reg = 65535;
_TC->CC[0].reg = UINT16_MAX;
}
}

Expand Down

0 comments on commit b848ab2

Please sign in to comment.