From ee0a22f5ee6bdc5c7f283f345e08356aab543aa3 Mon Sep 17 00:00:00 2001
From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com>
Date: Wed, 16 Nov 2022 20:33:35 -0500
Subject: [PATCH] v1.13.0 to update to use latest versions
### Major Releases v1.13.0
1. Update to use latest versions of the following libraries
- [ESP32_New_TimerInterrupt](https://github.com/khoih-prog/ESP32_New_TimerInterrupt)
- [MBED_RPI_PICO_TimerInterrupt](https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt)
- [megaAVR_TimerInterrupt](https://github.com/khoih-prog/megaAVR_TimerInterrupt)
- [NRF52_TimerInterrupt](https://github.com/khoih-prog/NRF52_TimerInterrupt)
- [NRF52_MBED_TimerInterrupt](https://github.com/khoih-prog/NRF52_MBED_TimerInterrupt)
2. Modify ESP32 examples to avoid using `LED_BUILTIN` / `GPIO2` as it can cause crash in some boards, such as `ESP32_C3`
3. Use `allman astyle` and add `utils`
4. Update `Packages_Patches`
---
CONTRIBUTING.md | 30 +-
README.md | 180 ++-
changelog.md | 20 +
library.json | 2 +-
library.properties | 2 +-
src/AVRTimerInterrupt_Generic.h | 1844 +++++++++++-----------
src/ESP32TimerInterrupt_Generic.h | 301 ++--
src/ESP8266TimerInterrupt_Generic.h | 47 +-
src/ISR_Timer-Impl_Generic.h | 137 +-
src/ISR_Timer_Generic.h | 28 +-
src/MBED_RP2040_TimerInterrupt_Generic.h | 77 +-
src/NRF52TimerInterrupt_Generic.h | 256 +--
src/NRF52_MBED_TimerInterrupt_Generic.h | 173 +-
src/RP2040_TimerInterrupt_Generic.h | 56 +-
src/SAMDTimerInterrupt_Generic.h | 1045 ++++++------
src/SAMDUETimerInterrupt_Generic.h | 146 +-
src/STM32TimerInterrupt_Generic.h | 25 +-
src/TeensyTimerInterrupt_Generic.h | 853 +++++-----
src/TimerInterrupt_Generic.h | 254 +--
src/TimerInterrupt_Generic_Debug.h | 4 +-
src/megaAVR_TimerInterrupt_Generic.h | 625 ++++----
utils/astyle_library.conf | 70 +
utils/restyle.sh | 6 +
23 files changed, 3288 insertions(+), 2893 deletions(-)
create mode 100644 utils/astyle_library.conf
create mode 100644 utils/restyle.sh
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ca8b49e0..cc6dfa79 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -27,14 +27,13 @@ Please ensure to specify the following:
```
Arduino IDE version: 1.8.19
-MBED RP2040 core v3.3.0
+MBED RP2040 core v3.4.1
RASPBERRY_PI_PICO Module
OS: Ubuntu 20.04 LTS
-Linux xy-Inspiron-3593 5.15.0-48-generic #54~20.04.1-Ubuntu SMP Thu Sep 1 16:17:26 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
+Linux xy-Inspiron-3593 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Context:
-I encountered a crash while trying to use this library
-
+I encountered a crash while using this library
Steps to reproduce:
1. ...
2. ...
@@ -42,14 +41,37 @@ Steps to reproduce:
4. ...
```
+### Additional context
+
+Add any other context about the problem here.
+
+---
+
### Sending Feature Requests
Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/TimerInterrupt_Generic/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
+---
+
### Sending Pull Requests
Pull Requests with changes and fixes are also welcome!
+Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux)
+
+1. Change directory to the library GitHub
+
+```
+xy@xy-Inspiron-3593:~$ cd Arduino/xy/TimerInterrupt_Generic_GitHub/
+xy@xy-Inspiron-3593:~/Arduino/xy/TimerInterrupt_Generic_GitHub$
+```
+
+2. Issue astyle command
+
+```
+xy@xy-Inspiron-3593:~/Arduino/xy/TimerInterrupt_Generic_GitHub$ bash utils/restyle.sh
+```
+
diff --git a/README.md b/README.md
index 512db291..95287b09 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,13 @@
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing)
[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/TimerInterrupt_Generic.svg)](http://github.com/khoih-prog/TimerInterrupt_Generic/issues)
+
+
+
+
+
---
---
@@ -45,6 +50,7 @@
* [10. For RTL8720DN boards using AmebaD core](#10-for-rtl8720dn-boards-using-amebad-core)
* [11. For SAMD21 and SAMD51 boards using ArduinoCore-fab-sam core](#11-For-SAMD21-and-SAMD51-boards-using-ArduinoCore-fab-sam-core)
* [12. For Seeeduino RP2040 boards](#12-For-Seeeduino-RP2040-boards)
+ * [13. For Seeeduino nRF52840 boards](#13-For-Seeeduino-nRF52840-boards)
* [Libraries' Patches](#libraries-patches)
* [1. For application requiring 2K+ HTML page](#1-for-application-requiring-2k-html-page)
* [2. For Ethernet library](#2-for-ethernet-library)
@@ -267,20 +273,20 @@ For Teensy 4.x, this library will be expanded to use other available hardware ti
2. [`ESP32 Core 2.0.5+`](https://github.com/espressif/arduino-esp32) for ESP32-based boards. [![Latest release](https://img.shields.io/github/release/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/latest/)
3. [`ESP8266 Core 3.0.2+`](https://github.com/esp8266/Arduino) for ESP8266-based boards. [![Latest release](https://img.shields.io/github/release/esp8266/Arduino.svg)](https://github.com/esp8266/Arduino/releases/latest/). To use ESP8266 core 2.7.1+ for LittleFS.
- 4. [`Arduino AVR core 1.8.5+`](https://github.com/arduino/ArduinoCore-avr) for Arduino (Use Arduino Board Manager) for AVR boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-avr.svg)](https://github.com/arduino/ArduinoCore-avr/releases/latest)
+ 4. [`Arduino AVR core 1.8.6+`](https://github.com/arduino/ArduinoCore-avr) for Arduino (Use Arduino Board Manager) for AVR boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-avr.svg)](https://github.com/arduino/ArduinoCore-avr/releases/latest)
5. [`Adafruit AVR core 1.4.13+`](https://github.com/adafruit/Adafruit_Arduino_Boards) for Adafruit AVR boards. Use Arduino Board Manager to install.
6. [`Sparkfun AVR core 1.1.13+`](https://github.com/sparkfun/Arduino_Boards) for Sparkfun AVR boards. Use Arduino Board Manager to install.
7. [`Teensy core v1.57+`](https://www.pjrc.com/teensy/td_download.html) for Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0) boards.
8. [`Arduino SAM DUE core v1.6.12+`](https://github.com/arduino/ArduinoCore-sam) for SAM DUE ARM Cortex-M3 boards.
9. [`Arduino SAMD core 1.8.13+`](https://github.com/arduino/ArduinoCore-samd) for SAMD ARM Cortex-M0+ boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-samd.svg)](https://github.com/arduino/ArduinoCore-samd/releases/latest)
-10. [`Adafruit SAMD core 1.7.10+`](https://github.com/adafruit/ArduinoCore-samd) for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). [![GitHub release](https://img.shields.io/github/release/adafruit/ArduinoCore-samd.svg)](https://github.com/adafruit/ArduinoCore-samd/releases/latest)
+10. [`Adafruit SAMD core 1.7.11+`](https://github.com/adafruit/ArduinoCore-samd) for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). [![GitHub release](https://img.shields.io/github/release/adafruit/ArduinoCore-samd.svg)](https://github.com/adafruit/ArduinoCore-samd/releases/latest)
11. [`Seeeduino SAMD core 1.8.3+`](https://github.com/Seeed-Studio/ArduinoCore-samd) for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). [![Latest release](https://img.shields.io/github/release/Seeed-Studio/ArduinoCore-samd.svg)](https://github.com/Seeed-Studio/ArduinoCore-samd/releases/latest/)
12. [`Sparkfun SAMD core 1.8.1+`](https://github.com/sparkfun/Arduino_Boards) for SAMD21/SAMD51 boards (SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc.).
13. [`Adafruit nRF52 v1.3.0+`](https://github.com/adafruit/Adafruit_nRF52_Arduino) for nRF52 boards such as Adafruit NRF52840_FEATHER, NRF52832_FEATHER, NRF52840_FEATHER_SENSE, NRF52840_ITSYBITSY, NRF52840_CIRCUITPLAY, NRF52840_CLUE, NRF52840_METRO, NRF52840_PCA10056, PARTICLE_XENON, **NINA_B302_ublox**, etc. [![GitHub release](https://img.shields.io/github/release/adafruit/Adafruit_nRF52_Arduino.svg)](https://github.com/adafruit/Adafruit_nRF52_Arduino/releases/latest)
14. [`Arduino Core for STM32 v2.3.0+`](https://github.com/stm32duino/Arduino_Core_STM32) for STM32F/L/H/G/WB/MP1 boards. [![GitHub release](https://img.shields.io/github/release/stm32duino/Arduino_Core_STM32.svg)](https://github.com/stm32duino/Arduino_Core_STM32/releases/latest)
15. [`Arduino megaAVR core 1.8.7+`](https://github.com/arduino/ArduinoCore-megaavr/releases) for Arduino megaAVR boards. Use Arduino Board Manager to install.
-16. [`Arduino mbed_rp2040 core 3.3.0+`](https://github.com/arduino/ArduinoCore-mbed) for Arduino (Use Arduino Board Manager) RP2040-based boards, such as **Arduino Nano RP2040 Connect, RASPBERRY_PI_PICO, etc.**. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-mbed.svg)](https://github.com/arduino/ArduinoCore-mbed/releases/latest)
-17. [`Earle Philhower's arduino-pico core v2.5.4+`](https://github.com/earlephilhower/arduino-pico) for RP2040-based boards such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, etc. [![GitHub release](https://img.shields.io/github/release/earlephilhower/arduino-pico.svg)](https://github.com/earlephilhower/arduino-pico/releases/latest)
+16. [`Arduino mbed_rp2040 core 3.4.1+`](https://github.com/arduino/ArduinoCore-mbed) for Arduino (Use Arduino Board Manager) RP2040-based boards, such as **Arduino Nano RP2040 Connect, RASPBERRY_PI_PICO, etc.**. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-mbed.svg)](https://github.com/arduino/ArduinoCore-mbed/releases/latest)
+17. [`Earle Philhower's arduino-pico core v2.6.3+`](https://github.com/earlephilhower/arduino-pico) for RP2040-based boards such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, etc. [![GitHub release](https://img.shields.io/github/release/earlephilhower/arduino-pico.svg)](https://github.com/earlephilhower/arduino-pico/releases/latest)
18. [`MegaCoreX megaAVR core 1.1.0+`](https://github.com/MCUdude/MegaCoreX/releases) for Arduino megaAVR boards. [![GitHub release](https://img.shields.io/github/release/MCUdude/MegaCoreX.svg)](https://github.com/MCUdude/MegaCoreX/releases/latest). Follow [**How to install**](https://github.com/MCUdude/MegaCoreX#how-to-install).
---
@@ -294,7 +300,7 @@ For Teensy 4.x, this library will be expanded to use other available hardware ti
- [`LwIP library v2.1.2+`](https://github.com/stm32duino/LwIP) for built-in LAN8742A Ethernet on (Nucleo-144, Discovery). [![GitHub release](https://img.shields.io/github/release/stm32duino/LwIP.svg)](https://github.com/stm32duino/LwIP/releases/latest)
21. For W5x00 Ethernet:
- - [`Ethernet_Generic library v2.6.1+`](https://github.com/khoih-prog/Ethernet_Generic) for W5100, W5200 and W5500/WIZ550io/WIZ850io/USR-ES1 with Wiznet W5500 chip. [![GitHub release](https://img.shields.io/github/release/khoih-prog/Ethernet_Generic.svg)](https://github.com/khoih-prog/Ethernet_Generic/releases/latest)
+ - [`Ethernet_Generic library v2.7.1+`](https://github.com/khoih-prog/Ethernet_Generic) for W5100, W5200 and W5500/WIZ550io/WIZ850io/USR-ES1 with Wiznet W5500 chip. [![GitHub release](https://img.shields.io/github/release/khoih-prog/Ethernet_Generic.svg)](https://github.com/khoih-prog/Ethernet_Generic/releases/latest)
22. For ENC28J60 Ethernet:
- [`EthernetENC library v2.0.3+`](https://github.com/jandrassy/EthernetENC) for ENC28J60. [![GitHub release](https://img.shields.io/github/release/jandrassy/EthernetENC.svg)](https://github.com/jandrassy/EthernetENC/releases/latest). **New and Better**
@@ -302,7 +308,7 @@ For Teensy 4.x, this library will be expanded to use other available hardware ti
---
-23. [`WiFiNINA_Generic library v1.8.14-6+`](https://github.com/khoih-prog/WiFiNINA_Generic) to use WiFiNINA modules/shields. To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiNINA_Generic.svg?)](https://www.ardu-badge.com/WiFiNINA_Generic) if using WiFiNINA for boards such as Nano 33 IoT, nRF52, Teensy, etc.
+23. [`WiFiNINA_Generic library v1.8.15-0+`](https://github.com/khoih-prog/WiFiNINA_Generic) to use WiFiNINA modules/shields. To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiNINA_Generic.svg?)](https://www.ardu-badge.com/WiFiNINA_Generic) if using WiFiNINA for boards such as Nano 33 IoT, nRF52, Teensy, etc.
24. [`Blynk_WiFiNINA_WM library 1.1.2+`](https://github.com/khoih-prog/Blynk_WiFiNINA_WM) to use with Blynk-WiFiNINA-related example. To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/Blynk_WiFiNINA_WM.svg?)](https://www.ardu-badge.com/Blynk_WiFiNINA_WM)
25. To use with certain examples
@@ -323,9 +329,9 @@ You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/
Another way to install is to:
1. Navigate to [**TimerInterrupt_Generic**](https://github.com/khoih-prog/TimerInterrupt_Generic) page.
-2. Download the latest release `TimerInterrupt_Generic-master.zip`.
-3. Extract the zip file to `TimerInterrupt_Generic-master` directory
-4. Copy whole `TimerInterrupt_Generic-master` folder to Arduino libraries' directory such as `~/Arduino/libraries/`.
+2. Download the latest release `TimerInterrupt_Generic-main.zip`.
+3. Extract the zip file to `TimerInterrupt_Generic-main` directory
+4. Copy whole `TimerInterrupt_Generic-main` folder to Arduino libraries' directory such as `~/Arduino/libraries/`.
### VS Code & PlatformIO
@@ -442,16 +448,16 @@ Whenever the above-mentioned compiler error issue is fixed with the new Arduino
#### 5. For Adafruit SAMD boards
- ***To be able to compile, run and automatically detect and display BOARD_NAME on Adafruit SAMD (Itsy-Bitsy M4, etc) boards***, you have to copy the whole [Adafruit SAMD Packages_Patches](Packages_Patches/adafruit/hardware/samd/1.7.10) directory into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.10).
+ ***To be able to compile, run and automatically detect and display BOARD_NAME on Adafruit SAMD (Itsy-Bitsy M4, etc) boards***, you have to copy the whole [Adafruit SAMD Packages_Patches](Packages_Patches/adafruit/hardware/samd/1.7.11) directory into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.11).
-Supposing the Adafruit SAMD core version is 1.7.10. This file must be copied into the directory:
+Supposing the Adafruit SAMD core version is 1.7.11. These files must be copied into the directory:
-- `~/.arduino15/packages/adafruit/hardware/samd/1.7.10/platform.txt`
-- `~/.arduino15/packages/adafruit/hardware/samd/1.7.10/cores/arduino/Print.h`
-- `~/.arduino15/packages/adafruit/hardware/samd/1.7.10/cores/arduino/Print.cpp`
+- `~/.arduino15/packages/adafruit/hardware/samd/1.7.11/platform.txt`
+- `~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.h`
+- `~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.cpp`
Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz
-This file must be copied into the directory:
+These files must be copied into the directory:
- `~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/platform.txt`
- `~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.h`
@@ -459,17 +465,17 @@ This file must be copied into the directory:
#### 6. For Seeeduino SAMD boards
- ***To be able to compile, run and automatically detect and display BOARD_NAME on Seeeduino SAMD (XIAO M0, Wio Terminal, etc) boards***, you have to copy the whole [Seeeduino SAMD Packages_Patches](Packages_Patches/Seeeduino/hardware/samd/1.8.2) directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.2).
+ ***To be able to compile, run and automatically detect and display BOARD_NAME on Seeeduino SAMD (XIAO M0, Wio Terminal, etc) boards***, you have to copy the whole [Seeeduino SAMD Packages_Patches](Packages_Patches/Seeeduino/hardware/samd/1.8.3) directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3).
-Supposing the Seeeduino SAMD core version is 1.8.2. This file must be copied into the directory:
+Supposing the Seeeduino SAMD core version is 1.8.3. These files must be copied into the directory:
-- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.2/platform.txt`
-- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.2/cores/arduino/Arduino.h`
-- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.2/cores/arduino/Print.h`
-- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.2/cores/arduino/Print.cpp`
+- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/platform.txt`
+- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Arduino.h`
+- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.h`
+- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.cpp`
Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz
-This file must be copied into the directory:
+These files must be copied into the directory:
- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/platform.txt`
- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Arduino.h`
@@ -550,12 +556,12 @@ With core after v1.5.0, this step is not necessary anymore thanks to the PR [Add
#### 9. For Portenta_H7 boards using Arduino IDE in Linux
- **To be able to upload firmware to Portenta_H7 using Arduino IDE in Linux (Ubuntu, etc.)**, you have to copy the file [portenta_post_install.sh](Packages_Patches/arduino/hardware/mbed_portenta/3.3.0/portenta_post_install.sh) into mbed_portenta directory (~/.arduino15/packages/arduino/hardware/mbed_portenta/3.3.0/portenta_post_install.sh).
+ **To be able to upload firmware to Portenta_H7 using Arduino IDE in Linux (Ubuntu, etc.)**, you have to copy the file [portenta_post_install.sh](Packages_Patches/arduino/hardware/mbed_portenta/3.4.1/portenta_post_install.sh) into mbed_portenta directory (~/.arduino15/packages/arduino/hardware/mbed_portenta/3.4.1/portenta_post_install.sh).
Then run the following command using `sudo`
```
-$ cd ~/.arduino15/packages/arduino/hardware/mbed_portenta/3.3.0
+$ cd ~/.arduino15/packages/arduino/hardware/mbed_portenta/3.4.1
$ chmod 755 portenta_post_install.sh
$ sudo ./portenta_post_install.sh
```
@@ -568,9 +574,9 @@ This will create the file `/etc/udev/rules.d/49-portenta_h7.rules` as follows:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="035b", GROUP="plugdev", MODE="0666"
```
-Supposing the ArduinoCore-mbed core version is 3.3.0. Now only one file must be copied into the directory:
+Supposing the ArduinoCore-mbed core version is 3.4.1. Now only one file must be copied into the directory:
-- `~/.arduino15/packages/arduino/hardware/mbed_portenta/3.3.0/portenta_post_install.sh`
+- `~/.arduino15/packages/arduino/hardware/mbed_portenta/3.4.1/portenta_post_install.sh`
Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz
@@ -595,11 +601,11 @@ This file must be copied into the directory:
#### 11. For SAMD21 and SAMD51 boards using ArduinoCore-fab-sam core
- To avoid compile error relating to SAMD21/SAMD51, you have to copy the file [ArduinoCore-fab-sam core pgmspace.h](Packages_Patches/Fab_SAM_Arduino/hardware/samd/1.7.0/boards.txt) into `ArduinoCore-fab-sam` samd directory (~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.7.0/boards.txt).
+ To avoid compile error relating to SAMD21/SAMD51, you have to copy the file [ArduinoCore-fab-sam core pgmspace.h](Packages_Patches/Fab_SAM_Arduino/hardware/samd/1.9.0/boards.txt) into `ArduinoCore-fab-sam` samd directory (~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.9.0/boards.txt).
-Supposing the `ArduinoCore-fab-sam` samd core version is 1.7.0. This file must be copied into the directory:
+Supposing the `ArduinoCore-fab-sam` samd core version is 1.9.0. This file must be copied into the directory:
-- `~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.7.0/boards.txt`
+- `~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.9.0/boards.txt`
Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz
This file must be copied into the directory:
@@ -611,18 +617,41 @@ This file must be copied into the directory:
***To be able to compile, run and automatically detect and display BOARD_NAME on Seeeduino RP2040 (XIAO RP2040, Wio RP2040 Mini) boards***, you have to copy the whole [Seeeduino RP2040 Packages_Patches](Packages_Patches/Seeeduino/hardware/rp2040/2.7.2) directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2).
-Supposing the Seeeduino SAMD core version is 2.7.2. This file must be copied into the directory:
+Supposing the Seeeduino RP2040 core version is 2.7.2. These files must be copied into the directory:
- `~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2/boards.txt`
- `~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2/variants/Seeed_XIAO_RP2040/pins_arduino.h`
Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz
-This file must be copied into the directory:
+These files must be copied into the directory:
- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/boards.txt`
- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/variants/Seeed_XIAO_RP2040/pins_arduino.h`
+---
+
+#### 13. For Seeeduino nRF52840 boards
+
+**To be able to compile and run on Xiao nRF52840 boards**, you have to copy the whole [nRF52 1.0.0](Packages_Patches/Seeeduino/hardware/nrf52/1.0.0) directory into Seeeduino nRF52 directory (~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0).
+
+Supposing the Seeeduino nRF52 version is 1.0.0. These files must be copied into the directory:
+
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/platform.txt`**
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/cores/nRF5/Print.h`**
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/cores/nRF5/Print.cpp`**
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/cores/nRF5/Udp.h`**
+
+Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z
+These files must be copied into the directory:
+
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/platform.txt`**
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/cores/nRF5/Print.h`**
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/cores/nRF5/Print.cpp`**
+- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/cores/nRF5/Udp.h`**
+
+
+
---
---
@@ -736,22 +765,22 @@ Please have a look at [**ESP_WiFiManager Issue 39: Not able to read analog port
#### 2. ESP32 ADCs functions
-- ADC1 controls ADC function for pins **GPIO32-GPIO39**
-- ADC2 controls ADC function for pins **GPIO0, 2, 4, 12-15, 25-27**
+- `ADC1` controls ADC function for pins **GPIO32-GPIO39**
+- `ADC2` controls ADC function for pins **GPIO0, 2, 4, 12-15, 25-27**
#### 3.. ESP32 WiFi uses ADC2 for WiFi functions
-Look in file [**adc_common.c**](https://github.com/espressif/esp-idf/blob/main/components/driver/adc_common.c#L61)
+Look in file [**adc_common.c**](https://github.com/espressif/esp-idf/blob/master/components/driver/adc_common.c)
-> In ADC2, there're two locks used for different cases:
+> In `ADC2`, there're two locks used for different cases:
> 1. lock shared with app and Wi-Fi:
> ESP32:
-> When Wi-Fi using the ADC2, we assume it will never stop, so app checks the lock and returns immediately if failed.
+> When Wi-Fi using the `ADC2`, we assume it will never stop, so app checks the lock and returns immediately if failed.
> ESP32S2:
> The controller's control over the ADC is determined by the arbiter. There is no need to control by lock.
>
> 2. lock shared between tasks:
-> when several tasks sharing the ADC2, we want to guarantee
+> when several tasks sharing the `ADC2`, we want to guarantee
> all the requests will be handled.
> Since conversions are short (about 31us), app returns the lock very soon,
> we use a spinlock to stand there waiting to do conversions one by one.
@@ -759,10 +788,10 @@ Look in file [**adc_common.c**](https://github.com/espressif/esp-idf/blob/main/c
> adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.
-- In order to use ADC2 for other functions, we have to **acquire complicated firmware locks and very difficult to do**
-- So, it's not advisable to use ADC2 with WiFi/BlueTooth (BT/BLE).
-- Use ADC1, and pins GPIO32-GPIO39
-- If somehow it's a must to use those pins serviced by ADC2 (**GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27**), use the **fix mentioned at the end** of [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to work with ESP32 WiFi/BlueTooth (BT/BLE).
+- In order to use `ADC2` for other functions, we have to **acquire complicated firmware locks and very difficult to do**
+- So, it's not advisable to use `ADC2` with WiFi/BlueTooth (BT/BLE).
+- Use `ADC1`, and pins `GPIO32-GPIO39`
+- If somehow it's a must to use those pins serviced by `ADC2` (**GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27**), use the **fix mentioned at the end** of [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to work with ESP32 WiFi/BlueTooth (BT/BLE).
---
@@ -793,17 +822,12 @@ Please have a look at [ESP8266TimerInterrupt Issue 8: **ESP8266Timer and PWM -->
### 1. For ESP32
-The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1 (for ESP32 core v2.0.0+)
-
- 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
- 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
-
-All the timers are based on 64 bits counters and 16 bit prescalers.
-
-The timer counters can be configured to count up or down and support automatic reload and software reload.
-
-They can also generate alarms when they reach a specific value, defined by the software. The value of the counter can be read by
-the software program.
+ - **The ESP32, ESP32_S2 and ESP32_S3 has two timer groups, each one with two general purpose hardware timers.**
+ - **The ESP32_C3 has two timer groups, each one with only one general purpose hardware timer.**
+ - All the timers are based on **64-bit counters (except 54-bit counter for ESP32_S3 counter) and 16-bit prescalers.**
+ - The timer counters can be configured to count up or down and support automatic reload and software reload.
+ - They can also generate alarms when they reach a specific value, defined by the software.
+ - The value of the counter can be read by the software program.
---
@@ -867,7 +891,7 @@ For example, **STM32F103C8T6** has one advance timer, while **STM32F103VET6** ha
-
+
@@ -2105,7 +2129,7 @@ While software timer, **programmed for 2s, is activated after 10.917s !!!**. The
```
Starting ISR_Timer_Complex_Ethernet on SAM DUE
SAMDUETimerInterrupt v1.3.0
-TimerInterrupt_Generic v1.12.0
+TimerInterrupt_Generic v1.13.0
Using Timer(0) = TC0, channel = 0, IRQ = TC0_IRQn
Timer(0), us = 50000.00
ITimer attached to Timer(0)
@@ -2197,8 +2221,8 @@ While software timer, **programmed for 2s, is activated after 4.867s !!!**. Then
```
Starting ISR_Timer_Complex_Ethernet on NRF52840_FEATHER
-NRF52TimerInterrupt v1.4.1
-TimerInterrupt_Generic v1.12.0
+NRF52TimerInterrupt v1.4.2
+TimerInterrupt_Generic v1.13.0
NRF52TimerInterrupt: F_CPU (MHz) = 64, Timer = NRF_TIMER2
NRF52TimerInterrupt: _fre = 1000000.00, _count = 50000
Starting ITimer OK, millis() = 1419
@@ -2291,7 +2315,7 @@ In this example, 16 independent ISR Timers are used, yet utilized just one Hardw
```
Starting ISR_16_Timers_Array_Complex on SAMD_NANO_33_IOT
SAMDTimerInterrupt v1.10.1
-TimerInterrupt_Generic v1.12.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 48 MHz
Starting ITimer OK, millis() = 1180
SimpleTimer : 2, ms : 11180, Dms : 10000
@@ -2443,7 +2467,7 @@ The following is the sample terminal output when running example [**TimerInterru
```
Starting TimerInterruptTest on Teensy 4.0
Teensy_TimerInterrupt v1.3.0
-TimerInterrupt_Generic v1.12.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 600 MHz
TEENSY_TIMER_1, F_BUS_ACTUAL (MHz) = 150, request interval = 30000, actual interval (us) = 29999
Prescale = 7, _timerCount = 17578
@@ -2487,8 +2511,8 @@ The following is the sample terminal output when running example [ISR_16_Timers_
```
Starting ISR_16_Timers_Array_Complex on ESP32_DEV
-ESP32_New_TimerInterrupt v1.4.0
-TimerInterrupt_Generic v1.12.0
+ESP32_New_TimerInterrupt v1.5.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 240 MHz
Starting ITimer OK, millis() = 2045
SimpleTimer : 2, ms : 12044, Dms : 9999
@@ -2640,7 +2664,7 @@ The following is the sample terminal output when running example [ISR_16_Timers_
```
Starting ISR_16_Timers_Array_Complex on ESP8266_NODEMCU_ESP12E
ESP8266TimerInterrupt v1.6.0
-TimerInterrupt_Generic v1.12.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 160 MHz
Starting ITimer OK, millis() = 177
SimpleTimer : 2, ms : 10179, Dms : 10000
@@ -2790,7 +2814,7 @@ The following is the sample terminal output when running example [ISR_16_Timers_
```
Starting ISR_16_Timers_Array_Complex on NUCLEO_F767ZI
STM32_TimerInterrupt v1.3.0
-TimerInterrupt_Generic v1.12.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 216 MHz
Starting ITimer OK, millis() = 105
SimpleTimer : 2, ms : 10110, Dms : 10005
@@ -2941,7 +2965,7 @@ The following is the sample terminal output when running example [**TimerInterru
```
Starting TimerInterruptTest on NUCLEO_F767ZI
STM32_TimerInterrupt v1.3.0
-TimerInterrupt_Generic v1.12.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 216 MHz
STM32TimerInterrupt: Timer Input Freq (Hz) = 216000000, _fre = 1000000.00, _count = 1000000
Starting ITimer0 OK, millis() = 108
@@ -2997,8 +3021,8 @@ While software timer, **programmed for 2s, is activated after more than 3.000s i
```
Starting ISR_16_Timers_Array_Complex on Nano 33 BLE
-NRF52_MBED_TimerInterrupt v1.4.0
-TimerInterrupt_Generic v1.12.0
+NRF52_MBED_TimerInterrupt v1.4.1
+TimerInterrupt_Generic v1.13.0
Starting ITimer OK, millis() = 810
SimpleTimer : 2, ms : 3810, Dms : 3000
Timer : 0, programmed : 5000, actual : 0
@@ -3474,8 +3498,8 @@ SimpleTimer : 2, ms : 85118, Dms : 3011
```
Starting ISR_16_Timers_Array_Complex on megaAVR Nano Every
-megaAVR_TimerInterrupt v1.6.1
-TimerInterrupt_Generic v1.12.0
+megaAVR_TimerInterrupt v1.7.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 16 MHz
TCB Clock Frequency = 16MHz for highest accuracy
[TISR] TCB 1
@@ -3586,8 +3610,8 @@ SimpleTimer : 2, ms : 90506, Dms : 10064
```
Starting ISR_16_Timers_Array_Complex on megaAVR Nano Every
-megaAVR_TimerInterrupt v1.6.1
-TimerInterrupt_Generic v1.12.0
+megaAVR_TimerInterrupt v1.7.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 16 MHz
TCB Clock Frequency = 8MHz for very high accuracy
Starting ITimer1 OK, millis() = 10
@@ -3655,8 +3679,8 @@ Timer : 15, programmed : 80000, actual : 80000
```
Starting ISR_16_Timers_Array_Complex on megaAVR Nano Every
-megaAVR_TimerInterrupt v1.6.1
-TimerInterrupt_Generic v1.12.0
+megaAVR_TimerInterrupt v1.7.0
+TimerInterrupt_Generic v1.13.0
CPU Frequency = 16 MHz
TCB Clock Frequency = 250KHz for lower accuracy but longer time
Starting ITimer1 OK, millis() = 11
@@ -3780,17 +3804,17 @@ Submit issues to: [TimerInterrupt_Generic issues](https://github.com/khoih-prog/
1. Basic hardware timers for
- [x] AVR. Sync with `v1.8.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/TimerInterrupt.svg)](https://github.com/khoih-prog/TimerInterrupt/releases/latest)
-- [x] megaAVR. Sync with `v1.6.1`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/megaAVR_TimerInterrupt.svg)](https://github.com/khoih-prog/megaAVR_TimerInterrupt/releases/latest)
+- [x] megaAVR. Sync with `v1.7.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/megaAVR_TimerInterrupt.svg)](https://github.com/khoih-prog/megaAVR_TimerInterrupt/releases/latest)
- [x] ESP8266. Sync with `v1.6.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP8266TimerInterrupt.svg)](https://github.com/khoih-prog/ESP8266TimerInterrupt/releases/latest)
-- [x] ESP32. Sync with `v1.4.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP32_New_TimerInterrupt.svg)](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/releases/latest)
+- [x] ESP32. Sync with `v1.5.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP32_New_TimerInterrupt.svg)](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/releases/latest)
- [x] SAMD. Sync with `v1.10.1`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/SAMD_TimerInterrupt.svg)](https://github.com/khoih-prog/SAMD_TimerInterrupt/releases/latest)
- [x] SAM DUE. Sync with `v1.3.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/SAMDUE_TimerInterrupt.svg)](https://github.com/khoih-prog/SAMDUE_TimerInterrupt/releases/latest)
-- [x] nRF52. Sync with `v1.4.1`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/NRF52_TimerInterrupt.svg)](https://github.com/khoih-prog/NRF52_TimerInterrupt/releases/latest)
+- [x] nRF52. Sync with `v1.4.2`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/NRF52_TimerInterrupt.svg)](https://github.com/khoih-prog/NRF52_TimerInterrupt/releases/latest)
- [x] Teensy. Sync with `v1.3.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/Teensy_TimerInterrupt.svg)](https://github.com/khoih-prog/Teensy_TimerInterrupt/releases/latest)
-- [x] Mbed-OS nRF52 Nano-33-BLE. Sync with `v1.4.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/NRF52_MBED_TimerInterrupt.svg)](https://github.com/khoih-prog/NRF52_MBED_TimerInterrupt/releases/latest)
+- [x] Mbed-OS nRF52 Nano-33-BLE. Sync with `v1.4.1`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/NRF52_MBED_TimerInterrupt.svg)](https://github.com/khoih-prog/NRF52_MBED_TimerInterrupt/releases/latest)
- [x] STM32F/L/H/G/WB/MP1. Sync with `v1.3.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/STM32_TimerInterrupt.svg)](https://github.com/khoih-prog/STM32_TimerInterrupt/releases/latest)
- [x] Raspberry Pi pico. Sync with `v1.3.1`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/RPI_PICO_TimerInterrupt.svg)](https://github.com/khoih-prog/RPI_PICO_TimerInterrupt/releases/latest)
-- [x] MBED Raspberry Pi pico. Sync with `v1.1.2`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/MBED_RPI_PICO_TimerInterrupt.svg)](https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt/releases/latest)
+- [x] MBED Raspberry Pi pico. Sync with `v1.2.0`. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/MBED_RPI_PICO_TimerInterrupt.svg)](https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt/releases/latest)
- [ ] Portenta H7. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/Portenta_H7_TimerInterrupt.svg)](https://github.com/khoih-prog/Portenta_H7_TimerInterrupt/releases/latest)
- [ ] RTL8720DN. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/RTL8720_TimerInterrupt.svg)](https://github.com/khoih-prog/RTL8720_TimerInterrupt/releases/latest)
- [ ] AVR_Dx. Latest [![GitHub release](https://img.shields.io/github/release/khoih-prog/Dx_TimerInterrupt.svg)](https://github.com/khoih-prog/Dx_TimerInterrupt/releases/latest)
@@ -3815,7 +3839,7 @@ Submit issues to: [TimerInterrupt_Generic issues](https://github.com/khoih-prog/
14. Optimize library code by using `reference-passing` instead of `value-passing`
15. Using `float` instead of `ulong` for better interval accuracy
16. Drop `src_cpp` and `src_h` directories
-
+17. Use `allman astyle` and add `utils`
---
---
@@ -3868,6 +3892,6 @@ If you want to contribute to this project:
## Copyright
-Copyright 2020- Khoi Hoang
+Copyright (C) 2020- Khoi Hoang
diff --git a/changelog.md b/changelog.md
index b979ab6e..82521ba1 100644
--- a/changelog.md
+++ b/changelog.md
@@ -6,12 +6,20 @@
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing)
[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/TimerInterrupt_Generic.svg)](http://github.com/khoih-prog/TimerInterrupt_Generic/issues)
+
+
+
+
+
+
+
---
---
## Table of Contents
* [Changelog](#changelog)
+ * [Major Releases v1.13.0](#major-releases-v1130)
* [Major Releases v1.12.0](#major-releases-v1120)
* [Major Releases v1.11.0](#major-releases-v1110)
* [Major Releases v1.10.0](#major-releases-v1100)
@@ -33,6 +41,18 @@
## Changelog
+### Major Releases v1.13.0
+
+1. Update to use latest versions of the following libraries
+- [ESP32_New_TimerInterrupt](https://github.com/khoih-prog/ESP32_New_TimerInterrupt)
+- [MBED_RPI_PICO_TimerInterrupt](https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt)
+- [megaAVR_TimerInterrupt](https://github.com/khoih-prog/megaAVR_TimerInterrupt)
+- [NRF52_TimerInterrupt](https://github.com/khoih-prog/NRF52_TimerInterrupt)
+- [NRF52_MBED_TimerInterrupt](https://github.com/khoih-prog/NRF52_MBED_TimerInterrupt)
+2. Modify ESP32 examples to avoid using `LED_BUILTIN` / `GPIO2` as it can cause crash in some boards, such as `ESP32_C3`
+3. Use `allman astyle` and add `utils`
+4. Update `Packages_Patches`
+
### Major Releases v1.12.0
1. Update to use latest versions of the following libraries
diff --git a/library.json b/library.json
index 0657965a..5369b31a 100644
--- a/library.json
+++ b/library.json
@@ -1,6 +1,6 @@
{
"name": "TimerInterrupt_Generic",
- "version": "1.12.0",
+ "version": "1.13.0",
"keywords": "timing, device, control, timer, interrupt, hardware, isr, hardware-timer, mbed, rp2040, esp8266, esp32, samd, nrf52, teensy, stm32, nano-33-ble, nano-rp2040-connect, mega, sam-due, isr-based, 32u4, non-blocking, mission-critical, accuracy, precise",
"description": "This library enables you to use Interrupt from Hardware Timers on supported boards such as AVR, Mega-AVR, ESP8266, ESP32, ESP32-S2, SAMD, SAM DUE, nRF52, STM32F/L/H/G/WB/MP1, Teensy, Nano-33-BLE, RP2040-based boards, etc. These hardware timers, using interrupt, still work even if other functions are blocking. It now supports 16 ISR-based timers, while consuming only 1 Hardware Timer. Timers' interval is very long (ulong millisecs). The most important feature is they're ISR-based timers. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's necessary if you need to measure some data requiring better accuracy",
"authors":
diff --git a/library.properties b/library.properties
index 393d411e..3bcf027e 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=TimerInterrupt_Generic
-version=1.12.0
+version=1.13.0
author=Khoi Hoang
maintainer=Khoi Hoang
license=MIT
diff --git a/src/AVRTimerInterrupt_Generic.h b/src/AVRTimerInterrupt_Generic.h
index 328da882..3e82de33 100644
--- a/src/AVRTimerInterrupt_Generic.h
+++ b/src/AVRTimerInterrupt_Generic.h
@@ -8,7 +8,7 @@
OCRx - Output Compare Register
ICRx - Input Capture Register (only for 16bit timer)
TIMSKx - Timer/Counter Interrupt Mask Register. To enable/disable timer interrupts.
- TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt.
+ TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt.
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one Hardware timer and avoid conflicting with other cores' tasks.
@@ -26,7 +26,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -44,6 +44,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
@@ -58,7 +60,7 @@
#ifndef TIMER_INTERRUPT_VERSION
#define TIMER_INTERRUPT_VERSION "TimerInterrupt v1.8.0"
-
+
#define TIMER_INTERRUPT_VERSION_MAJOR 1
#define TIMER_INTERRUPT_VERSION_MINOR 8
#define TIMER_INTERRUPT_VERSION_PATCH 0
@@ -92,7 +94,7 @@
typedef void (*timer_callback)();
typedef void (*timer_callback_p)(void *);
-enum
+enum
{
HW_TIMER_0 = 0,
HW_TIMER_1,
@@ -103,7 +105,7 @@ enum
NUM_HW_TIMERS
};
-enum
+enum
{
NO_CLOCK_SOURCE = 0,
NO_PRESCALER,
@@ -114,7 +116,7 @@ enum
NUM_ITEMS
};
-enum
+enum
{
T2_NO_CLOCK_SOURCE = 0,
T2_NO_PRESCALER,
@@ -123,7 +125,7 @@ enum
T2_PRESCALER_64,
T2_PRESCALER_128,
T2_PRESCALER_256,
- T2_PRESCALER_1024,
+ T2_PRESCALER_1024,
T2_NUM_ITEMS
};
@@ -143,10 +145,10 @@ class TimerInterrupt
double _frequency;
void* _callback; // pointer to the callback function
- void* _params; // function parameter
-
+ void* _params; // function parameter
+
///////////////////////////////////////////
-
+
void set_OCR()
{
// Run with noInterrupt()
@@ -162,19 +164,20 @@ class TimerInterrupt
OCR1A = _OCRValueToUse;
_OCRValueRemaining -= _OCRValueToUse;
- #if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
+#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
// Bit 1 – OCIEA: Output Compare A Match Interrupt Enable
// When this bit is written to '1', and the I-flag in the Status Register is set (interrupts globally enabled), the
// Timer/Counter Output Compare A Match interrupt is enabled. The corresponding Interrupt Vector is
// executed when the OCFA Flag, located in TIFR1, is set.
bitWrite(TIMSK1, OCIE1A, 1);
- #elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
+#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
// this combination is for at least the ATmega32
bitWrite(TIMSK, OCIE1A, 1);
- #endif
+#endif
break;
- #if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
+#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
+
case 2:
_OCRValueToUse = min(MAX_COUNT_8BIT, _OCRValueRemaining);
OCR2A = _OCRValueToUse;
@@ -182,9 +185,10 @@ class TimerInterrupt
bitWrite(TIMSK2, OCIE2A, 1);
break;
- #endif
+#endif
+
+#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
- #if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
case 3:
_OCRValueToUse = min(MAX_COUNT_16BIT, _OCRValueRemaining);
OCR3A = _OCRValueToUse;
@@ -192,25 +196,27 @@ class TimerInterrupt
bitWrite(TIMSK3, OCIE3A, 1);
break;
- #endif
+#endif
+
+#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
- #if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
case 4:
-
- #if TIMER_INTERRUPT_USING_ATMEGA_32U4
+
+#if TIMER_INTERRUPT_USING_ATMEGA_32U4
_OCRValueToUse = min(MAX_COUNT_8BIT, _OCRValueRemaining);
- #else
+#else
_OCRValueToUse = min(MAX_COUNT_16BIT, _OCRValueRemaining);
- #endif
-
+#endif
+
OCR4A = _OCRValueToUse;
_OCRValueRemaining -= _OCRValueToUse;
bitWrite(TIMSK4, OCIE4A, 1);
break;
- #endif
+#endif
+
+#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
- #if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
case 5:
_OCRValueToUse = min(MAX_COUNT_16BIT, _OCRValueRemaining);
OCR5A = _OCRValueToUse;
@@ -218,7 +224,7 @@ class TimerInterrupt
bitWrite(TIMSK5, OCIE5A, 1);
break;
- #endif
+#endif
}
// Flag _OCRValue == 0 => end of long timer
@@ -226,12 +232,12 @@ class TimerInterrupt
_timerDone = true;
}
-
+
///////////////////////////////////////////
-
+
public:
- TimerInterrupt()
+ TimerInterrupt()
{
_timer = -1;
_frequency = 0;
@@ -256,750 +262,790 @@ class TimerInterrupt
_OCRValueRemaining = 0;
_toggle_count = -1;
};
-
- void callback() __attribute__((always_inline))
- {
- if (_callback != NULL)
+
+ void callback() __attribute__((always_inline))
{
- if (_params != NULL)
+ if (_callback != NULL)
+ {
+ if (_params != NULL)
(*(timer_callback_p)_callback)(_params);
- else
+ else
(*(timer_callback)_callback)();
+ }
}
- }
-
- void init(int8_t timer)
- {
- // Set timer specific stuff
- // All timers in CTC mode
- // 8 bit timers will require changing prescalar values,
- // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
-
- //cli();//stop interrupts
- noInterrupts();
-
- switch (timer)
- {
- #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
- case 1:
- // 16 bit timer
- TCCR1A = 0;
- TCCR1B = 0;
- // Page 172-173. ATmega 328/328P or Page 145-146 of ATmega 640/1280/2560
- // Mode 4 => Clear Timer on Compare match (CTC) using OCR1A for counter value
- bitWrite(TCCR1B, WGM12, 1);
- // No scaling now
- bitWrite(TCCR1B, CS10, 1);
-
- TISR_LOGWARN(F("T1"));
-
- break;
- #endif
-
- #if defined(TCCR2A) && defined(TCCR2B)
- case 2:
- // 8 bit timer
- TCCR2A = 0;
- TCCR2B = 0;
- // Page 205-206. ATmegal328, Page 184-185 ATmega 640/1280/2560
- // Mode 2 => Clear Timer on Compare match (CTC) using OCR2A for counter value
- bitWrite(TCCR2A, WGM21, 1);
- // No scaling now
- bitWrite(TCCR2B, CS20, 1);
-
- TISR_LOGWARN(F("T2"));
-
- break;
- #endif
-
- #if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
- case 3:
- // 16 bit timer
- TCCR3A = 0;
- TCCR3B = 0;
- bitWrite(TCCR3B, WGM32, 1);
- bitWrite(TCCR3B, CS30, 1);
-
- TISR_LOGWARN(F("T3"));
-
- break;
- #endif
-
- #if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
- case 4:
- // 16 bit timer
- TCCR4A = 0;
- TCCR4B = 0;
- #if defined(WGM42)
+
+ void init(int8_t timer)
+ {
+ // Set timer specific stuff
+ // All timers in CTC mode
+ // 8 bit timers will require changing prescalar values,
+ // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
+
+ //cli();//stop interrupts
+ noInterrupts();
+
+ switch (timer)
+ {
+#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
+
+ case 1:
+ // 16 bit timer
+ TCCR1A = 0;
+ TCCR1B = 0;
+ // Page 172-173. ATmega 328/328P or Page 145-146 of ATmega 640/1280/2560
+ // Mode 4 => Clear Timer on Compare match (CTC) using OCR1A for counter value
+ bitWrite(TCCR1B, WGM12, 1);
+ // No scaling now
+ bitWrite(TCCR1B, CS10, 1);
+
+ TISR_LOGWARN(F("T1"));
+
+ break;
+#endif
+
+#if defined(TCCR2A) && defined(TCCR2B)
+
+ case 2:
+ // 8 bit timer
+ TCCR2A = 0;
+ TCCR2B = 0;
+ // Page 205-206. ATmegal328, Page 184-185 ATmega 640/1280/2560
+ // Mode 2 => Clear Timer on Compare match (CTC) using OCR2A for counter value
+ bitWrite(TCCR2A, WGM21, 1);
+ // No scaling now
+ bitWrite(TCCR2B, CS20, 1);
+
+ TISR_LOGWARN(F("T2"));
+
+ break;
+#endif
+
+#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
+
+ case 3:
+ // 16 bit timer
+ TCCR3A = 0;
+ TCCR3B = 0;
+ bitWrite(TCCR3B, WGM32, 1);
+ bitWrite(TCCR3B, CS30, 1);
+
+ TISR_LOGWARN(F("T3"));
+
+ break;
+#endif
+
+#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
+
+ case 4:
+ // 16 bit timer
+ TCCR4A = 0;
+ TCCR4B = 0;
+#if defined(WGM42)
bitWrite(TCCR4B, WGM42, 1);
- #elif defined(CS43)
+#elif defined(CS43)
// TODO this may not be correct
// atmega32u4
bitWrite(TCCR4B, CS43, 1);
- #endif
- bitWrite(TCCR4B, CS40, 1);
-
- TISR_LOGWARN(F("T4"));
-
- break;
- #endif
-
- #if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
- case 5:
- // 16 bit timer
- TCCR5A = 0;
- TCCR5B = 0;
- bitWrite(TCCR5B, WGM52, 1);
- bitWrite(TCCR5B, CS50, 1);
-
- TISR_LOGWARN(F("T5"));
-
- break;
- #endif
- }
+#endif
+ bitWrite(TCCR4B, CS40, 1);
- _timer = timer;
+ TISR_LOGWARN(F("T4"));
- //sei();//enable interrupts
- interrupts();
-
- }
+ break;
+#endif
- ///////////////////////////////////////////
-
- // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- // bool setFrequency(float frequency, timer_callback_p callback, /* void* */ uint32_t params, unsigned long duration = 0);
+#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
- // frequency (in hertz) and duration (in milliseconds).
- // Return true if frequency is OK with selected timer (OCRValue is in range)
- bool setFrequency(float frequency, timer_callback_p callback, uint32_t params, unsigned long duration = 0)
- {
- uint8_t andMask = 0b11111000;
- unsigned long OCRValue;
- bool isSuccess = false;
+ case 5:
+ // 16 bit timer
+ TCCR5A = 0;
+ TCCR5B = 0;
+ bitWrite(TCCR5B, WGM52, 1);
+ bitWrite(TCCR5B, CS50, 1);
- //frequencyLimit must > 1
- float frequencyLimit = frequency * 17179.840;
+ TISR_LOGWARN(F("T5"));
+
+ break;
+#endif
+ }
+
+ _timer = timer;
+
+ //sei();//enable interrupts
+ interrupts();
- // Limit frequency to larger than (0.00372529 / 64) Hz or interval 17179.840s / 17179840 ms to avoid uint32_t overflow
- if ((_timer <= 0) || (callback == NULL) || ((frequencyLimit) < 1) )
- {
- return false;
}
- else
- {
- // Calculate the toggle count. Duration must be at least longer then one cycle
- if (duration > 0)
- {
- _toggle_count = frequency * duration / 1000;
- TISR_LOGWARN1(F("setFrequency => _toggle_count ="), _toggle_count);
- TISR_LOGWARN3(F("Frequency ="), frequency, F(", duration ="), duration);
-
- if (_toggle_count < 1)
- {
- return false;
- }
+ ///////////////////////////////////////////
+
+ // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ // bool setFrequency(float frequency, timer_callback_p callback, /* void* */ uint32_t params, unsigned long duration = 0);
+
+ // frequency (in hertz) and duration (in milliseconds).
+ // Return true if frequency is OK with selected timer (OCRValue is in range)
+ bool setFrequency(float frequency, timer_callback_p callback, uint32_t params, unsigned long duration = 0)
+ {
+ uint8_t andMask = 0b11111000;
+ unsigned long OCRValue;
+ bool isSuccess = false;
+
+ //frequencyLimit must > 1
+ float frequencyLimit = frequency * 17179.840;
+
+ // Limit frequency to larger than (0.00372529 / 64) Hz or interval 17179.840s / 17179840 ms to avoid uint32_t overflow
+ if ((_timer <= 0) || (callback == NULL) || ((frequencyLimit) < 1) )
+ {
+ return false;
}
else
{
- _toggle_count = -1;
- }
-
- //Timer0 and timer2 are 8 bit timers, meaning they can store a maximum counter value of 255.
- //Timer2 does not have the option of 1024 prescaler, only 1, 8, 32, 64
- //Timer1 is a 16 bit timer, meaning it can store a maximum counter value of 65535.
- int prescalerIndexStart;
-
- //Use smallest prescaler first, then increase until fits (<255)
- if (_timer != 2)
- {
- if (frequencyLimit > 64)
- prescalerIndexStart = NO_PRESCALER;
- else if (frequencyLimit > 8)
- prescalerIndexStart = PRESCALER_8;
+ // Calculate the toggle count. Duration must be at least longer then one cycle
+ if (duration > 0)
+ {
+ _toggle_count = frequency * duration / 1000;
+
+ TISR_LOGWARN1(F("setFrequency => _toggle_count ="), _toggle_count);
+ TISR_LOGWARN3(F("Frequency ="), frequency, F(", duration ="), duration);
+
+ if (_toggle_count < 1)
+ {
+ return false;
+ }
+ }
else
- prescalerIndexStart = PRESCALER_64;
+ {
+ _toggle_count = -1;
+ }
+
+ //Timer0 and timer2 are 8 bit timers, meaning they can store a maximum counter value of 255.
+ //Timer2 does not have the option of 1024 prescaler, only 1, 8, 32, 64
+ //Timer1 is a 16 bit timer, meaning it can store a maximum counter value of 65535.
+ int prescalerIndexStart;
-
- for (int prescalerIndex = prescalerIndexStart; prescalerIndex <= PRESCALER_1024; prescalerIndex++)
+ //Use smallest prescaler first, then increase until fits (<255)
+ if (_timer != 2)
{
- OCRValue = F_CPU / (frequency * prescalerDiv[prescalerIndex]) - 1;
-
- TISR_LOGWARN1(F("Freq * 1000 ="), frequency * 1000);
- TISR_LOGWARN3(F("F_CPU ="), F_CPU, F(", preScalerDiv ="), prescalerDiv[prescalerIndex]);
- TISR_LOGWARN3(F("OCR ="), OCRValue, F(", preScalerIndex ="), prescalerIndex);
-
- // We use very large _OCRValue now, and every time timer ISR activates, we deduct min(MAX_COUNT_16BIT, _OCRValueRemaining) from _OCRValueRemaining
- // So that we can create very long timer, even if the counter is only 16-bit.
- // Use very high frequency (OCRValue / MAX_COUNT_16BIT) around 16 * 1024 to achieve higher accuracy
- #if TIMER_INTERRUPT_USING_ATMEGA_32U4
- uint16_t MAX_COUNT_32U4 = (_timer == 4) ? MAX_COUNT_8BIT : MAX_COUNT_16BIT;
-
- if ( (OCRValue / MAX_COUNT_32U4) < 16384 )
- #else
- if ( (OCRValue / MAX_COUNT_16BIT) < 16384 )
- #endif
+ if (frequencyLimit > 64)
+ prescalerIndexStart = NO_PRESCALER;
+ else if (frequencyLimit > 8)
+ prescalerIndexStart = PRESCALER_8;
+ else
+ prescalerIndexStart = PRESCALER_64;
+
+
+ for (int prescalerIndex = prescalerIndexStart; prescalerIndex <= PRESCALER_1024; prescalerIndex++)
+ {
+ OCRValue = F_CPU / (frequency * prescalerDiv[prescalerIndex]) - 1;
+
+ TISR_LOGWARN1(F("Freq * 1000 ="), frequency * 1000);
+ TISR_LOGWARN3(F("F_CPU ="), F_CPU, F(", preScalerDiv ="), prescalerDiv[prescalerIndex]);
+ TISR_LOGWARN3(F("OCR ="), OCRValue, F(", preScalerIndex ="), prescalerIndex);
+
+ // We use very large _OCRValue now, and every time timer ISR activates, we deduct min(MAX_COUNT_16BIT, _OCRValueRemaining) from _OCRValueRemaining
+ // So that we can create very long timer, even if the counter is only 16-bit.
+ // Use very high frequency (OCRValue / MAX_COUNT_16BIT) around 16 * 1024 to achieve higher accuracy
+#if TIMER_INTERRUPT_USING_ATMEGA_32U4
+ uint16_t MAX_COUNT_32U4 = (_timer == 4) ? MAX_COUNT_8BIT : MAX_COUNT_16BIT;
+
+ if ( (OCRValue / MAX_COUNT_32U4) < 16384 )
+#else
+ if ( (OCRValue / MAX_COUNT_16BIT) < 16384 )
+#endif
+ {
+ _OCRValue = OCRValue;
+ _OCRValueRemaining = OCRValue;
+ _prescalerIndex = prescalerIndex;
+
+ TISR_LOGWARN1(F("OK in loop => _OCR ="), _OCRValue);
+ TISR_LOGWARN3(F("_preScalerIndex ="), _prescalerIndex, F(", preScalerDiv ="), prescalerDiv[_prescalerIndex]);
+
+ isSuccess = true;
+
+ break;
+ }
+ }
+
+ if (!isSuccess)
{
+ // Always do this
_OCRValue = OCRValue;
_OCRValueRemaining = OCRValue;
- _prescalerIndex = prescalerIndex;
-
- TISR_LOGWARN1(F("OK in loop => _OCR ="), _OCRValue);
+ _prescalerIndex = PRESCALER_1024;
+
+ TISR_LOGWARN1(F("OK out loop => _OCR ="), _OCRValue);
TISR_LOGWARN3(F("_preScalerIndex ="), _prescalerIndex, F(", preScalerDiv ="), prescalerDiv[_prescalerIndex]);
-
- isSuccess = true;
-
- break;
- }
+ }
}
-
- if (!isSuccess)
- {
- // Always do this
- _OCRValue = OCRValue;
- _OCRValueRemaining = OCRValue;
- _prescalerIndex = PRESCALER_1024;
-
- TISR_LOGWARN1(F("OK out loop => _OCR ="), _OCRValue);
- TISR_LOGWARN3(F("_preScalerIndex ="), _prescalerIndex, F(", preScalerDiv ="), prescalerDiv[_prescalerIndex]);
- }
- }
- else
- {
- if (frequencyLimit > 64)
- prescalerIndexStart = T2_NO_PRESCALER;
- else if (frequencyLimit > 8)
- prescalerIndexStart = T2_PRESCALER_8;
- else if (frequencyLimit > 2)
- prescalerIndexStart = T2_PRESCALER_32;
else
- prescalerIndexStart = T2_PRESCALER_64;
-
- // Page 206-207. ATmegal328
- //8-bit Timer2 has more options up to 1024 prescaler, from 1, 8, 32, 64, 128, 256 and 1024
- for (int prescalerIndex = prescalerIndexStart; prescalerIndex <= T2_PRESCALER_1024; prescalerIndex++)
{
- OCRValue = F_CPU / (frequency * prescalerDivT2[prescalerIndex]) - 1;
-
- TISR_LOGWARN3(F("F_CPU ="), F_CPU, F(", preScalerDiv ="), prescalerDivT2[prescalerIndex]);
- TISR_LOGWARN3(F("OCR2 ="), OCRValue, F(", preScalerIndex ="), prescalerIndex);
-
- // We use very large _OCRValue now, and every time timer ISR activates, we deduct min(MAX_COUNT_8BIT, _OCRValue) from _OCRValue
- // to create very long timer, even if the counter is only 16-bit.
- // Use very high frequency (OCRValue / MAX_COUNT_8BIT) around 16 * 1024 to achieve higher accuracy
- if ( (OCRValue / MAX_COUNT_8BIT) < 16384 )
+ if (frequencyLimit > 64)
+ prescalerIndexStart = T2_NO_PRESCALER;
+ else if (frequencyLimit > 8)
+ prescalerIndexStart = T2_PRESCALER_8;
+ else if (frequencyLimit > 2)
+ prescalerIndexStart = T2_PRESCALER_32;
+ else
+ prescalerIndexStart = T2_PRESCALER_64;
+
+ // Page 206-207. ATmegal328
+ //8-bit Timer2 has more options up to 1024 prescaler, from 1, 8, 32, 64, 128, 256 and 1024
+ for (int prescalerIndex = prescalerIndexStart; prescalerIndex <= T2_PRESCALER_1024; prescalerIndex++)
+ {
+ OCRValue = F_CPU / (frequency * prescalerDivT2[prescalerIndex]) - 1;
+
+ TISR_LOGWARN3(F("F_CPU ="), F_CPU, F(", preScalerDiv ="), prescalerDivT2[prescalerIndex]);
+ TISR_LOGWARN3(F("OCR2 ="), OCRValue, F(", preScalerIndex ="), prescalerIndex);
+
+ // We use very large _OCRValue now, and every time timer ISR activates, we deduct min(MAX_COUNT_8BIT, _OCRValue) from _OCRValue
+ // to create very long timer, even if the counter is only 16-bit.
+ // Use very high frequency (OCRValue / MAX_COUNT_8BIT) around 16 * 1024 to achieve higher accuracy
+ if ( (OCRValue / MAX_COUNT_8BIT) < 16384 )
+ {
+ _OCRValue = OCRValue;
+ _OCRValueRemaining = OCRValue;
+ // same as prescalarbits
+ _prescalerIndex = prescalerIndex;
+
+ TISR_LOGWARN1(F("OK in loop => _OCR ="), _OCRValue);
+ TISR_LOGWARN3(F("_preScalerIndex ="), _prescalerIndex, F(", preScalerDiv ="), prescalerDivT2[_prescalerIndex]);
+
+ isSuccess = true;
+
+ break;
+ }
+ }
+
+ if (!isSuccess)
{
+ // Always do this
_OCRValue = OCRValue;
_OCRValueRemaining = OCRValue;
// same as prescalarbits
- _prescalerIndex = prescalerIndex;
-
- TISR_LOGWARN1(F("OK in loop => _OCR ="), _OCRValue);
+ _prescalerIndex = T2_PRESCALER_1024;
+
+ TISR_LOGWARN1(F("OK out loop => _OCR ="), _OCRValue);
TISR_LOGWARN3(F("_preScalerIndex ="), _prescalerIndex, F(", preScalerDiv ="), prescalerDivT2[_prescalerIndex]);
-
- isSuccess = true;
-
- break;
- }
+ }
}
- if (!isSuccess)
- {
- // Always do this
- _OCRValue = OCRValue;
- _OCRValueRemaining = OCRValue;
- // same as prescalarbits
- _prescalerIndex = T2_PRESCALER_1024;
-
- TISR_LOGWARN1(F("OK out loop => _OCR ="), _OCRValue);
- TISR_LOGWARN3(F("_preScalerIndex ="), _prescalerIndex, F(", preScalerDiv ="), prescalerDivT2[_prescalerIndex]);
- }
- }
+ //cli();//stop interrupts
+ noInterrupts();
- //cli();//stop interrupts
- noInterrupts();
+ _frequency = frequency;
+ _callback = (void*) callback;
+ _params = reinterpret_cast(params);
- _frequency = frequency;
- _callback = (void*) callback;
- _params = reinterpret_cast(params);
+ _timerDone = false;
- _timerDone = false;
-
- // 8 bit timers from here
- #if defined(TCCR2B)
- if (_timer == 2)
- {
- TCCR2B = (TCCR2B & andMask) | _prescalerIndex; //prescalarbits;
-
- TISR_LOGWARN1(F("TCCR2B ="), TCCR2B);
- }
- #endif
+ // 8 bit timers from here
+#if defined(TCCR2B)
- // 16 bit timers from here
- #if defined(TCCR1B)
- #if ( TIMER_INTERRUPT_USING_ATMEGA_32U4 )
- if (_timer == 1)
- #else
- else if (_timer == 1)
- #endif
- {
- TCCR1B = (TCCR1B & andMask) | _prescalerIndex; //prescalarbits;
-
- TISR_LOGWARN1(F("TCCR1B ="), TCCR1B);
- }
- #endif
-
- #if defined(TCCR3B)
- else if (_timer == 3)
- TCCR3B = (TCCR3B & andMask) | _prescalerIndex; //prescalarbits;
- #endif
-
- #if defined(TCCR4B)
- else if (_timer == 4)
- TCCR4B = (TCCR4B & andMask) | _prescalerIndex; //prescalarbits;
- #endif
-
- #if defined(TCCR5B)
- else if (_timer == 5)
- TCCR5B = (TCCR5B & andMask) | _prescalerIndex; //prescalarbits;
- #endif
-
- // Set the OCR for the given timer,
- // set the toggle count,
- // then turn on the interrupts
- set_OCR();
-
- //sei();//allow interrupts
- interrupts();
+ if (_timer == 2)
+ {
+ TCCR2B = (TCCR2B & andMask) | _prescalerIndex; //prescalarbits;
- return true;
- }
- }
+ TISR_LOGWARN1(F("TCCR2B ="), TCCR2B);
+ }
- ///////////////////////////////////////////
-
-
- void init()
- {
- init(_timer);
- };
-
+#endif
- // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- bool setFrequency(float frequency, timer_callback callback, unsigned long duration = 0)
- {
- return setFrequency(frequency, reinterpret_cast(callback), /*NULL*/ 0, duration);
- }
+ // 16 bit timers from here
+#if defined(TCCR1B)
+#if ( TIMER_INTERRUPT_USING_ATMEGA_32U4 )
- // interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- template
- bool setInterval(unsigned long interval, void (*callback)(TArg), TArg params, unsigned long duration = 0)
- {
- static_assert(sizeof(TArg) <= sizeof(uint32_t), "setInterval() callback argument size must be <= 4 bytes");
- return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), (uint32_t) params, duration);
- }
+ if (_timer == 1)
+#else
+ else if (_timer == 1)
+#endif
+ {
+ TCCR1B = (TCCR1B & andMask) | _prescalerIndex; //prescalarbits;
- // interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- bool setInterval(unsigned long interval, timer_callback callback, unsigned long duration = 0)
- {
- return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), /*NULL*/ 0, duration);
- }
+ TISR_LOGWARN1(F("TCCR1B ="), TCCR1B);
+ }
- template
- bool attachInterrupt(float frequency, void (*callback)(TArg), TArg params, unsigned long duration = 0)
- {
- static_assert(sizeof(TArg) <= sizeof(uint32_t), "attachInterrupt() callback argument size must be <= 4 bytes");
- return setFrequency(frequency, reinterpret_cast(callback), (uint32_t) params, duration);
- }
+#endif
- bool attachInterrupt(float frequency, timer_callback callback, unsigned long duration = 0)
- {
- return setFrequency(frequency, reinterpret_cast(callback), /*NULL*/ 0, duration);
- }
-
- // Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- template
- bool attachInterruptInterval(unsigned long interval, void (*callback)(TArg), TArg params, unsigned long duration = 0)
- {
- static_assert(sizeof(TArg) <= sizeof(uint32_t), "attachInterruptInterval() callback argument size must be <= 4 bytes");
- return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast(callback), (uint32_t) params, duration);
- }
+#if defined(TCCR3B)
+ else if (_timer == 3)
+ TCCR3B = (TCCR3B & andMask) | _prescalerIndex; //prescalarbits;
- // Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- bool attachInterruptInterval(unsigned long interval, timer_callback callback, unsigned long duration = 0)
- {
- return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast (callback), /*NULL*/ 0, duration);
- }
+#endif
-
- ///////////////////////////////////////////
-
- // void detachInterrupt();
-
- void detachInterrupt()
- {
- //cli();//stop interrupts
- noInterrupts();
-
- switch (_timer)
- {
- #if defined(TIMSK1) && defined(OCIE1A)
- case 1:
- bitWrite(TIMSK1, OCIE1A, 0);
-
- TISR_LOGWARN(F("Disable T1"));
-
- break;
- #endif
-
- case 2:
- #if defined(TIMSK2) && defined(OCIE2A)
- bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
- #endif
-
- TISR_LOGWARN(F("Disable T2"));
-
- break;
-
- #if defined(TIMSK3) && defined(OCIE3A)
- case 3:
- bitWrite(TIMSK3, OCIE3A, 0);
-
- TISR_LOGWARN(F("Disable T3"));
-
- break;
- #endif
+#if defined(TCCR4B)
+ else if (_timer == 4)
+ TCCR4B = (TCCR4B & andMask) | _prescalerIndex; //prescalarbits;
- #if defined(TIMSK4) && defined(OCIE4A)
- case 4:
- bitWrite(TIMSK4, OCIE4A, 0);
+#endif
- TISR_LOGWARN(F("Disable T4"));
-
- break;
- #endif
+#if defined(TCCR5B)
+ else if (_timer == 5)
+ TCCR5B = (TCCR5B & andMask) | _prescalerIndex; //prescalarbits;
- #if defined(TIMSK5) && defined(OCIE5A)
- case 5:
- bitWrite(TIMSK5, OCIE5A, 0);
+#endif
- TISR_LOGWARN(F("Disable T5"));
-
- break;
- #endif
- }
-
- //sei();//allow interrupts
- interrupts();
- }
-
- // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- void reattachInterrupt(unsigned long duration = 0)
- {
- //cli();//stop interrupts
- noInterrupts();
+ // Set the OCR for the given timer,
+ // set the toggle count,
+ // then turn on the interrupts
+ set_OCR();
- // Calculate the toggle count
- if (duration > 0)
- {
- _toggle_count = _frequency * duration / 1000;
- }
- else
- {
- _toggle_count = -1;
- }
-
- switch (_timer)
- {
- #if defined(TIMSK1) && defined(OCIE1A)
- case 1:
- bitWrite(TIMSK1, OCIE1A, 1);
+ //sei();//allow interrupts
+ interrupts();
- TISR_LOGWARN(F("Enable T1"));
-
- break;
- #endif
+ return true;
+ }
+ }
- case 2:
- #if defined(TIMSK2) && defined(OCIE2A)
- bitWrite(TIMSK2, OCIE2A, 1); // enable interrupt
- #endif
-
- TISR_LOGWARN(F("Enable T2"));
-
- break;
-
- #if defined(TIMSK3) && defined(OCIE3A)
- case 3:
- bitWrite(TIMSK3, OCIE3A, 1);
-
- TISR_LOGWARN(F("Enable T3"));
-
- break;
- #endif
+ ///////////////////////////////////////////
- #if defined(TIMSK4) && defined(OCIE4A)
- case 4:
- bitWrite(TIMSK4, OCIE4A, 1);
- TISR_LOGWARN(F("Enable T4"));
-
- break;
- #endif
+ void init()
+ {
+ init(_timer);
+ };
- #if defined(TIMSK5) && defined(OCIE5A)
- case 5:
- bitWrite(TIMSK5, OCIE5A, 1);
- TISR_LOGWARN(F("Enable T5"));
-
- break;
- #endif
+ // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ bool setFrequency(float frequency, timer_callback callback, unsigned long duration = 0)
+ {
+ return setFrequency(frequency, reinterpret_cast(callback), /*NULL*/ 0, duration);
}
-
- //sei();//allow interrupts
- interrupts();
- }
-
- ///////////////////////////////////////////
-
- void disableTimer()
- {
- detachInterrupt();
- }
- // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
- void enableTimer(unsigned long duration = 0) __attribute__((always_inline))
- {
- reattachInterrupt(duration);
- }
-
- ///////////////////////////////////////////
-
- // Just stop clock source, still keep the count
- // void pauseTimer();
-
- // Just stop clock source, still keep the count
- void pauseTimer()
- {
- uint8_t andMask = 0b11111000;
-
- //Just clear the CSx2-CSx0. Still keep the count in TCNT and Timer Interrupt mask TIMKSx.
-
- // 8 bit timers from here
- #if defined(TCCR2B)
- if (_timer == 2)
+ // interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ template
+ bool setInterval(unsigned long interval, void (*callback)(TArg), TArg params, unsigned long duration = 0)
{
- TCCR2B = (TCCR2B & andMask);
+ static_assert(sizeof(TArg) <= sizeof(uint32_t), "setInterval() callback argument size must be <= 4 bytes");
+ return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), (uint32_t) params,
+ duration);
+ }
- TISR_LOGWARN1(F("TCCR2B ="), TCCR2B);
+ // interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ bool setInterval(unsigned long interval, timer_callback callback, unsigned long duration = 0)
+ {
+ return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), /*NULL*/ 0, duration);
}
- #endif
-
- // 16 bit timers from here
- #if defined(TCCR1B)
- #if ( TIMER_INTERRUPT_USING_ATMEGA_32U4 )
- if (_timer == 1)
- #else
- else if (_timer == 1)
- #endif
+
+ template
+ bool attachInterrupt(float frequency, void (*callback)(TArg), TArg params, unsigned long duration = 0)
{
- TCCR1B = (TCCR1B & andMask);
-
- TISR_LOGWARN1(F("TCCR1B ="), TCCR1B);
+ static_assert(sizeof(TArg) <= sizeof(uint32_t), "attachInterrupt() callback argument size must be <= 4 bytes");
+ return setFrequency(frequency, reinterpret_cast(callback), (uint32_t) params, duration);
}
- #endif
-
- #if defined(TCCR3B)
- else if (_timer == 3)
- TCCR3B = (TCCR3B & andMask);
- #endif
-
- #if defined(TCCR4B)
- else if (_timer == 4)
- TCCR4B = (TCCR4B & andMask);
- #endif
-
- #if defined(TCCR5B)
- else if (_timer == 5)
- TCCR5B = (TCCR5B & andMask);
- #endif
- }
- // Just reconnect clock source, continue from the current count
- // void resumeTimer();
-
- // Just reconnect clock source, continue from the current count
- void resumeTimer()
- {
- uint8_t andMask = 0b11111000;
-
- //Just restore the CSx2-CSx0 stored in _prescalerIndex. Still keep the count in TCNT and Timer Interrupt mask TIMKSx.
- // 8 bit timers from here
- #if defined(TCCR2B)
- if (_timer == 2)
+ bool attachInterrupt(float frequency, timer_callback callback, unsigned long duration = 0)
{
- TCCR2B = (TCCR2B & andMask) | _prescalerIndex; //prescalarbits;
+ return setFrequency(frequency, reinterpret_cast(callback), /*NULL*/ 0, duration);
+ }
- TISR_LOGWARN1(F("TCCR2B ="), TCCR2B);
+ // Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ template
+ bool attachInterruptInterval(unsigned long interval, void (*callback)(TArg), TArg params, unsigned long duration = 0)
+ {
+ static_assert(sizeof(TArg) <= sizeof(uint32_t), "attachInterruptInterval() callback argument size must be <= 4 bytes");
+ return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast(callback), (uint32_t) params,
+ duration);
}
- #endif
-
- // 16 bit timers from here
- #if defined(TCCR1B)
- #if ( TIMER_INTERRUPT_USING_ATMEGA_32U4 )
- if (_timer == 1)
- #else
- else if (_timer == 1)
- #endif
+
+ // Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ bool attachInterruptInterval(unsigned long interval, timer_callback callback, unsigned long duration = 0)
{
- TCCR1B = (TCCR1B & andMask) | _prescalerIndex; //prescalarbits;
-
- TISR_LOGWARN1(F("TCCR1B ="), TCCR1B);
+ return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast (callback), /*NULL*/ 0,
+ duration);
}
- #endif
-
- #if defined(TCCR3B)
- else if (_timer == 3)
- TCCR3B = (TCCR3B & andMask) | _prescalerIndex; //prescalarbits;
- #endif
-
- #if defined(TCCR4B)
- else if (_timer == 4)
- TCCR4B = (TCCR4B & andMask) | _prescalerIndex; //prescalarbits;
- #endif
-
- #if defined(TCCR5B)
- else if (_timer == 5)
- TCCR5B = (TCCR5B & andMask) | _prescalerIndex; //prescalarbits;
- #endif
- }
-
- ///////////////////////////////////////////
-
- // Just stop clock source, clear the count
- void stopTimer()
- {
- detachInterrupt();
- }
- // Just reconnect clock source, start current count from 0
- void restartTimer(unsigned long duration = 0)
- {
- reattachInterrupt(duration);
- }
+ ///////////////////////////////////////////
- int8_t getTimer() __attribute__((always_inline))
- {
- return _timer;
- };
-
- long getCount() __attribute__((always_inline))
- {
- return _toggle_count;
- };
-
- void setCount(long countInput) __attribute__((always_inline))
- {
- //cli();//stop interrupts
- //noInterrupts();
-
- _toggle_count = countInput;
-
- //sei();//enable interrupts
- //interrupts();
- };
-
- long get_OCRValue() __attribute__((always_inline))
- {
- return _OCRValue;
- };
-
- long get_OCRValueRemaining() __attribute__((always_inline))
- {
- return _OCRValueRemaining;
- };
-
- void adjust_OCRValue() //__attribute__((always_inline))
- {
- //cli();//stop interrupts
- noInterrupts();
+ // void detachInterrupt();
- if (_timer != 2)
+ void detachInterrupt()
{
-#if TIMER_INTERRUPT_USING_ATMEGA_32U4
- if (_timer == 4)
- {
- if (_OCRValueRemaining < MAX_COUNT_8BIT)
- {
- set_OCR();
- }
-
- _OCRValueRemaining -= min(MAX_COUNT_8BIT, _OCRValueRemaining);
- }
- else
- {
- if (_OCRValueRemaining < MAX_COUNT_16BIT)
- {
- set_OCR();
- }
-
- _OCRValueRemaining -= min(MAX_COUNT_16BIT, _OCRValueRemaining);
- }
-#else
- if (_OCRValueRemaining < MAX_COUNT_16BIT)
+ //cli();//stop interrupts
+ noInterrupts();
+
+ switch (_timer)
{
- set_OCR();
+#if defined(TIMSK1) && defined(OCIE1A)
+
+ case 1:
+ bitWrite(TIMSK1, OCIE1A, 0);
+
+ TISR_LOGWARN(F("Disable T1"));
+
+ break;
+#endif
+
+ case 2:
+#if defined(TIMSK2) && defined(OCIE2A)
+ bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
+#endif
+
+ TISR_LOGWARN(F("Disable T2"));
+
+ break;
+
+#if defined(TIMSK3) && defined(OCIE3A)
+
+ case 3:
+ bitWrite(TIMSK3, OCIE3A, 0);
+
+ TISR_LOGWARN(F("Disable T3"));
+
+ break;
+#endif
+
+#if defined(TIMSK4) && defined(OCIE4A)
+
+ case 4:
+ bitWrite(TIMSK4, OCIE4A, 0);
+
+ TISR_LOGWARN(F("Disable T4"));
+
+ break;
+#endif
+
+#if defined(TIMSK5) && defined(OCIE5A)
+
+ case 5:
+ bitWrite(TIMSK5, OCIE5A, 0);
+
+ TISR_LOGWARN(F("Disable T5"));
+
+ break;
+#endif
}
-
- _OCRValueRemaining -= min(MAX_COUNT_16BIT, _OCRValueRemaining);
-#endif
+
+ //sei();//allow interrupts
+ interrupts();
}
- else
+
+ // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ void reattachInterrupt(unsigned long duration = 0)
{
- if (_OCRValueRemaining < MAX_COUNT_8BIT)
+ //cli();//stop interrupts
+ noInterrupts();
+
+ // Calculate the toggle count
+ if (duration > 0)
{
- set_OCR();
+ _toggle_count = _frequency * duration / 1000;
+ }
+ else
+ {
+ _toggle_count = -1;
}
-
- _OCRValueRemaining -= min(MAX_COUNT_8BIT, _OCRValueRemaining);
+
+ switch (_timer)
+ {
+#if defined(TIMSK1) && defined(OCIE1A)
+
+ case 1:
+ bitWrite(TIMSK1, OCIE1A, 1);
+
+ TISR_LOGWARN(F("Enable T1"));
+
+ break;
+#endif
+
+ case 2:
+#if defined(TIMSK2) && defined(OCIE2A)
+ bitWrite(TIMSK2, OCIE2A, 1); // enable interrupt
+#endif
+
+ TISR_LOGWARN(F("Enable T2"));
+
+ break;
+
+#if defined(TIMSK3) && defined(OCIE3A)
+
+ case 3:
+ bitWrite(TIMSK3, OCIE3A, 1);
+
+ TISR_LOGWARN(F("Enable T3"));
+
+ break;
+#endif
+
+#if defined(TIMSK4) && defined(OCIE4A)
+
+ case 4:
+ bitWrite(TIMSK4, OCIE4A, 1);
+
+ TISR_LOGWARN(F("Enable T4"));
+
+ break;
+#endif
+
+#if defined(TIMSK5) && defined(OCIE5A)
+
+ case 5:
+ bitWrite(TIMSK5, OCIE5A, 1);
+
+ TISR_LOGWARN(F("Enable T5"));
+
+ break;
+#endif
+ }
+
+ //sei();//allow interrupts
+ interrupts();
}
- if (_OCRValueRemaining <= 0)
+ ///////////////////////////////////////////
+
+ void disableTimer()
{
- // Reset value for next cycle
- _OCRValueRemaining = _OCRValue;
- _timerDone = true;
+ detachInterrupt();
}
- else
- _timerDone = false;
- //sei();//enable interrupts
- interrupts();
- };
+ // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
+ void enableTimer(unsigned long duration = 0) __attribute__((always_inline))
+ {
+ reattachInterrupt(duration);
+ }
- void reload_OCRValue() //__attribute__((always_inline))
- {
- //cli();//stop interrupts
- noInterrupts();
+ ///////////////////////////////////////////
+
+ // Just stop clock source, still keep the count
+ // void pauseTimer();
- // Reset value for next cycle, have to deduct the value already loaded to OCR register
-
- _OCRValueRemaining = _OCRValue;
- set_OCR();
+ // Just stop clock source, still keep the count
+ void pauseTimer()
+ {
+ uint8_t andMask = 0b11111000;
- _timerDone = false;
+ //Just clear the CSx2-CSx0. Still keep the count in TCNT and Timer Interrupt mask TIMKSx.
- //sei();//enable interrupts
- interrupts();
- };
-
- bool checkTimerDone() //__attribute__((always_inline))
- {
- return _timerDone;
- };
+ // 8 bit timers from here
+#if defined(TCCR2B)
+
+ if (_timer == 2)
+ {
+ TCCR2B = (TCCR2B & andMask);
+
+ TISR_LOGWARN1(F("TCCR2B ="), TCCR2B);
+ }
+
+#endif
+
+ // 16 bit timers from here
+#if defined(TCCR1B)
+#if ( TIMER_INTERRUPT_USING_ATMEGA_32U4 )
+
+ if (_timer == 1)
+#else
+ else if (_timer == 1)
+#endif
+ {
+ TCCR1B = (TCCR1B & andMask);
+
+ TISR_LOGWARN1(F("TCCR1B ="), TCCR1B);
+ }
+
+#endif
+
+#if defined(TCCR3B)
+ else if (_timer == 3)
+ TCCR3B = (TCCR3B & andMask);
+
+#endif
+
+#if defined(TCCR4B)
+ else if (_timer == 4)
+ TCCR4B = (TCCR4B & andMask);
+
+#endif
+
+#if defined(TCCR5B)
+ else if (_timer == 5)
+ TCCR5B = (TCCR5B & andMask);
+
+#endif
+ }
+
+ // Just reconnect clock source, continue from the current count
+ // void resumeTimer();
+
+ // Just reconnect clock source, continue from the current count
+ void resumeTimer()
+ {
+ uint8_t andMask = 0b11111000;
+
+ //Just restore the CSx2-CSx0 stored in _prescalerIndex. Still keep the count in TCNT and Timer Interrupt mask TIMKSx.
+ // 8 bit timers from here
+#if defined(TCCR2B)
+
+ if (_timer == 2)
+ {
+ TCCR2B = (TCCR2B & andMask) | _prescalerIndex; //prescalarbits;
+
+ TISR_LOGWARN1(F("TCCR2B ="), TCCR2B);
+ }
+
+#endif
+
+ // 16 bit timers from here
+#if defined(TCCR1B)
+#if ( TIMER_INTERRUPT_USING_ATMEGA_32U4 )
+
+ if (_timer == 1)
+#else
+ else if (_timer == 1)
+#endif
+ {
+ TCCR1B = (TCCR1B & andMask) | _prescalerIndex; //prescalarbits;
+
+ TISR_LOGWARN1(F("TCCR1B ="), TCCR1B);
+ }
+
+#endif
+
+#if defined(TCCR3B)
+ else if (_timer == 3)
+ TCCR3B = (TCCR3B & andMask) | _prescalerIndex; //prescalarbits;
+
+#endif
+
+#if defined(TCCR4B)
+ else if (_timer == 4)
+ TCCR4B = (TCCR4B & andMask) | _prescalerIndex; //prescalarbits;
+
+#endif
+
+#if defined(TCCR5B)
+ else if (_timer == 5)
+ TCCR5B = (TCCR5B & andMask) | _prescalerIndex; //prescalarbits;
+
+#endif
+ }
+
+ ///////////////////////////////////////////
+
+
+ // Just stop clock source, clear the count
+ void stopTimer()
+ {
+ detachInterrupt();
+ }
+
+ // Just reconnect clock source, start current count from 0
+ void restartTimer(unsigned long duration = 0)
+ {
+ reattachInterrupt(duration);
+ }
+
+ int8_t getTimer() __attribute__((always_inline))
+ {
+ return _timer;
+ };
+
+ long getCount() __attribute__((always_inline))
+ {
+ return _toggle_count;
+ };
+
+ void setCount(long countInput) __attribute__((always_inline))
+ {
+ //cli();//stop interrupts
+ //noInterrupts();
+
+ _toggle_count = countInput;
+
+ //sei();//enable interrupts
+ //interrupts();
+ };
+
+ long get_OCRValue() __attribute__((always_inline))
+ {
+ return _OCRValue;
+ };
+
+ long get_OCRValueRemaining() __attribute__((always_inline))
+ {
+ return _OCRValueRemaining;
+ };
+
+ void adjust_OCRValue() //__attribute__((always_inline))
+ {
+ //cli();//stop interrupts
+ noInterrupts();
+
+ if (_timer != 2)
+ {
+#if TIMER_INTERRUPT_USING_ATMEGA_32U4
+
+ if (_timer == 4)
+ {
+ if (_OCRValueRemaining < MAX_COUNT_8BIT)
+ {
+ set_OCR();
+ }
+
+ _OCRValueRemaining -= min(MAX_COUNT_8BIT, _OCRValueRemaining);
+ }
+ else
+ {
+ if (_OCRValueRemaining < MAX_COUNT_16BIT)
+ {
+ set_OCR();
+ }
+
+ _OCRValueRemaining -= min(MAX_COUNT_16BIT, _OCRValueRemaining);
+ }
+
+#else
+
+ if (_OCRValueRemaining < MAX_COUNT_16BIT)
+ {
+ set_OCR();
+ }
+
+ _OCRValueRemaining -= min(MAX_COUNT_16BIT, _OCRValueRemaining);
+#endif
+ }
+ else
+ {
+ if (_OCRValueRemaining < MAX_COUNT_8BIT)
+ {
+ set_OCR();
+ }
+
+ _OCRValueRemaining -= min(MAX_COUNT_8BIT, _OCRValueRemaining);
+ }
+
+ if (_OCRValueRemaining <= 0)
+ {
+ // Reset value for next cycle
+ _OCRValueRemaining = _OCRValue;
+ _timerDone = true;
+ }
+ else
+ _timerDone = false;
+
+ //sei();//enable interrupts
+ interrupts();
+ };
+
+ void reload_OCRValue() //__attribute__((always_inline))
+ {
+ //cli();//stop interrupts
+ noInterrupts();
+
+ // Reset value for next cycle, have to deduct the value already loaded to OCR register
+
+ _OCRValueRemaining = _OCRValue;
+ set_OCR();
+
+ _timerDone = false;
+
+ //sei();//enable interrupts
+ interrupts();
+ };
+
+ bool checkTimerDone() //__attribute__((always_inline))
+ {
+ return _timerDone;
+ };
}; // class TimerInterrupt
@@ -1048,267 +1094,267 @@ class TimerInterrupt
//////////////////////////////////////////////
-#if USE_TIMER_1
- #ifndef TIMER1_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER1_INSTANTIATED
- TimerInterrupt ITimer1(HW_TIMER_1);
-
- // Timer0 is used for micros(), millis(), delay(), etc and can't be used
- // Pre-instatiate
+#if USE_TIMER_1
+#ifndef TIMER1_INSTANTIATED
+// To force pre-instatiate only once
+#define TIMER1_INSTANTIATED
+TimerInterrupt ITimer1(HW_TIMER_1);
+
+// Timer0 is used for micros(), millis(), delay(), etc and can't be used
+// Pre-instatiate
+
+ISR(TIMER1_COMPA_vect)
+{
+ long countLocal = ITimer1.getCount();
- ISR(TIMER1_COMPA_vect)
+ if (ITimer1.getTimer() == 1)
+ {
+ if (countLocal != 0)
{
- long countLocal = ITimer1.getCount();
-
- if (ITimer1.getTimer() == 1)
+ if (ITimer1.checkTimerDone())
{
- if (countLocal != 0)
- {
- if (ITimer1.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T1 callback, _OCRValueRemaining ="), ITimer1.get_OCRValueRemaining(), (", millis ="), millis());
-
- ITimer1.callback();
-
- // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT if _OCRValueRemaining > MAX_COUNT_16BIT
- if (ITimer1.get_OCRValue() > MAX_COUNT_16BIT)
- {
- ITimer1.reload_OCRValue();
- }
-
- if (countLocal > 0)
- ITimer1.setCount(countLocal - 1);
- }
- else
- {
- //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue)
- // If _OCRValue == 0, flag _timerDone for next cycle
- // If last one (_OCRValueRemaining < MAX_COUNT_16BIT) => load _OCR register _OCRValueRemaining
- ITimer1.adjust_OCRValue();
- }
- }
- else
+ TISR_LOGDEBUG3(("T1 callback, _OCRValueRemaining ="), ITimer1.get_OCRValueRemaining(), (", millis ="), millis());
+
+ ITimer1.callback();
+
+ // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT if _OCRValueRemaining > MAX_COUNT_16BIT
+ if (ITimer1.get_OCRValue() > MAX_COUNT_16BIT)
{
- TISR_LOGWARN(("T1 done"));
-
- ITimer1.detachInterrupt();
+ ITimer1.reload_OCRValue();
}
+
+ if (countLocal > 0)
+ ITimer1.setCount(countLocal - 1);
}
+ else
+ {
+ //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue)
+ // If _OCRValue == 0, flag _timerDone for next cycle
+ // If last one (_OCRValueRemaining < MAX_COUNT_16BIT) => load _OCR register _OCRValueRemaining
+ ITimer1.adjust_OCRValue();
+ }
+ }
+ else
+ {
+ TISR_LOGWARN(("T1 done"));
+
+ ITimer1.detachInterrupt();
}
-
- #endif //#ifndef TIMER1_INSTANTIATED
+ }
+}
+
+#endif //#ifndef TIMER1_INSTANTIATED
#endif //#if USE_TIMER_1
#if USE_TIMER_2
- #ifndef TIMER2_INSTANTIATED
- #define TIMER2_INSTANTIATED
- TimerInterrupt ITimer2(HW_TIMER_2);
-
- ISR(TIMER2_COMPA_vect)
+#ifndef TIMER2_INSTANTIATED
+#define TIMER2_INSTANTIATED
+TimerInterrupt ITimer2(HW_TIMER_2);
+
+ISR(TIMER2_COMPA_vect)
+{
+ long countLocal = ITimer2.getCount();
+
+ if (ITimer2.getTimer() == 2)
+ {
+ if (countLocal != 0)
{
- long countLocal = ITimer2.getCount();
-
- if (ITimer2.getTimer() == 2)
+ if (ITimer2.checkTimerDone())
{
- if (countLocal != 0)
- {
- if (ITimer2.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T2 callback, _OCRValueRemaining ="), ITimer2.get_OCRValueRemaining(), (", millis ="), millis());
-
- ITimer2.callback();
-
- // To reload _OCRValue
- if (ITimer2.get_OCRValue() > MAX_COUNT_8BIT)
- {
- ITimer2.reload_OCRValue();
- }
+ TISR_LOGDEBUG3(("T2 callback, _OCRValueRemaining ="), ITimer2.get_OCRValueRemaining(), (", millis ="), millis());
- if (countLocal > 0)
- ITimer2.setCount(countLocal - 1);
+ ITimer2.callback();
- }
- else
- {
- //Deduct _OCRValue by min(MAX_COUNT_8BIT, _OCRValue)
- // If _OCRValue == 0, flag _timerDone for next cycle
- ITimer2.adjust_OCRValue();
- }
- }
- else
+ // To reload _OCRValue
+ if (ITimer2.get_OCRValue() > MAX_COUNT_8BIT)
{
- TISR_LOGWARN(("T2 done"));
-
- ITimer2.detachInterrupt();
+ ITimer2.reload_OCRValue();
}
+
+ if (countLocal > 0)
+ ITimer2.setCount(countLocal - 1);
+
+ }
+ else
+ {
+ //Deduct _OCRValue by min(MAX_COUNT_8BIT, _OCRValue)
+ // If _OCRValue == 0, flag _timerDone for next cycle
+ ITimer2.adjust_OCRValue();
}
- }
- #endif //#ifndef TIMER2_INSTANTIATED
+ }
+ else
+ {
+ TISR_LOGWARN(("T2 done"));
+
+ ITimer2.detachInterrupt();
+ }
+ }
+}
+#endif //#ifndef TIMER2_INSTANTIATED
#endif //#if USE_TIMER_2
#if (TIMER_INTERRUPT_USING_ATMEGA2560 || TIMER_INTERRUPT_USING_ATMEGA_32U4)
- // Pre-instatiate
- #if USE_TIMER_3
- #ifndef TIMER3_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER3_INSTANTIATED
- TimerInterrupt ITimer3(HW_TIMER_3);
-
- ISR(TIMER3_COMPA_vect)
+// Pre-instatiate
+#if USE_TIMER_3
+#ifndef TIMER3_INSTANTIATED
+// To force pre-instatiate only once
+#define TIMER3_INSTANTIATED
+TimerInterrupt ITimer3(HW_TIMER_3);
+
+ISR(TIMER3_COMPA_vect)
+{
+ long countLocal = ITimer3.getCount();
+
+ if (ITimer3.getTimer() == 3)
+ {
+ if (countLocal != 0)
+ {
+ if (ITimer3.checkTimerDone())
{
- long countLocal = ITimer3.getCount();
-
- if (ITimer3.getTimer() == 3)
+ TISR_LOGDEBUG3(("T3 callback, _OCRValueRemaining ="), ITimer3.get_OCRValueRemaining(), (", millis ="), millis());
+
+ ITimer3.callback();
+
+ // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT
+ if (ITimer3.get_OCRValue() > MAX_COUNT_16BIT)
{
- if (countLocal != 0)
- {
- if (ITimer3.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T3 callback, _OCRValueRemaining ="), ITimer3.get_OCRValueRemaining(), (", millis ="), millis());
-
- ITimer3.callback();
-
- // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT
- if (ITimer3.get_OCRValue() > MAX_COUNT_16BIT)
- {
- ITimer3.reload_OCRValue();
- }
-
- if (countLocal > 0)
- ITimer3.setCount(countLocal - 1);
- }
- else
- {
- //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue)
- // If _OCRValue == 0, flag _timerDone for next cycle
- // If last one (_OCRValueRemaining < MAX_COUNT_16BIT) => load _OCR register _OCRValueRemaining
- ITimer3.adjust_OCRValue();
- }
- }
- else
- {
- TISR_LOGWARN(("T3 done"));
-
- ITimer3.detachInterrupt();
- }
+ ITimer3.reload_OCRValue();
}
- }
-
- #endif //#ifndef TIMER3_INSTANTIATED
- #endif //#if USE_TIMER_3
+
+ if (countLocal > 0)
+ ITimer3.setCount(countLocal - 1);
+ }
+ else
+ {
+ //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue)
+ // If _OCRValue == 0, flag _timerDone for next cycle
+ // If last one (_OCRValueRemaining < MAX_COUNT_16BIT) => load _OCR register _OCRValueRemaining
+ ITimer3.adjust_OCRValue();
+ }
+ }
+ else
+ {
+ TISR_LOGWARN(("T3 done"));
+
+ ITimer3.detachInterrupt();
+ }
+ }
+}
+
+#endif //#ifndef TIMER3_INSTANTIATED
+#endif //#if USE_TIMER_3
#endif //#if (TIMER_INTERRUPT_USING_ATMEGA2560 || TIMER_INTERRUPT_USING_ATMEGA_32U4)
#if (TIMER_INTERRUPT_USING_ATMEGA2560 || TIMER_INTERRUPT_USING_ATMEGA_32U4)
- // Even 32u4 Timer4 has 10-bit counter, we use only 8-bit to simplify by not using 2-bit High Byte Register (TC4H)
- // Check 15.2.2 Accuracy, page 141 of ATmega16U4/32U4 [DATASHEET]
+// Even 32u4 Timer4 has 10-bit counter, we use only 8-bit to simplify by not using 2-bit High Byte Register (TC4H)
+// Check 15.2.2 Accuracy, page 141 of ATmega16U4/32U4 [DATASHEET]
- #if USE_TIMER_4
- #ifndef TIMER4_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER4_INSTANTIATED
- TimerInterrupt ITimer4(HW_TIMER_4);
-
- ISR(TIMER4_COMPA_vect)
+#if USE_TIMER_4
+#ifndef TIMER4_INSTANTIATED
+// To force pre-instatiate only once
+#define TIMER4_INSTANTIATED
+TimerInterrupt ITimer4(HW_TIMER_4);
+
+ISR(TIMER4_COMPA_vect)
+{
+ long countLocal = ITimer4.getCount();
+
+ if (ITimer4.getTimer() == 4)
+ {
+ if (countLocal != 0)
+ {
+ if (ITimer4.checkTimerDone())
{
- long countLocal = ITimer4.getCount();
-
- if (ITimer4.getTimer() == 4)
+ TISR_LOGDEBUG3(("T4 callback, _OCRValueRemaining ="), ITimer4.get_OCRValueRemaining(), (", millis ="), millis());
+
+ ITimer4.callback();
+
+ // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT (Mega2560) or MAX_COUNT_8BIT (32u4)
+ if (ITimer4.get_OCRValue() > MAX_COUNT_16BIT)
{
- if (countLocal != 0)
- {
- if (ITimer4.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T4 callback, _OCRValueRemaining ="), ITimer4.get_OCRValueRemaining(), (", millis ="), millis());
-
- ITimer4.callback();
-
- // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT (Mega2560) or MAX_COUNT_8BIT (32u4)
- if (ITimer4.get_OCRValue() > MAX_COUNT_16BIT)
- {
- ITimer4.reload_OCRValue();
- }
-
- if (countLocal > 0)
- ITimer4.setCount(countLocal - 1);
- }
- else
- {
- //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue) or min(MAX_COUNT_8BIT, _OCRValue)
- // If _OCRValue == 0, flag _timerDone for next cycle
- // If last one (_OCRValueRemaining < MAX_COUNT_16BIT / MAX_COUNT_8BIT) => load _OCR register _OCRValueRemaining
- ITimer4.adjust_OCRValue();
- }
- }
- else
- {
- TISR_LOGWARN(("T4 done"));
-
- ITimer4.detachInterrupt();
- }
+ ITimer4.reload_OCRValue();
}
+
+ if (countLocal > 0)
+ ITimer4.setCount(countLocal - 1);
+ }
+ else
+ {
+ //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue) or min(MAX_COUNT_8BIT, _OCRValue)
+ // If _OCRValue == 0, flag _timerDone for next cycle
+ // If last one (_OCRValueRemaining < MAX_COUNT_16BIT / MAX_COUNT_8BIT) => load _OCR register _OCRValueRemaining
+ ITimer4.adjust_OCRValue();
}
-
-
- #endif //#ifndef TIMER4_INSTANTIATED
- #endif //#if USE_TIMER_4
+ }
+ else
+ {
+ TISR_LOGWARN(("T4 done"));
+
+ ITimer4.detachInterrupt();
+ }
+ }
+}
+
+
+#endif //#ifndef TIMER4_INSTANTIATED
+#endif //#if USE_TIMER_4
#endif //#if (TIMER_INTERRUPT_USING_ATMEGA2560 || TIMER_INTERRUPT_USING_ATMEGA_32U4)
#if TIMER_INTERRUPT_USING_ATMEGA2560
-
- #if USE_TIMER_5
- #ifndef TIMER5_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER5_INSTANTIATED
- TimerInterrupt ITimer5(HW_TIMER_5);
-
- ISR(TIMER5_COMPA_vect)
+
+#if USE_TIMER_5
+#ifndef TIMER5_INSTANTIATED
+// To force pre-instatiate only once
+#define TIMER5_INSTANTIATED
+TimerInterrupt ITimer5(HW_TIMER_5);
+
+ISR(TIMER5_COMPA_vect)
+{
+ long countLocal = ITimer5.getCount();
+
+ if (ITimer5.getTimer() == 5)
+ {
+ if (countLocal != 0)
+ {
+ if (ITimer5.checkTimerDone())
{
- long countLocal = ITimer5.getCount();
-
- if (ITimer5.getTimer() == 5)
+ TISR_LOGDEBUG3(("T5 callback, _OCRValueRemaining ="), ITimer5.get_OCRValueRemaining(), (", millis ="), millis());
+
+ ITimer5.callback();
+
+ // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT
+ if (ITimer5.get_OCRValue() > MAX_COUNT_16BIT)
{
- if (countLocal != 0)
- {
- if (ITimer5.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T5 callback, _OCRValueRemaining ="), ITimer5.get_OCRValueRemaining(), (", millis ="), millis());
-
- ITimer5.callback();
-
- // To reload _OCRValueRemaining as well as _OCR register to MAX_COUNT_16BIT
- if (ITimer5.get_OCRValue() > MAX_COUNT_16BIT)
- {
- ITimer5.reload_OCRValue();
- }
-
- if (countLocal > 0)
- ITimer5.setCount(countLocal - 1);
- }
- else
- {
- //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue)
- // If _OCRValue == 0, flag _timerDone for next cycle
- // If last one (_OCRValueRemaining < MAX_COUNT_16BIT) => load _OCR register _OCRValueRemaining
- ITimer5.adjust_OCRValue();
- }
- }
- else
- {
- TISR_LOGWARN(("T5 done"));
-
- ITimer5.detachInterrupt();
- }
+ ITimer5.reload_OCRValue();
}
+
+ if (countLocal > 0)
+ ITimer5.setCount(countLocal - 1);
+ }
+ else
+ {
+ //Deduct _OCRValue by min(MAX_COUNT_16BIT, _OCRValue)
+ // If _OCRValue == 0, flag _timerDone for next cycle
+ // If last one (_OCRValueRemaining < MAX_COUNT_16BIT) => load _OCR register _OCRValueRemaining
+ ITimer5.adjust_OCRValue();
}
-
- #endif //#ifndef TIMER5_INSTANTIATED
- #endif //#if USE_TIMER_5
-
+ }
+ else
+ {
+ TISR_LOGWARN(("T5 done"));
+
+ ITimer5.detachInterrupt();
+ }
+ }
+}
+
+#endif //#ifndef TIMER5_INSTANTIATED
+#endif //#if USE_TIMER_5
+
#endif //#if TIMER_INTERRUPT_USING_ATMEGA2560
#endif //#ifndef TimerInterrupt_h
diff --git a/src/ESP32TimerInterrupt_Generic.h b/src/ESP32TimerInterrupt_Generic.h
index d0878eaa..353940be 100644
--- a/src/ESP32TimerInterrupt_Generic.h
+++ b/src/ESP32TimerInterrupt_Generic.h
@@ -10,9 +10,9 @@
The ESP32, ESP32_S2, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
1) each group of ESP32, ESP32_S2 has two general purpose hardware timers, TIMER_0 and TIMER_1
2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
-
- All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
- and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
+
+ All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
+ and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
the software. The value of the counter can be read by the software program.
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
@@ -28,7 +28,7 @@
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -46,6 +46,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -53,148 +55,169 @@
#ifndef ESP32_NEW_TIMERINTERRUPT_H
#define ESP32_NEW_TIMERINTERRUPT_H
+////////////////////////////////////////
#if ( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \
ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \
ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM || ARDUINO_ADAFRUIT_QTPY_ESP32S2 || ARDUINO_ESP32S2_USB || \
ARDUINO_FEATHERS2NEO || ARDUINO_TINYS2 || ARDUINO_RMP || ARDUINO_LOLIN_S2_MINI || ARDUINO_LOLIN_S2_PICO || \
ARDUINO_ADAFRUIT_FEATHER_ESP32S2 || ARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT || ARDUINO_atmegazero_esp32s2 || \
ARDUINO_DYM || ARDUINO_FRANZININHO_WIFI || ARDUINO_FRANZININHO_WIFI_MSC )
- #define USING_ESP32_S2_NEW_TIMERINTERRUPT true
-
- #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
- #warning USING_ESP32_S2_NEW_TIMERINTERRUPT
- #endif
+#define USING_ESP32_S2_NEW_TIMERINTERRUPT true
+
+#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
+ #warning USING_ESP32_S2_NEW_TIMERINTERRUPT
+#endif
+
+////////////////////////////////////////
+
#elif ( defined(ARDUINO_ESP32S3_DEV) || defined(ARDUINO_ESP32_S3_BOX) || defined(ARDUINO_TINYS3) || \
defined(ARDUINO_PROS3) || defined(ARDUINO_FEATHERS3) || defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_NOPSRAM) || \
defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM) || defined(ARDUINO_ESP32S3_CAM_LCD) || \
defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3) || defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_TFT) || \
defined(ARDUINO_ESP32_S3_USB_OTG) )
- #define USING_ESP32_S3_NEW_TIMERINTERRUPT true
-
- #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
- #warning USING_ESP32_S3_NEW_TIMERINTERRUPT
- #endif
+#define USING_ESP32_S3_NEW_TIMERINTERRUPT true
+
+#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
+ #warning USING_ESP32_S3_NEW_TIMERINTERRUPT
+#endif
+
+////////////////////////////////////////
+
#elif ( defined(ARDUINO_ESP32C3_DEV) || defined(ARDUINO_LOLIN_C3_MINI) || defined(ARDUINO_ADAFRUIT_QTPY_ESP32C3) || \
defined(ARDUINO_AirM2M_CORE_ESP32C3) || defined(ARDUINO_XIAO_ESP32C3) )
- #define USING_ESP32_C3_NEW_TIMERINTERRUPT true
-
- #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
- #warning USING_ESP32_C3_NEW_TIMERINTERRUPT
- #endif
+#define USING_ESP32_C3_NEW_TIMERINTERRUPT true
+
+#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
+ #warning USING_ESP32_C3_NEW_TIMERINTERRUPT
+#endif
+
+////////////////////////////////////////
+
#elif defined(ESP32)
- #define USING_ESP32_NEW_TIMERINTERRUPT true
-
- #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
- #warning USING_ESP32_NEW_TIMERINTERRUPT
- #endif
+#define USING_ESP32_NEW_TIMERINTERRUPT true
+
+#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
+ #warning USING_ESP32_NEW_TIMERINTERRUPT
+#endif
+
+////////////////////////////////////////
+
#else
- #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
+#error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
#endif
+////////////////////////////////////////
+
#ifndef ESP32_TIMER_INTERRUPT_VERSION
- #define ESP32_TIMER_INTERRUPT_VERSION "ESP32_New_TimerInterrupt v1.4.0"
-
+ #define ESP32_TIMER_INTERRUPT_VERSION "ESP32_New_TimerInterrupt v1.5.0"
+
#define ESP32_TIMER_INTERRUPT_VERSION_MAJOR 1
- #define ESP32_TIMER_INTERRUPT_VERSION_MINOR 4
+ #define ESP32_TIMER_INTERRUPT_VERSION_MINOR 5
#define ESP32_TIMER_INTERRUPT_VERSION_PATCH 0
- #define ESP32_TIMER_INTERRUPT_VERSION_INT 1004000
+ #define ESP32_TIMER_INTERRUPT_VERSION_INT 1005000
#endif
+////////////////////////////////////////
+
#ifndef TIMER_INTERRUPT_DEBUG
#define TIMER_INTERRUPT_DEBUG 0
#endif
+////////////////////////////////////////
+
#include "TimerInterrupt_Generic_Debug.h"
#include
+////////////////////////////////////////
+
/*
//ESP32 core v1.0.6, hw_timer_t defined in esp32/tools/sdk/include/driver/driver/timer.h:
- #define TIMER_BASE_CLK (APB_CLK_FREQ) //Frequency of the clock on the input of the timer groups
+ #define TIMER_BASE_CLK (APB_CLK_FREQ) //Frequency of the clock on the input of the timer groups
- //@brief Selects a Timer-Group out of 2 available groups
-
-typedef enum
-{
+ //@brief Selects a Timer-Group out of 2 available groups
+
+ typedef enum
+ {
TIMER_GROUP_0 = 0, // Hw timer group 0
TIMER_GROUP_1 = 1, // Hw timer group 1
TIMER_GROUP_MAX,
-} timer_group_t;
+ } timer_group_t;
- //@brief Select a hardware timer from timer groups
-
-typedef enum
-{
+ //@brief Select a hardware timer from timer groups
+
+ typedef enum
+ {
TIMER_0 = 0, // Select timer0 of GROUPx
TIMER_1 = 1, // Select timer1 of GROUPx
TIMER_MAX,
-} timer_idx_t;
+ } timer_idx_t;
- //@brief Decides the direction of counter
-
-typedef enum
-{
+ //@brief Decides the direction of counter
+
+ typedef enum
+ {
TIMER_COUNT_DOWN = 0, //Descending Count from cnt.high|cnt.low
TIMER_COUNT_UP = 1, //Ascending Count from Zero
TIMER_COUNT_MAX
-} timer_count_dir_t;
+ } timer_count_dir_t;
- //@brief Decides whether timer is on or paused
-
-typedef enum
-{
+ //@brief Decides whether timer is on or paused
+
+ typedef enum
+ {
TIMER_PAUSE = 0, //Pause timer counter
TIMER_START = 1, //Start timer counter
-} timer_start_t;
+ } timer_start_t;
- //@brief Decides whether to enable alarm mode
-
-typedef enum
-{
+ //@brief Decides whether to enable alarm mode
+
+ typedef enum
+ {
TIMER_ALARM_DIS = 0, //Disable timer alarm
TIMER_ALARM_EN = 1, //Enable timer alarm
TIMER_ALARM_MAX
-} timer_alarm_t;
+ } timer_alarm_t;
- //@brief Select interrupt type if running in alarm mode.
-
-typedef enum
-{
+ //@brief Select interrupt type if running in alarm mode.
+
+ typedef enum
+ {
TIMER_INTR_LEVEL = 0, //Interrupt mode: level mode
//TIMER_INTR_EDGE = 1, //Interrupt mode: edge mode, Not supported Now
TIMER_INTR_MAX
-} timer_intr_mode_t;
+ } timer_intr_mode_t;
- //@brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
-
-typedef enum
-{
+ //@brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
+
+ typedef enum
+ {
TIMER_AUTORELOAD_DIS = 0, //Disable auto-reload: hardware will not load counter value after an alarm event
TIMER_AUTORELOAD_EN = 1, //Enable auto-reload: hardware will load counter value after an alarm event
TIMER_AUTORELOAD_MAX,
-} timer_autoreload_t;
+ } timer_autoreload_t;
- //@brief Data structure with timer's configuration settings
-
-typedef struct
-{
- bool alarm_en; //Timer alarm enable
- bool counter_en; //Counter enable
- timer_intr_mode_t intr_type; //Interrupt mode
- timer_count_dir_t counter_dir; //Counter direction
- bool auto_reload; //Timer auto-reload
- uint32_t divider; //Counter clock divider. The divider's range is from from 2 to 65536.
-} timer_config_t;
+ //@brief Data structure with timer's configuration settings
+
+ typedef struct
+ {
+ bool alarm_en; //Timer alarm enable
+ bool counter_en; //Counter enable
+ timer_intr_mode_t intr_type; //Interrupt mode
+ timer_count_dir_t counter_dir; //Counter direction
+ bool auto_reload; //Timer auto-reload
+ uint32_t divider; //Counter clock divider. The divider's range is from from 2 to 65536.
+ } timer_config_t;
*/
@@ -220,20 +243,27 @@ typedef struct
*/
+////////////////////////////////////////
+
class ESP32TimerInterrupt;
typedef ESP32TimerInterrupt ESP32Timer;
+////////////////////////////////////////
+
#if USING_ESP32_C3_NEW_TIMERINTERRUPT
#define MAX_ESP32_NUM_TIMERS 2
#else
#define MAX_ESP32_NUM_TIMERS 4
#endif
+////////////////////////////////////////
+
#define TIMER_DIVIDER 80 // Hardware timer clock divider
// TIMER_BASE_CLK = APB_CLK_FREQ = Frequency of the clock on the input of the timer groups
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
+////////////////////////////////////////
// In esp32/1.0.6/tools/sdk/esp32s2/include/driver/include/driver/timer.h
// typedef bool (*timer_isr_t)(void *);
@@ -243,13 +273,15 @@ typedef ESP32TimerInterrupt ESP32Timer;
//esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
//esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
-
+////////////////////////////////////////
typedef bool (*esp32_timer_callback) (void *);
// For ESP32_C3, TIMER_MAX == 1
// For ESP32 and ESP32_S2, TIMER_MAX == 2
+////////////////////////////////////////
+
typedef struct
{
timer_idx_t timer_idx;
@@ -258,11 +290,18 @@ typedef struct
//timer_autoreload_t auto_reload;
} timer_info_t;
+////////////////////////////////////////
+
+// Warning: TIMER_SRC_CLK_XTAL only good for ESP32
+// Use TIMER_SRC_CLK_APB for ESP32_C3, ESP32_S2 and ESP32_S3
+
+////////////////////////////////////////
+
class ESP32TimerInterrupt
{
private:
-
- timer_config_t stdConfig =
+
+ timer_config_t stdConfig =
{
.alarm_en = TIMER_ALARM_EN, //enable timer alarm
.counter_en = TIMER_START, //starts counting counter once timer_init called
@@ -270,29 +309,37 @@ class ESP32TimerInterrupt
.counter_dir = TIMER_COUNT_UP, //counts from 0 to counter value
.auto_reload = TIMER_AUTORELOAD_EN, //reloads counter automatically
.divider = TIMER_DIVIDER,
-#if SOC_TIMER_GROUP_SUPPORT_XTAL
+#if (SOC_TIMER_GROUP_SUPPORT_XTAL)
+#if (USING_ESP32_TIMERINTERRUPT)
.clk_src = TIMER_SRC_CLK_XTAL //Use XTAL as source clock
-#endif
+#else
+ .clk_src = TIMER_SRC_CLK_APB //Use APB as source clock
+#endif
+#endif
};
+ ////////////////////////////////////////
+
timer_idx_t _timerIndex;
timer_group_t _timerGroup;
uint32_t interruptFlag; // either TIMER_INTR_T0 or TIMER_INTR_T1
-
+
uint8_t _timerNo;
esp32_timer_callback _callback; // pointer to the callback function
float _frequency; // Timer frequency
uint64_t _timerCount; // count to activate timer
-
+
//xQueueHandle s_timer_queue;
public:
+ ////////////////////////////////////////
+
ESP32TimerInterrupt(uint8_t timerNo)
- {
+ {
_callback = NULL;
-
+
if (timerNo < MAX_ESP32_NUM_TIMERS)
{
_timerNo = timerNo;
@@ -301,17 +348,17 @@ class ESP32TimerInterrupt
// Always using TIMER_INTR_T0
_timerIndex = (timer_idx_t) ( (uint32_t) 0 );
-
+
// timerNo == 0 => Group 0, timerNo == 1 => Group 1
_timerGroup = (timer_group_t) ( (uint32_t) timerNo);
-
+
#else
-
+
_timerIndex = (timer_idx_t) (_timerNo % TIMER_MAX);
-
+
_timerGroup = (timer_group_t) (_timerNo / TIMER_MAX);
-
-#endif
+
+#endif
}
else
{
@@ -319,12 +366,14 @@ class ESP32TimerInterrupt
}
};
+ ////////////////////////////////////////
+
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
bool setFrequency(const float& frequency, esp32_timer_callback callback)
{
if (_timerNo < MAX_ESP32_NUM_TIMERS)
- {
+ {
// select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now.
// Will use later if very low frequency is needed.
_frequency = TIMER_BASE_CLK / TIMER_DIVIDER; //1000000;
@@ -335,7 +384,7 @@ class ESP32TimerInterrupt
TISR_LOGWARN3(F("ESP32_S2_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
- TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
+ TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
#elif USING_ESP32_S3_NEW_TIMERINTERRUPT
// ESP32-S3 is embedded with four 54-bit general-purpose timers, which are based on 16-bit prescalers
@@ -343,50 +392,52 @@ class ESP32TimerInterrupt
TISR_LOGWARN3(F("ESP32_S3_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
- TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
- TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
+ TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
+ TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
#else
TISR_LOGWARN3(F("ESP32_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
- TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
+ TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
#endif
timer_init(_timerGroup, _timerIndex, &stdConfig);
-
+
// Counter value to 0 => counting up to alarm value as .counter_dir == TIMER_COUNT_UP
- timer_set_counter_value(_timerGroup, _timerIndex , 0x00000000ULL);
-
+ timer_set_counter_value(_timerGroup, _timerIndex, 0x00000000ULL);
+
timer_set_alarm_value(_timerGroup, _timerIndex, TIMER_SCALE / frequency);
-
+
// enable interrupts for _timerGroup, _timerIndex
timer_enable_intr(_timerGroup, _timerIndex);
-
+
_callback = callback;
-
- // Register the ISR handler
+
+ // Register the ISR handler
// If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, the handler function must be declared with IRAM_ATTR attribute
// and can only call functions in IRAM or ROM. It cannot call other timer APIs.
- //timer_isr_register(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, ESP_INTR_FLAG_IRAM, NULL);
+ //timer_isr_register(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, ESP_INTR_FLAG_IRAM, NULL);
timer_isr_callback_add(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, 0);
timer_start(_timerGroup, _timerIndex);
-
+
return true;
}
else
{
#if USING_ESP32_C3_NEW_TIMERINTERRUPT
TISR_LOGERROR(F("Error. Timer must be 0-1"));
-#else
+#else
TISR_LOGERROR(F("Error. Timer must be 0-3"));
#endif
-
+
return false;
}
}
+ ////////////////////////////////////////
+
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
bool setInterval(const unsigned long& interval, esp32_timer_callback callback)
@@ -394,11 +445,15 @@ class ESP32TimerInterrupt
return setFrequency((float) (1000000.0f / interval), callback);
}
+ ////////////////////////////////////////
+
bool attachInterrupt(const float& frequency, esp32_timer_callback callback)
{
return setFrequency(frequency, callback);
}
+ ////////////////////////////////////////
+
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
bool attachInterruptInterval(const unsigned long& interval, esp32_timer_callback callback)
@@ -406,67 +461,85 @@ class ESP32TimerInterrupt
return setFrequency( (float) ( 1000000.0f / interval), callback);
}
+ ////////////////////////////////////////
+
void detachInterrupt()
{
#if USING_ESP32_C3_NEW_TIMERINTERRUPT
timer_group_intr_disable(_timerGroup, TIMER_INTR_T0);
-#else
+#else
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
+ ////////////////////////////////////////
+
void disableTimer()
{
#if USING_ESP32_C3_NEW_TIMERINTERRUPT
timer_group_intr_disable(_timerGroup, TIMER_INTR_T0);
-#else
+#else
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
+ ////////////////////////////////////////
+
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void reattachInterrupt()
{
#if USING_ESP32_C3_NEW_TIMERINTERRUPT
timer_group_intr_enable(_timerGroup, TIMER_INTR_T0);
-#else
+#else
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
-#endif
+#endif
}
+ ////////////////////////////////////////
+
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void enableTimer()
{
#if USING_ESP32_C3_NEW_TIMERINTERRUPT
timer_group_intr_enable(_timerGroup, TIMER_INTR_T0);
-#else
+#else
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
+ ////////////////////////////////////////
+
// Just stop clock source, clear the count
void stopTimer()
{
timer_pause(_timerGroup, _timerIndex);
}
+ ////////////////////////////////////////
+
// Just reconnect clock source, start current count from 0
void restartTimer()
{
- timer_set_counter_value(_timerGroup, _timerIndex , 0x00000000ULL);
+ timer_set_counter_value(_timerGroup, _timerIndex, 0x00000000ULL);
timer_start(_timerGroup, _timerIndex);
}
+ ////////////////////////////////////////
+
int8_t getTimer() __attribute__((always_inline))
{
return _timerIndex;
};
-
+
+ ////////////////////////////////////////
+
int8_t getTimerGroup() __attribute__((always_inline))
{
return _timerGroup;
};
+ ////////////////////////////////////////
+
}; // class ESP32TimerInterrupt
#endif // ESP32_NEW_TIMERINTERRUPT_H
diff --git a/src/ESP8266TimerInterrupt_Generic.h b/src/ESP8266TimerInterrupt_Generic.h
index ac1f784f..efc8a6f5 100644
--- a/src/ESP8266TimerInterrupt_Generic.h
+++ b/src/ESP8266TimerInterrupt_Generic.h
@@ -24,7 +24,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -42,6 +42,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -60,11 +62,11 @@
#ifndef ESP8266_TIMER_INTERRUPT_VERSION
#define ESP8266_TIMER_INTERRUPT_VERSION "ESP8266TimerInterrupt v1.6.0"
- #define ESP8266_TIMER_INTERRUPT_VERSION_MAJOR 1
- #define ESP8266_TIMER_INTERRUPT_VERSION_MINOR 6
- #define ESP8266_TIMER_INTERRUPT_VERSION_PATCH 0
+ #define ESP8266_TIMER_INTERRUPT_VERSION_MAJOR 1
+ #define ESP8266_TIMER_INTERRUPT_VERSION_MINOR 6
+ #define ESP8266_TIMER_INTERRUPT_VERSION_PATCH 0
- #define ESP8266_TIMER_INTERRUPT_VERSION_INT 1006000
+ #define ESP8266_TIMER_INTERRUPT_VERSION_INT 1006000
#endif
@@ -96,11 +98,11 @@
};
//timer int_types
- #define TIM_EDGE 0
- #define TIM_LEVEL 1
+ #define TIM_EDGE 0
+ #define TIM_LEVEL 1
//timer reload values
- #define TIM_SINGLE 0 //on interrupt routine you need to write a new value to start the timer again
- #define TIM_LOOP 1 //on interrupt the counter will start with the same value again
+ #define TIM_SINGLE 0 //on interrupt routine you need to write a new value to start the timer again
+ #define TIM_LOOP 1 //on interrupt the counter will start with the same value again
*/
@@ -122,31 +124,31 @@ typedef void (*timer_callback) ();
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using TIM_DIV1_CLOCK for shortest and most accurate timer
#endif
-
+
#define TIM_CLOCK_FREQ TIM_DIV1_CLOCK
#define TIM_DIV TIM_DIV1
#elif ( defined(USING_TIM_DIV16) && USING_TIM_DIV16 )
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using TIM_DIV16_CLOCK for medium time and medium accurate timer
#endif
-
+
#define TIM_CLOCK_FREQ TIM_DIV16_CLOCK
#define TIM_DIV TIM_DIV16
#elif ( defined(USING_TIM_DIV256) && USING_TIM_DIV256 )
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using TIM_DIV256_CLOCK for longest timer but least accurate
#endif
-
+
#define TIM_CLOCK_FREQ TIM_DIV256_CLOCK
- #define TIM_DIV TIM_DIV256
+ #define TIM_DIV TIM_DIV256
#else
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Default to using TIM_DIV256_CLOCK for longest timer but least accurate
#endif
-
+
#define TIM_CLOCK_FREQ TIM_DIV256_CLOCK
#define TIM_DIV TIM_DIV256
-#endif
+#endif
///////////////////////////////////////////
@@ -176,15 +178,16 @@ class ESP8266TimerInterrupt
// ESP8266 only has one usable timer1, max count is only 8,388,607. So to get longer time, we use max available 256 divider
// Will use later if very low frequency is needed.
-
+
if (frequency < minFreq)
{
- TISR_LOGERROR3(F("ESP8266TimerInterrupt: Too long Timer, smallest frequency ="), minFreq, F(" for TIM_CLOCK_FREQ ="), TIM_CLOCK_FREQ);
-
+ TISR_LOGERROR3(F("ESP8266TimerInterrupt: Too long Timer, smallest frequency ="), minFreq, F(" for TIM_CLOCK_FREQ ="),
+ TIM_CLOCK_FREQ);
+
return false;
- }
-
- _frequency = frequency;
+ }
+
+ _frequency = frequency;
_timerCount = (uint32_t) (TIM_CLOCK_FREQ / frequency);
_callback = callback;
@@ -280,7 +283,7 @@ class ESP8266TimerInterrupt
}
///////////////////////////////////////////
-
+
}; // class ESP8266TimerInterrupt
diff --git a/src/ISR_Timer-Impl_Generic.h b/src/ISR_Timer-Impl_Generic.h
index 7bbb94f0..879b44a4 100644
--- a/src/ISR_Timer-Impl_Generic.h
+++ b/src/ISR_Timer-Impl_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -55,18 +57,18 @@ ISR_Timer::ISR_Timer()
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::init()
+void IRAM_ATTR_PREFIX ISR_Timer::init()
{
unsigned long current_millis = millis();
- for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
+ for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
{
memset((void*) &timer[i], 0, sizeof (timer_t));
timer[i].prev_millis = current_millis;
}
numTimers = 0;
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
timerMux = portMUX_INITIALIZER_UNLOCKED;
@@ -75,55 +77,55 @@ void IRAM_ATTR_PREFIX ISR_Timer::init()
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::run()
+void IRAM_ATTR_PREFIX ISR_Timer::run()
{
uint8_t i;
unsigned long current_millis;
// get current time
current_millis = millis();
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portENTER_CRITICAL_ISR(&timerMux);
#endif
- for (i = 0; i < MAX_NUMBER_TIMERS; i++)
+ for (i = 0; i < MAX_NUMBER_TIMERS; i++)
{
timer[i].toBeCalled = TIMER_DEFCALL_DONTRUN;
// no callback == no timer, i.e. jump over empty slots
- if (timer[i].callback != NULL)
+ if (timer[i].callback != NULL)
{
// is it time to process this timer ?
// see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592
- if ((current_millis - timer[i].prev_millis) >= timer[i].delay)
+ if ((current_millis - timer[i].prev_millis) >= timer[i].delay)
{
unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay;
-
+
// update time
timer[i].prev_millis += timer[i].delay * skipTimes;
// check if the timer callback has to be executed
- if (timer[i].enabled)
+ if (timer[i].enabled)
{
// "run forever" timers must always be executed
- if (timer[i].maxNumRuns == TIMER_RUN_FOREVER)
+ if (timer[i].maxNumRuns == TIMER_RUN_FOREVER)
{
timer[i].toBeCalled = TIMER_DEFCALL_RUNONLY;
}
// other timers get executed the specified number of times
- else if (timer[i].numRuns < timer[i].maxNumRuns)
+ else if (timer[i].numRuns < timer[i].maxNumRuns)
{
timer[i].toBeCalled = TIMER_DEFCALL_RUNONLY;
timer[i].numRuns++;
// after the last run, delete the timer
- if (timer[i].numRuns >= timer[i].maxNumRuns)
+ if (timer[i].numRuns >= timer[i].maxNumRuns)
{
timer[i].toBeCalled = TIMER_DEFCALL_RUNANDDEL;
}
@@ -133,7 +135,7 @@ void IRAM_ATTR_PREFIX ISR_Timer::run()
}
}
- for (i = 0; i < MAX_NUMBER_TIMERS; i++)
+ for (i = 0; i < MAX_NUMBER_TIMERS; i++)
{
if (timer[i].toBeCalled == TIMER_DEFCALL_DONTRUN)
continue;
@@ -146,7 +148,7 @@ void IRAM_ATTR_PREFIX ISR_Timer::run()
if (timer[i].toBeCalled == TIMER_DEFCALL_RUNANDDEL)
deleteTimer(i);
}
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portEXIT_CRITICAL_ISR(&timerMux);
@@ -157,18 +159,18 @@ void IRAM_ATTR_PREFIX ISR_Timer::run()
// find the first available slot
// return -1 if none found
-int IRAM_ATTR_PREFIX ISR_Timer::findFirstFreeSlot()
+int IRAM_ATTR_PREFIX ISR_Timer::findFirstFreeSlot()
{
// all slots are used
- if (numTimers >= MAX_NUMBER_TIMERS)
+ if (numTimers >= MAX_NUMBER_TIMERS)
{
return -1;
}
// return the first slot with no callback (i.e. free)
- for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
+ for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
{
- if (timer[i].callback == NULL)
+ if (timer[i].callback == NULL)
{
return (int) i;
}
@@ -180,22 +182,23 @@ int IRAM_ATTR_PREFIX ISR_Timer::findFirstFreeSlot()
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setupTimer(const float& d, void* f, void* p, bool h, const uint32_t& n)
+int IRAM_ATTR_PREFIX ISR_Timer::setupTimer(const float& d, void* f, void* p, bool h, const uint32_t& n)
{
int freeTimer;
- if (numTimers < 0)
+ if (numTimers < 0)
{
init();
}
freeTimer = findFirstFreeSlot();
- if (freeTimer < 0)
+
+ if (freeTimer < 0)
{
return -1;
}
- if (f == NULL)
+ if (f == NULL)
{
return -1;
}
@@ -215,63 +218,63 @@ int IRAM_ATTR_PREFIX ISR_Timer::setupTimer(const float& d, void* f, void* p, boo
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setTimer(const float& d, timerCallback f, const uint32_t& n)
+int IRAM_ATTR_PREFIX ISR_Timer::setTimer(const float& d, timerCallback f, const uint32_t& n)
{
return setupTimer(d, (void *)f, NULL, false, n);
}
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setTimer(const float& d, timerCallback_p f, void* p, const uint32_t& n)
+int IRAM_ATTR_PREFIX ISR_Timer::setTimer(const float& d, timerCallback_p f, void* p, const uint32_t& n)
{
return setupTimer(d, (void *)f, p, true, n);
}
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setInterval(const float& d, timerCallback f)
+int IRAM_ATTR_PREFIX ISR_Timer::setInterval(const float& d, timerCallback f)
{
return setupTimer(d, (void *)f, NULL, false, TIMER_RUN_FOREVER);
}
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setInterval(const float& d, timerCallback_p f, void* p)
+int IRAM_ATTR_PREFIX ISR_Timer::setInterval(const float& d, timerCallback_p f, void* p)
{
return setupTimer(d, (void *)f, p, true, TIMER_RUN_FOREVER);
}
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setTimeout(const float& d, timerCallback f)
+int IRAM_ATTR_PREFIX ISR_Timer::setTimeout(const float& d, timerCallback f)
{
return setupTimer(d, (void *)f, NULL, false, TIMER_RUN_ONCE);
}
///////////////////////////////////////////
-int IRAM_ATTR_PREFIX ISR_Timer::setTimeout(const float& d, timerCallback_p f, void* p)
+int IRAM_ATTR_PREFIX ISR_Timer::setTimeout(const float& d, timerCallback_p f, void* p)
{
return setupTimer(d, (void *)f, p, true, TIMER_RUN_ONCE);
}
///////////////////////////////////////////
-bool IRAM_ATTR_PREFIX ISR_Timer::changeInterval(const uint8_t& numTimer, const float& d)
+bool IRAM_ATTR_PREFIX ISR_Timer::changeInterval(const uint8_t& numTimer, const float& d)
{
- if (numTimer >= MAX_NUMBER_TIMERS)
+ if (numTimer >= MAX_NUMBER_TIMERS)
{
return false;
}
// Updates interval of existing specified timer
- if (timer[numTimer].callback != NULL)
+ if (timer[numTimer].callback != NULL)
{
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portENTER_CRITICAL(&timerMux);
#endif
-
+
timer[numTimer].delay = d;
timer[numTimer].prev_millis = millis();
@@ -282,75 +285,75 @@ bool IRAM_ATTR_PREFIX ISR_Timer::changeInterval(const uint8_t& numTimer, const f
return true;
}
-
+
// false return for non-used numTimer, no callback
return false;
}
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::deleteTimer(const uint8_t& timerId)
+void IRAM_ATTR_PREFIX ISR_Timer::deleteTimer(const uint8_t& timerId)
{
- if (timerId >= MAX_NUMBER_TIMERS)
+ if (timerId >= MAX_NUMBER_TIMERS)
{
return;
}
// nothing to delete if no timers are in use
- if (numTimers == 0)
+ if (numTimers == 0)
{
return;
}
// don't decrease the number of timers if the specified slot is already empty
- if (timer[timerId].callback != NULL)
+ if (timer[timerId].callback != NULL)
{
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portENTER_CRITICAL(&timerMux);
#endif
-
+
memset((void*) &timer[timerId], 0, sizeof (timer_t));
timer[timerId].prev_millis = millis();
// update number of timers
numTimers--;
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portEXIT_CRITICAL(&timerMux);
-#endif
+#endif
}
}
///////////////////////////////////////////
// function contributed by code@rowansimms.com
-void IRAM_ATTR_PREFIX ISR_Timer::restartTimer(const uint8_t& numTimer)
+void IRAM_ATTR_PREFIX ISR_Timer::restartTimer(const uint8_t& numTimer)
{
- if (numTimer >= MAX_NUMBER_TIMERS)
+ if (numTimer >= MAX_NUMBER_TIMERS)
{
return;
}
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portENTER_CRITICAL(&timerMux);
-#endif
+#endif
timer[numTimer].prev_millis = millis();
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portEXIT_CRITICAL(&timerMux);
-#endif
+#endif
}
///////////////////////////////////////////
-bool IRAM_ATTR_PREFIX ISR_Timer::isEnabled(const uint8_t& numTimer)
+bool IRAM_ATTR_PREFIX ISR_Timer::isEnabled(const uint8_t& numTimer)
{
- if (numTimer >= MAX_NUMBER_TIMERS)
+ if (numTimer >= MAX_NUMBER_TIMERS)
{
return false;
}
@@ -360,9 +363,9 @@ bool IRAM_ATTR_PREFIX ISR_Timer::isEnabled(const uint8_t& numTimer)
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::enable(const uint8_t& numTimer)
+void IRAM_ATTR_PREFIX ISR_Timer::enable(const uint8_t& numTimer)
{
- if (numTimer >= MAX_NUMBER_TIMERS)
+ if (numTimer >= MAX_NUMBER_TIMERS)
{
return;
}
@@ -372,9 +375,9 @@ void IRAM_ATTR_PREFIX ISR_Timer::enable(const uint8_t& numTimer)
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::disable(const uint8_t& numTimer)
+void IRAM_ATTR_PREFIX ISR_Timer::disable(const uint8_t& numTimer)
{
- if (numTimer >= MAX_NUMBER_TIMERS)
+ if (numTimer >= MAX_NUMBER_TIMERS)
{
return;
}
@@ -384,7 +387,7 @@ void IRAM_ATTR_PREFIX ISR_Timer::disable(const uint8_t& numTimer)
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::enableAll()
+void IRAM_ATTR_PREFIX ISR_Timer::enableAll()
{
// Enable all timers with a callback assigned (used)
@@ -393,23 +396,23 @@ void IRAM_ATTR_PREFIX ISR_Timer::enableAll()
portENTER_CRITICAL(&timerMux);
#endif
- for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
+ for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
{
- if (timer[i].callback != NULL && timer[i].numRuns == TIMER_RUN_FOREVER)
+ if (timer[i].callback != NULL && timer[i].numRuns == TIMER_RUN_FOREVER)
{
timer[i].enabled = true;
}
}
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portEXIT_CRITICAL(&timerMux);
-#endif
+#endif
}
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::disableAll()
+void IRAM_ATTR_PREFIX ISR_Timer::disableAll()
{
// Disable all timers with a callback assigned (used)
@@ -418,25 +421,25 @@ void IRAM_ATTR_PREFIX ISR_Timer::disableAll()
portENTER_CRITICAL(&timerMux);
#endif
- for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
+ for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
{
- if (timer[i].callback != NULL && timer[i].numRuns == TIMER_RUN_FOREVER)
+ if (timer[i].callback != NULL && timer[i].numRuns == TIMER_RUN_FOREVER)
{
timer[i].enabled = false;
}
}
-
+
#if ( defined(ESP32) || ESP32 )
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
portEXIT_CRITICAL(&timerMux);
-#endif
+#endif
}
///////////////////////////////////////////
-void IRAM_ATTR_PREFIX ISR_Timer::toggle(const uint8_t& numTimer)
+void IRAM_ATTR_PREFIX ISR_Timer::toggle(const uint8_t& numTimer)
{
- if (numTimer >= MAX_NUMBER_TIMERS)
+ if (numTimer >= MAX_NUMBER_TIMERS)
{
return;
}
@@ -446,7 +449,7 @@ void IRAM_ATTR_PREFIX ISR_Timer::toggle(const uint8_t& numTimer)
///////////////////////////////////////////
-uint8_t IRAM_ATTR_PREFIX ISR_Timer::getNumTimers()
+uint8_t IRAM_ATTR_PREFIX ISR_Timer::getNumTimers()
{
return numTimers;
}
diff --git a/src/ISR_Timer_Generic.h b/src/ISR_Timer_Generic.h
index 4ef5d04d..e77be5ff 100644
--- a/src/ISR_Timer_Generic.h
+++ b/src/ISR_Timer_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -48,7 +50,7 @@
#ifndef TIMER_INTERRUPT_GENERIC_VERSION
#define TIMER_INTERRUPT_GENERIC_VERSION "TimerInterrupt_Generic v1.12.0"
-
+
#define TIMER_INTERRUPT_GENERIC_VERSION_MAJOR 1
#define TIMER_INTERRUPT_GENERIC_VERSION_MINOR 12
#define TIMER_INTERRUPT_GENERIC_VERSION_PATCH 0
@@ -71,18 +73,18 @@
#if !( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \
ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \
ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM || ARDUINO_ADAFRUIT_QTPY_ESP32S2)
- #define CONFIG_ESP32_APPTRACE_ENABLE
+#define CONFIG_ESP32_APPTRACE_ENABLE
#endif
#if ( defined(ESP8266) || ESP8266 )
- extern "C"
- {
- #include "ets_sys.h"
- #include "os_type.h"
- #include "mem.h"
- }
+extern "C"
+{
+#include "ets_sys.h"
+#include "os_type.h"
+#include "mem.h"
+}
#else
- #include
+#include
#endif
///////////////////////////////////////////
@@ -104,7 +106,7 @@ typedef void (*timerCallback_p)(void *);
///////////////////////////////////////////
-class ISR_Timer
+class ISR_Timer
{
public:
// maximum number of timers
@@ -183,7 +185,7 @@ class ISR_Timer
///////////////////////////////////////////
// returns the number of available timers
- uint8_t IRAM_ATTR_PREFIX getNumAvailableTimers()
+ uint8_t IRAM_ATTR_PREFIX getNumAvailableTimers()
{
return MAX_NUMBER_TIMERS - numTimers;
};
@@ -207,7 +209,7 @@ class ISR_Timer
///////////////////////////////////////////
- typedef struct
+ typedef struct
{
unsigned long prev_millis; // value returned by the millis() function in the previous run() call
void* callback; // pointer to the callback function
diff --git a/src/MBED_RP2040_TimerInterrupt_Generic.h b/src/MBED_RP2040_TimerInterrupt_Generic.h
index 81cd4cd1..57e903e4 100644
--- a/src/MBED_RP2040_TimerInterrupt_Generic.h
+++ b/src/MBED_RP2040_TimerInterrupt_Generic.h
@@ -5,7 +5,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
-
+
The RPI_PICO system timer peripheral provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
• A single 64-bit counter, incrementing once per microsecond
@@ -25,7 +25,7 @@
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -43,6 +43,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -54,21 +56,21 @@
#if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \
defined(ARDUINO_GENERIC_RP2040) ) && defined(ARDUINO_ARCH_MBED)
- #define USING_MBED_RPI_PICO_TIMER_INTERRUPT true
+#define USING_MBED_RPI_PICO_TIMER_INTERRUPT true
#else
- #error This code is intended to run on the MBED RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
+#error This code is intended to run on the MBED RASPBERRY_PI_PICO platform! Please check your Tools->Board setting.
#endif
///////////////////////////////////////////
#ifndef MBED_RPI_PICO_TIMER_INTERRUPT_VERSION
- #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION "MBED_RPi_Pico_TimerInterrupt v1.1.2"
-
+ #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION "MBED_RPi_Pico_TimerInterrupt v1.2.0"
+
#define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_MAJOR 1
- #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_MINOR 1
- #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_PATCH 2
+ #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_MINOR 2
+ #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_PATCH 0
- #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_INT 1001002
+ #define MBED_RPI_PICO_TIMER_INTERRUPT_VERSION_INT 1002000
#endif
///////////////////////////////////////////
@@ -91,27 +93,27 @@
alarm time in microseconds). Writing the time to the ALARM register sets the ARMED bit as a side effect.
Once the alarm has fired, the ARMED bit will be set to 0 . To clear the latched interrupt, write a 1 to the appropriate bit in
INTR.
-
+
Defined in x.y.z/cores/arduino/mbed/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/include/hardware/timer.h
-
+
typedef void (*hardware_alarm_callback_t)(uint alarm_num);
-
+
void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback);
- bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
+ bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
void hardware_alarm_cancel(uint alarm_num);
*/
// We can use many timers here
#define MAX_RPI_PICO_NUM_TIMERS 4
-absolute_time_t absAlarmTime[MAX_RPI_PICO_NUM_TIMERS];
+absolute_time_t absAlarmTime[MAX_RPI_PICO_NUM_TIMERS];
volatile uint64_t _timerCount [MAX_RPI_PICO_NUM_TIMERS];
///////////////////////////////////////////
void TIMER_ISR_START(uint alarm_num)
-{
- absAlarmTime[alarm_num]._private_us_since_boot = time_us_64() + _timerCount[alarm_num];
+{
+ absAlarmTime[alarm_num]._private_us_since_boot = time_us_64() + _timerCount[alarm_num];
hardware_alarm_set_target(alarm_num, absAlarmTime[alarm_num]);
}
@@ -128,26 +130,26 @@ class MBED_RPI_PICO_TimerInterrupt;
typedef MBED_RPI_PICO_TimerInterrupt MBED_RPI_PICO_Timer;
////////////////////////////////////////////////////////////////////////
-
+
class MBED_RPI_PICO_TimerInterrupt
{
private:
-
+
uint8_t _timerNo;
hardware_alarm_callback_t _callback; // pointer to the local callback function
float _frequency; // Timer frequency
-
+
public:
MBED_RPI_PICO_TimerInterrupt(uint8_t timerNo)
- {
+ {
_timerNo = timerNo;
_callback = NULL;
};
///////////////////////////////////////////
- #define TIM_CLOCK_FREQ ( (float) 1000000.0f )
+#define TIM_CLOCK_FREQ ( (float) 1000000.0f )
///////////////////////////////////////////
@@ -160,40 +162,43 @@ class MBED_RPI_PICO_TimerInterrupt
if ( (frequency == 0.0f) || (frequency > 100000.0f) || (callback == NULL) )
{
TISR_LOGERROR(F("Error. frequency == 0, higher than 100KHz or callback == NULL "));
-
+
return false;
}
-
+
// Hardware timer is preset in RP2040 at 1MHz / 1uS
_frequency = frequency;
- _timerCount[_timerNo] = (uint64_t) TIM_CLOCK_FREQ / frequency;
-
+
+ //_timerCount[_timerNo] = (uint64_t) TIM_CLOCK_FREQ / frequency;
+ // Ref: https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt/issues/4
+ _timerCount[_timerNo] = (uint64_t) ( ( float) TIM_CLOCK_FREQ / frequency ) - 1;
+
TISR_LOGWARN5(F("_timerNo = "), _timerNo, F(", Clock (Hz) = "), TIM_CLOCK_FREQ, F(", _fre (Hz) = "), _frequency);
- TISR_LOGWARN3(F("_count = "), (uint32_t) (_timerCount[_timerNo] >> 32) , F("-"), (uint32_t) (_timerCount[_timerNo]));
-
+ TISR_LOGWARN3(F("_count = "), (uint32_t) (_timerCount[_timerNo] >> 32), F("-"), (uint32_t) (_timerCount[_timerNo]) + 1);
+
_callback = callback;
-
+
//void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback);
//param callback the callback to install, or NULL to unset
- hardware_alarm_set_callback(_timerNo, callback);
-
+ hardware_alarm_set_callback(_timerNo, callback);
+
TIMER_ISR_START(_timerNo);
-
+
//bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
// KH, redundant, to be removed
//hardware_alarm_set_target(_timerNo, absAlarmTime[_timerNo]);
-
- TISR_LOGWARN1(F("hardware_alarm_set_target, uS = "), _timerCount[_timerNo]);
+
+ TISR_LOGWARN1(F("hardware_alarm_set_target, uS = "), _timerCount[_timerNo] + 1);
return true;
}
else
{
TISR_LOGERROR(F("Error. Timer must be 0-3"));
-
+
return false;
}
-
+
TIMER_ISR_END(_timerNo);
}
@@ -279,7 +284,7 @@ class MBED_RPI_PICO_TimerInterrupt
}
///////////////////////////////////////////
-
+
}; // class MBED_RPI_PICO_TimerInterrupt
#endif // MBED_RPI_PICO_TIMERINTERRUPT_H
diff --git a/src/NRF52TimerInterrupt_Generic.h b/src/NRF52TimerInterrupt_Generic.h
index f9de324c..07e03cf1 100644
--- a/src/NRF52TimerInterrupt_Generic.h
+++ b/src/NRF52TimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,13 +37,15 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
/*
nRF52 has 5 Hardware TIMERs: NRF_TIMER0-NRF_TIMER4
NRF_TIMER0 is used by the soft device, NRF_TIMER1-NRF_TIMER4 are available
-
+
Defined in file ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/mdk/nrf52.h
-
+
#define NRF_TIMER0_BASE 0x40008000UL
#define NRF_TIMER1_BASE 0x40009000UL
#define NRF_TIMER2_BASE 0x4000A000UL
@@ -57,9 +59,9 @@
#define NRF_TIMER4 ((NRF_TIMER_Type*) NRF_TIMER4_BASE)
===============================================================================
-
+
Defined in ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/hal/nrf_timer.h
-
+
Timer prescalers
typedef enum
{
@@ -74,47 +76,61 @@
NRF_TIMER_FREQ_62500Hz, ///< Timer frequency 62500 Hz.
NRF_TIMER_FREQ_31250Hz ///< Timer frequency 31250 Hz.
} nrf_timer_frequency_t;
-
+
*/
#pragma once
#ifndef NRF52TIMERINTERRUPT_H
#define NRF52TIMERINTERRUPT_H
+////////////////////////////////////////
+
#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \
defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \
defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || \
defined(NRF52840_LED_GLASSES) || defined(MDBT50Q_RX) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) )
- #error This code is designed to run on Adafruit nRF52 platform! Please check your Tools->Board setting.
+#error This code is designed to run on Adafruit nRF52 platform! Please check your Tools->Board setting.
#endif
+////////////////////////////////////////
+
#include
#include "nrf_timer.h"
#include
+////////////////////////////////////////
+
#ifndef NRF52_TIMER_INTERRUPT_VERSION
- #define NRF52_TIMER_INTERRUPT_VERSION "NRF52TimerInterrupt v1.4.1"
-
+ #define NRF52_TIMER_INTERRUPT_VERSION "NRF52TimerInterrupt v1.4.2"
+
#define NRF52_TIMER_INTERRUPT_VERSION_MAJOR 1
#define NRF52_TIMER_INTERRUPT_VERSION_MINOR 4
- #define NRF52_TIMER_INTERRUPT_VERSION_PATCH 1
+ #define NRF52_TIMER_INTERRUPT_VERSION_PATCH 2
- #define NRF52_TIMER_INTERRUPT_VERSION_INT 1004001
+ #define NRF52_TIMER_INTERRUPT_VERSION_INT 1004002
#endif
+////////////////////////////////////////
+
#ifndef TIMER_INTERRUPT_DEBUG
#define TIMER_INTERRUPT_DEBUG 0
#endif
+////////////////////////////////////////
+
#include "TimerInterrupt_Generic_Debug.h"
+////////////////////////////////////////
+
class NRF52TimerInterrupt;
typedef NRF52TimerInterrupt NRF52Timer;
typedef void (*timerCallback) ();
+////////////////////////////////////////
+
typedef enum
{
NRF_TIMER_0 = 0,
@@ -125,6 +141,8 @@ typedef enum
NRF_MAX_TIMER
} NRF52TimerNumber;
+////////////////////////////////////////
+
const char* NRF52TimerName[NRF_MAX_TIMER] =
{
"NRF_TIMER0-DON'T_USE_THIS",
@@ -134,28 +152,27 @@ const char* NRF52TimerName[NRF_MAX_TIMER] =
"NRF_TIMER4",
};
+////////////////////////////////////////
+
/*
-typedef enum
-{
+ typedef enum
+ {
NRF_TIMER_CC_CHANNEL0 = 0, ///< Timer capture/compare channel 0.
NRF_TIMER_CC_CHANNEL1, ///< Timer capture/compare channel 1.
NRF_TIMER_CC_CHANNEL2, ///< Timer capture/compare channel 2.
NRF_TIMER_CC_CHANNEL3, ///< Timer capture/compare channel 3.
-#ifdef NRF52
+ #ifdef NRF52
NRF_TIMER_CC_CHANNEL4, ///< Timer capture/compare channel 4.
NRF_TIMER_CC_CHANNEL5, ///< Timer capture/compare channel 5.
-#endif
-} nrf_timer_cc_channel_t;
+ #endif
+ } nrf_timer_cc_channel_t;
*/
+////////////////////////////////////////
class NRF52TimerInterrupt;
-//NRF_TIMER_Type* nrf_timers [NRF_MAX_TIMER] = { NRF_TIMER0, NRF_TIMER1, NRF_TIMER2, NRF_TIMER3, NRF_TIMER4 };
-
-//IRQn_Type nrf_timers_irq[NRF_MAX_TIMER] = { TIMER0_IRQn, TIMER1_IRQn, TIMER2_IRQn, TIMER3_IRQn, TIMER4_IRQn };
-
-//NRF52TimerInterrupt* nRF52Timers [NRF_MAX_TIMER] = { NULL, NULL, NULL, NULL, NULL };
+////////////////////////////////////////
static NRF_TIMER_Type* nrf_timers [NRF_MAX_TIMER] = { NRF_TIMER0, NRF_TIMER1, NRF_TIMER2, NRF_TIMER3, NRF_TIMER4 };
@@ -163,27 +180,31 @@ static IRQn_Type nrf_timers_irq[NRF_MAX_TIMER] = { TIMER0_IRQn, TIMER1_IRQ
static NRF52TimerInterrupt* nRF52Timers [NRF_MAX_TIMER] = { NULL, NULL, NULL, NULL, NULL };
+////////////////////////////////////////
+
class NRF52TimerInterrupt
{
private:
uint8_t _timer = NRF_TIMER_1;
-
+
NRF_TIMER_Type* nrf_timer = NRF_TIMER1;
nrf_timer_cc_channel_t cc_channel = NRF_TIMER_CC_CHANNEL0;
-
+
IRQn_Type _timer_IRQ;
timerCallback _callback; // pointer to the callback function
-
+
// NRF_TIMER_FREQ_16MHz,NRF_TIMER_FREQ_8MHz,...,NRF_TIMER_FREQ_31250Hz
nrf_timer_frequency_t _frequency_t = NRF_TIMER_FREQ_1MHz;
-
+
float TIM_CLOCK_FREQ; // Timer Clock frequency
float _frequency; // Timer frequency
uint32_t _timerCount; // count to activate timer
public:
+ ////////////////////////////////////////
+
NRF52TimerInterrupt(uint8_t timer = NRF_TIMER_1)
{
// KH, force to use NRF_TIMER1 if accidentally select already used NRF_TIMER0
@@ -192,85 +213,95 @@ class NRF52TimerInterrupt
_timer = NRF_TIMER_1;
else
_timer = timer;
-
+
nrf_timer = nrf_timers[_timer];
-
+
_timer_IRQ = nrf_timers_irq[_timer];
// Update to use in TIMERx_IRQHandler
nRF52Timers[_timer] = this;
-
+
_callback = NULL;
-
+
// Timer mode with 32bit width
nrf_timer_bit_width_set(nrf_timer, NRF_TIMER_BIT_WIDTH_32);
nrf_timer_mode_set(nrf_timer, NRF_TIMER_MODE_TIMER);
-
+
// KH, just 1MHz is enough. 16MHz can have better accuracy, but shorter time range.
nrf_timer_frequency_set(nrf_timer, _frequency_t);
-
+
switch (_frequency_t)
{
- case NRF_TIMER_FREQ_16MHz:
- TIM_CLOCK_FREQ = 16000000.0f;
-
- break;
- case NRF_TIMER_FREQ_8MHz:
- TIM_CLOCK_FREQ = 8000000.0f;
-
- break;
+ case NRF_TIMER_FREQ_16MHz:
+ TIM_CLOCK_FREQ = 16000000.0f;
+
+ break;
+
+ case NRF_TIMER_FREQ_8MHz:
+ TIM_CLOCK_FREQ = 8000000.0f;
+
+ break;
+
case NRF_TIMER_FREQ_4MHz:
- TIM_CLOCK_FREQ = 4000000.0f;
-
- break;
- case NRF_TIMER_FREQ_2MHz:
- TIM_CLOCK_FREQ = 2000000.0f;
-
- break;
- case NRF_TIMER_FREQ_1MHz:
- TIM_CLOCK_FREQ = 1000000.0f;
-
- break;
- default:
- TIM_CLOCK_FREQ = 1000000.0f;
- break;
- }
+ TIM_CLOCK_FREQ = 4000000.0f;
+
+ break;
+
+ case NRF_TIMER_FREQ_2MHz:
+ TIM_CLOCK_FREQ = 2000000.0f;
+
+ break;
+
+ case NRF_TIMER_FREQ_1MHz:
+ TIM_CLOCK_FREQ = 1000000.0f;
+
+ break;
+
+ default:
+ TIM_CLOCK_FREQ = 1000000.0f;
+ break;
+ }
};
-
+
+ ////////////////////////////////////////
+
~NRF52TimerInterrupt()
{
nRF52Timers[_timer] = NULL;
}
+ ////////////////////////////////////////
+
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c
bool setFrequency(const float& frequency, timerCallback callback)
{
// This function will be called when time out interrupt will occur
- if (callback)
+ if (callback)
{
- _callback = callback;
- }
- else
+ _callback = callback;
+ }
+ else
{
- TISR_LOGERROR(F("NRF52TimerInterrupt: ERROR: NULL callback function pointer."));
-
- return false;
+ TISR_LOGERROR(F("NRF52TimerInterrupt: ERROR: NULL callback function pointer."));
+
+ return false;
}
-
- if ( (frequency <= 0) || (frequency > TIM_CLOCK_FREQ / 10.0f) )
+
+ if ( (frequency <= 0) || (frequency > TIM_CLOCK_FREQ / 10.0f) )
{
- TISR_LOGERROR1(F("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <="), TIM_CLOCK_FREQ/10.0f);
-
+ TISR_LOGERROR1(F("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <="), TIM_CLOCK_FREQ / 10.0f);
+
return false;
}
-
+
// select timer frequency is 1MHz for better accuracy as well as longer timer. We don't use 16-bit prescaler for now.
// Will use later if very low frequency is needed.
- _frequency = frequency;
+ _frequency = frequency;
_timerCount = (uint32_t) TIM_CLOCK_FREQ / frequency;
-
- TISR_LOGWARN5(F("F_CPU (MHz) = "), F_CPU/1000000, F(", Timer = "), NRF52TimerName[_timer], F(", Timer Clock (Hz) = "), TIM_CLOCK_FREQ);
+
+ TISR_LOGWARN5(F("F_CPU (MHz) = "), F_CPU / 1000000, F(", Timer = "), NRF52TimerName[_timer], F(", Timer Clock (Hz) = "),
+ TIM_CLOCK_FREQ);
TISR_LOGWARN3(F("Frequency = "), frequency, F(", _count = "), (uint32_t) (_timerCount));
// Start if not already running (and reset?)
@@ -280,9 +311,9 @@ class NRF52TimerInterrupt
// Clear and enable compare interrupt
nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel);
nrf_timer_int_enable(nrf_timer, channel_mask);
-
+
NVIC_EnableIRQ(_timer_IRQ);
-
+
//nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount);
// New for Adafruit nRF52 core 0.21.0
nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount);
@@ -290,6 +321,8 @@ class NRF52TimerInterrupt
return true;
}
+ ////////////////////////////////////////
+
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c
bool setInterval(const unsigned long& interval, timerCallback callback)
@@ -297,11 +330,15 @@ class NRF52TimerInterrupt
return setFrequency((float) (1000000.0f / interval), callback);
}
+ ////////////////////////////////////////
+
bool attachInterrupt(const float& frequency, timerCallback callback)
{
return setFrequency(frequency, callback);
}
+ ////////////////////////////////////////
+
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c
bool attachInterruptInterval(const unsigned long& interval, timerCallback callback)
@@ -309,10 +346,12 @@ class NRF52TimerInterrupt
return setFrequency( (float) ( 1000000.0f / interval), callback);
}
+ ////////////////////////////////////////
+
void detachInterrupt()
{
NVIC_DisableIRQ(_timer_IRQ);
-
+
// Stop timer
nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_STOP);
@@ -325,17 +364,23 @@ class NRF52TimerInterrupt
nrf_timer_event_clear(nrf_timer, event);
}
+ ////////////////////////////////////////
+
void disableTimer()
{
detachInterrupt();
}
+ ////////////////////////////////////////
+
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void reattachInterrupt()
{
setFrequency(_frequency, _callback);
}
+ ////////////////////////////////////////
+
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void enableTimer()
{
@@ -346,86 +391,107 @@ class NRF52TimerInterrupt
// Clear and enable compare interrupt
nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel);
nrf_timer_int_enable(nrf_timer, channel_mask);
-
+
NVIC_EnableIRQ(_timer_IRQ);
-
+
//nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount);
// New for Adafruit nRF52 core 0.21.0
nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount);
}
+ ////////////////////////////////////////
+
// Just stop clock source, clear the count
void stopTimer()
{
disableTimer();
}
+ ////////////////////////////////////////
+
// Just reconnect clock source, start current count from 0
void restartTimer()
{
enableTimer();
}
-
- timerCallback getCallback()
+
+ ////////////////////////////////////////
+
+ inline timerCallback getCallback()
{
return _callback;
}
-
- IRQn_Type getTimerIRQn()
+
+ ////////////////////////////////////////
+
+ inline IRQn_Type getTimerIRQn()
{
return _timer_IRQ;
}
+
+ ////////////////////////////////////////
+
}; // class NRF52TimerInterrupt
+////////////////////////////////////////
+
// Timer 0 is used by the soft device but Timer 1, 2, 3 and 4 are available
-extern "C" void TIMER1_IRQHandler()
+extern "C" void TIMER1_IRQHandler()
{
- if (nRF52Timers[1])
+ if (nRF52Timers[1])
{
nRF52Timers[1]->detachInterrupt();
-
+
(*(nRF52Timers[1]->getCallback()))();
-
+
nRF52Timers[1]->enableTimer();
}
}
-extern "C" void TIMER2_IRQHandler()
+////////////////////////////////////////
+
+extern "C" void TIMER2_IRQHandler()
{
- if (nRF52Timers[2])
+ if (nRF52Timers[2])
{
nRF52Timers[2]->detachInterrupt();
-
+
(*(nRF52Timers[2]->getCallback()))();
-
+
nRF52Timers[2]->enableTimer();
}
}
-extern "C" void TIMER3_IRQHandler()
+////////////////////////////////////////
+
+extern "C" void TIMER3_IRQHandler()
{
- if (nRF52Timers[3])
+ if (nRF52Timers[3])
{
nRF52Timers[3]->detachInterrupt();
-
+
(*(nRF52Timers[3]->getCallback()))();
-
+
nRF52Timers[3]->enableTimer();
}
}
-extern "C" void TIMER4_IRQHandler()
+////////////////////////////////////////
+
+extern "C" void TIMER4_IRQHandler()
{
- if (nRF52Timers[4])
+ if (nRF52Timers[4])
{
nRF52Timers[4]->detachInterrupt();
-
+
(*(nRF52Timers[4]->getCallback()))();
-
+
nRF52Timers[4]->enableTimer();
}
}
+////////////////////////////////////////
+
#endif // NRF52TIMERINTERRUPT_H
diff --git a/src/NRF52_MBED_TimerInterrupt_Generic.h b/src/NRF52_MBED_TimerInterrupt_Generic.h
index cc04d321..c7189ba2 100644
--- a/src/NRF52_MBED_TimerInterrupt_Generic.h
+++ b/src/NRF52_MBED_TimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,13 +37,15 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
/*
nRF52 has 5 Hardware TIMERs: NRF_TIMER0-NRF_TIMER4
NRF_TIMER0 is used by the soft device, NRF_TIMER1-NRF_TIMER4 are available
-
+
Defined in file ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/mdk/nrf52.h
-
+
#define NRF_TIMER0_BASE 0x40008000UL
#define NRF_TIMER1_BASE 0x40009000UL
#define NRF_TIMER2_BASE 0x4000A000UL
@@ -57,9 +59,9 @@
#define NRF_TIMER4 ((NRF_TIMER_Type*) NRF_TIMER4_BASE)
===============================================================================
-
+
Defined in ./adafruit/hardware/nrf52/0.21.0/cores/nRF5/nordic/nrfx/hal/nrf_timer.h
-
+
Timer prescalers
typedef enum
{
@@ -74,7 +76,7 @@
NRF_TIMER_FREQ_62500Hz, ///< Timer frequency 62500 Hz.
NRF_TIMER_FREQ_31250Hz ///< Timer frequency 31250 Hz.
} nrf_timer_frequency_t;
-
+
*/
#pragma once
@@ -93,13 +95,13 @@
#include "hal/nrf_timer.h"
#ifndef NRF52_MBED_TIMER_INTERRUPT_VERSION
- #define NRF52_MBED_TIMER_INTERRUPT_VERSION "NRF52_MBED_TimerInterrupt v1.4.0"
-
+ #define NRF52_MBED_TIMER_INTERRUPT_VERSION "NRF52_MBED_TimerInterrupt v1.4.1"
+
#define NRF52_MBED_TIMER_INTERRUPT_VERSION_MAJOR 1
#define NRF52_MBED_TIMER_INTERRUPT_VERSION_MINOR 4
- #define NRF52_MBED_TIMER_INTERRUPT_VERSION_PATCH 0
+ #define NRF52_MBED_TIMER_INTERRUPT_VERSION_PATCH 1
- #define NRF52_MBED_TIMER_INTERRUPT_VERSION_INT 1004000
+ #define NRF52_MBED_TIMER_INTERRUPT_VERSION_INT 1004001
#endif
#include "TimerInterrupt_Generic_Debug.h"
@@ -130,17 +132,17 @@ const char* NRF52_MBED_TimerName[NRF_MAX_TIMER] =
};
/*
-typedef enum
-{
+ typedef enum
+ {
NRF_TIMER_CC_CHANNEL0 = 0, ///< Timer capture/compare channel 0.
NRF_TIMER_CC_CHANNEL1, ///< Timer capture/compare channel 1.
NRF_TIMER_CC_CHANNEL2, ///< Timer capture/compare channel 2.
NRF_TIMER_CC_CHANNEL3, ///< Timer capture/compare channel 3.
-#ifdef NRF52
+ #ifdef NRF52
NRF_TIMER_CC_CHANNEL4, ///< Timer capture/compare channel 4.
NRF_TIMER_CC_CHANNEL5, ///< Timer capture/compare channel 5.
-#endif
-} nrf_timer_cc_channel_t;
+ #endif
+ } nrf_timer_cc_channel_t;
*/
///////////////////////////////////////////////////////
@@ -158,13 +160,13 @@ NRF_STATIC_INLINE void nrf_timer_cc_set(NRF_TIMER_Type * p_reg,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value)
{
- p_reg->CC[cc_channel] = cc_value;
+ p_reg->CC[cc_channel] = cc_value;
}
NRF_STATIC_INLINE uint32_t nrf_timer_cc_get(NRF_TIMER_Type const * p_reg,
nrf_timer_cc_channel_t cc_channel)
{
- return (uint32_t)p_reg->CC[cc_channel];
+ return (uint32_t)p_reg->CC[cc_channel];
}
///////////////////////////////////////////////////////
@@ -181,17 +183,17 @@ class NRF52_MBED_TimerInterrupt
{
private:
uint8_t _timer = NRF_TIMER_3;
-
+
NRF_TIMER_Type* nrf_timer = NRF_TIMER3;
nrf_timer_cc_channel_t cc_channel = NRF_TIMER_CC_CHANNEL0;
-
+
IRQn_Type _timer_IRQ;
timerCallback _callback; // pointer to the callback function
-
+
// NRF_TIMER_FREQ_16MHz,NRF_TIMER_FREQ_8MHz,...,NRF_TIMER_FREQ_31250Hz
nrf_timer_frequency_t _frequency_t = NRF_TIMER_FREQ_1MHz;
-
+
float TIM_CLOCK_FREQ; // Timer Clock frequency
float _frequency; // Timer frequency
uint32_t _timerCount; // count to activate timer
@@ -208,51 +210,56 @@ class NRF52_MBED_TimerInterrupt
_timer = NRF_TIMER_3;
else
_timer = timer;
-
+
nrf_timer = nrf_timers[_timer];
-
+
_timer_IRQ = nrf_timers_irq[_timer];
// Update to use in TIMERx_IRQHandler
nRF52Timers[_timer] = this;
-
+
_callback = NULL;
-
+
// Timer mode with 32bit width
nrf_timer_bit_width_set(nrf_timer, NRF_TIMER_BIT_WIDTH_32);
nrf_timer_mode_set(nrf_timer, NRF_TIMER_MODE_TIMER);
-
+
// KH, just 1MHz is enough. 16MHz can have better accuracy, but shorter time range.
nrf_timer_frequency_set(nrf_timer, _frequency_t);
-
+
switch (_frequency_t)
{
- case NRF_TIMER_FREQ_16MHz:
- TIM_CLOCK_FREQ = 16000000.0f;
-
- break;
- case NRF_TIMER_FREQ_8MHz:
- TIM_CLOCK_FREQ = 8000000.0f;
-
- break;
+ case NRF_TIMER_FREQ_16MHz:
+ TIM_CLOCK_FREQ = 16000000.0f;
+
+ break;
+
+ case NRF_TIMER_FREQ_8MHz:
+ TIM_CLOCK_FREQ = 8000000.0f;
+
+ break;
+
case NRF_TIMER_FREQ_4MHz:
- TIM_CLOCK_FREQ = 4000000.0f;
-
- break;
- case NRF_TIMER_FREQ_2MHz:
- TIM_CLOCK_FREQ = 2000000.0f;
-
- break;
- case NRF_TIMER_FREQ_1MHz:
- TIM_CLOCK_FREQ = 1000000.0f;
-
- break;
- default:
- TIM_CLOCK_FREQ = 1000000.0f;
- break;
- }
+ TIM_CLOCK_FREQ = 4000000.0f;
+
+ break;
+
+ case NRF_TIMER_FREQ_2MHz:
+ TIM_CLOCK_FREQ = 2000000.0f;
+
+ break;
+
+ case NRF_TIMER_FREQ_1MHz:
+ TIM_CLOCK_FREQ = 1000000.0f;
+
+ break;
+
+ default:
+ TIM_CLOCK_FREQ = 1000000.0f;
+ break;
+ }
};
-
+
~NRF52_MBED_TimerInterrupt()
{
nRF52Timers[_timer] = NULL;
@@ -263,29 +270,29 @@ class NRF52_MBED_TimerInterrupt
bool setFrequency(const float& frequency, timerCallback callback)
{
// This function will be called when time out interrupt will occur
- if (callback)
+ if (callback)
{
- _callback = callback;
- }
- else
+ _callback = callback;
+ }
+ else
{
- TISR_LOGERROR(F("NRF52_MBED_TimerInterrupt: ERROR: NULL callback function pointer."));
+ TISR_LOGERROR(F("NRF52_MBED_TimerInterrupt: ERROR: NULL callback function pointer."));
- return false;
+ return false;
}
-
- if ( (frequency <= 0) || (frequency > TIM_CLOCK_FREQ / 10.0f) )
+
+ if ( (frequency <= 0) || (frequency > TIM_CLOCK_FREQ / 10.0f) )
{
- TISR_LOGERROR1(F("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <="), TIM_CLOCK_FREQ/10.0f);
-
+ TISR_LOGERROR1(F("NRF52TimerInterrupt: ERROR: Negative or Too high frequency. Must be <="), TIM_CLOCK_FREQ / 10.0f);
+
return false;
}
-
+
// select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now.
- // Will use later if very low frequency is needed.
- _frequency = frequency;
+ // Will use later if very low frequency is needed.
+ _frequency = frequency;
_timerCount = (uint32_t) TIM_CLOCK_FREQ / frequency;
-
+
TISR_LOGWARN3(F("Timer = "), NRF52_MBED_TimerName[_timer], F(", Timer Clock (Hz) = "), TIM_CLOCK_FREQ);
TISR_LOGWARN3(F("Frequency = "), frequency, F(", _count = "), (uint32_t) (_timerCount));
@@ -296,9 +303,9 @@ class NRF52_MBED_TimerInterrupt
// Clear and enable compare interrupt
nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel);
nrf_timer_int_enable(nrf_timer, channel_mask);
-
+
NVIC_EnableIRQ(_timer_IRQ);
-
+
//nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount);
// New for Adafruit nRF52 core 0.21.0
nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount);
@@ -328,7 +335,7 @@ class NRF52_MBED_TimerInterrupt
void detachInterrupt()
{
NVIC_DisableIRQ(_timer_IRQ);
-
+
// Stop timer
nrf_timer_task_trigger(nrf_timer, NRF_TIMER_TASK_STOP);
@@ -362,9 +369,9 @@ class NRF52_MBED_TimerInterrupt
// Clear and enable compare interrupt
nrf_timer_int_mask_t channel_mask = nrf_timer_compare_int_get(cc_channel);
nrf_timer_int_enable(nrf_timer, channel_mask);
-
+
NVIC_EnableIRQ(_timer_IRQ);
-
+
//nrf_timer_cc_write(nrf_timer, cc_channel, _timerCount);
// New for Adafruit nRF52 core 0.21.0
nrf_timer_cc_set(nrf_timer, cc_channel, _timerCount);
@@ -381,12 +388,12 @@ class NRF52_MBED_TimerInterrupt
{
enableTimer();
}
-
+
timerCallback getCallback()
{
return _callback;
}
-
+
IRQn_Type getTimerIRQn()
{
return _timer_IRQ;
@@ -398,36 +405,36 @@ class NRF52_MBED_TimerInterrupt
// only Timer 1, 3 and 4 are available
extern "C" void TIMER1_IRQHandler_v()
{
- if (nRF52Timers[1])
+ if (nRF52Timers[1])
{
nRF52Timers[1]->detachInterrupt();
-
+
(*(nRF52Timers[1]->getCallback()))();
-
+
nRF52Timers[1]->enableTimer();
}
}
-extern "C" void TIMER3_IRQHandler_v()
+extern "C" void TIMER3_IRQHandler_v()
{
- if (nRF52Timers[3])
+ if (nRF52Timers[3])
{
nRF52Timers[3]->detachInterrupt();
-
+
(*(nRF52Timers[3]->getCallback()))();
-
+
nRF52Timers[3]->enableTimer();
}
}
-extern "C" void TIMER4_IRQHandler_v()
+extern "C" void TIMER4_IRQHandler_v()
{
- if (nRF52Timers[4])
+ if (nRF52Timers[4])
{
nRF52Timers[4]->detachInterrupt();
-
+
(*(nRF52Timers[4]->getCallback()))();
-
+
nRF52Timers[4]->enableTimer();
}
}
diff --git a/src/RP2040_TimerInterrupt_Generic.h b/src/RP2040_TimerInterrupt_Generic.h
index 8837a58a..99b5582d 100644
--- a/src/RP2040_TimerInterrupt_Generic.h
+++ b/src/RP2040_TimerInterrupt_Generic.h
@@ -25,7 +25,7 @@
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -43,6 +43,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -52,11 +54,11 @@
///////////////////////////////////////////
-#if ( defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) ) && !defined(ARDUINO_ARCH_MBED)
+#if ( defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) ) && !defined(ARDUINO_ARCH_MBED)
#if defined(USING_RPI_PICO_TIMER_INTERRUPT)
#undef USING_RPI_PICO_TIMER_INTERRUPT
- #endif
- #define USING_RPI_PICO_TIMER_INTERRUPT true
+ #endif
+ #define USING_RPI_PICO_TIMER_INTERRUPT true
#else
#error This code is intended to run on the non-mbed RP2040 arduino-pico platform! Please check your Tools->Board setting.
#endif
@@ -65,7 +67,7 @@
#ifndef RPI_PICO_TIMER_INTERRUPT_VERSION
#define RPI_PICO_TIMER_INTERRUPT_VERSION "RPi_Pico_TimerInterrupt v1.3.1"
-
+
#define RPI_PICO_TIMER_INTERRUPT_VERSION_MAJOR 1
#define RPI_PICO_TIMER_INTERRUPT_VERSION_MINOR 3
#define RPI_PICO_TIMER_INTERRUPT_VERSION_PATCH 1
@@ -82,25 +84,25 @@
///////////////////////////////////////////
#if defined(ARDUINO_ARCH_MBED)
-
+
#if(_TIMERINTERRUPT_LOGLEVEL_>3)
#warning Using mbed_rp2040 core
#endif
-
+
#include "pico.h"
//#include "pico/stdio.h"
#include "pico/time.h"
#include "hardware/gpio.h"
#include "hardware/uart.h"
-
+
#include "hardware/timer.h"
#include "hardware/irq.h"
#else
-
+
#if(_TIMERINTERRUPT_LOGLEVEL_>3)
#warning Using RP2040 arduino-pico core
#endif
-
+
#include
#include "pico/stdlib.h"
#include "hardware/timer.h"
@@ -136,26 +138,26 @@ typedef bool (*pico_timer_callback) (struct repeating_timer *t);
class RPI_PICO_TimerInterrupt
{
private:
-
+
uint8_t _timerNo;
pico_timer_callback _callback; // pointer to the callback function
float _frequency; // Timer frequency
int64_t _timerCount; // count to activate timer, in us
-
+
struct repeating_timer _timer;
public:
RPI_PICO_TimerInterrupt(uint8_t timerNo)
- {
+ {
_timerNo = timerNo;
_callback = NULL;
};
///////////////////////////////////////////
- #define TIM_CLOCK_FREQ ( (float) 1000000.0f )
+#define TIM_CLOCK_FREQ ( (float) 1000000.0f )
///////////////////////////////////////////
@@ -164,38 +166,38 @@ class RPI_PICO_TimerInterrupt
bool setFrequency(const float& frequency, pico_timer_callback callback)
{
if (_timerNo < MAX_RPI_PICO_NUM_TIMERS)
- {
+ {
if ( (frequency == 0.0f) || (frequency > 100000.0f) || (callback == NULL) )
{
TISR_LOGERROR(F("Error. frequency == 0, higher than 100KHz or callback == NULL "));
-
+
return false;
}
-
+
// select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now.
- // Will use later if very low frequency is needed.
+ // Will use later if very low frequency is needed.
_frequency = frequency;
_timerCount = (int64_t) TIM_CLOCK_FREQ / frequency;
-
+
TISR_LOGWARN5(F("_timerNo = "), _timerNo, F(", Clock (Hz) = "), TIM_CLOCK_FREQ, F(", _fre (Hz) = "), _frequency);
- TISR_LOGWARN3(F("_count = "), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
-
+ TISR_LOGWARN3(F("_count = "), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
+
_callback = callback;
-
+
// static bool add_repeating_timer_us(int64_t delay_us, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out);
// static bool add_repeating_timer_ms(int64_t delay_ms, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out);
// bool cancel_repeating_timer (repeating_timer_t *timer);
//////////////////////////////////////////////////////////////////////////
// Important Notes
// delay_ms the repeat delay in milliseconds; if >0 then this is the delay between one callback ending and the next
- // starting; if <0 then this is the negative of the time between the starts of the callbacks.
+ // starting; if <0 then this is the negative of the time between the starts of the callbacks.
// The value of 0 is treated as 1 microsecond
//////////////////////////////////////////////////////////////////////////
cancel_repeating_timer(&_timer);
-
+
// Use negative value to select time between the starts of the callbacks
add_repeating_timer_us(-(_timerCount), _callback, NULL, &_timer);
-
+
TISR_LOGWARN1(F("add_repeating_timer_us between starts = "), _timerCount);
return true;
@@ -203,7 +205,7 @@ class RPI_PICO_TimerInterrupt
else
{
TISR_LOGERROR(F("Error. Timer must be 0-3"));
-
+
return false;
}
}
@@ -288,7 +290,7 @@ class RPI_PICO_TimerInterrupt
};
////////////////////////////////////////////////////////////////
-
+
}; // class RPI_PICO_TimerInterrupt
#endif // RPI_PICO_TIMERINTERRUPT_H
diff --git a/src/SAMDTimerInterrupt_Generic.h b/src/SAMDTimerInterrupt_Generic.h
index 7e64b8ca..50d7ed2a 100644
--- a/src/SAMDTimerInterrupt_Generic.h
+++ b/src/SAMDTimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,20 +37,22 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
/*
SAMD21
-
+
The Timer/Counter for Control Applications (TCC) module provides a set of timing and counting related functionality, such as the
generation of periodic waveforms, the capturing of a periodic waveform's frequency/duty cycle, software timekeeping for periodic
operations, waveform extension control, fault detection etc.
The counter size of the TCC modules can be 16- or 24-bit depending on the TCC instance
-
+
1) Nano-33-IoT SAMD21G18A
.arduino15/packages/arduino/tools/CMSIS-Atmel/1.2.0/CMSIS/Device/ATMEL/samd21/include/samd21g18a.h
#define TC3 ((Tc *)0x42002C00UL)
-
+
*/
#pragma once
@@ -68,7 +70,7 @@
|| defined(__SAMD21E15A__) || defined(__SAMD21E16A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__) \
|| defined(__SAMD21G15A__) || defined(__SAMD21G16A__) || defined(__SAMD21G17A__) || defined(__SAMD21G18A__) \
|| defined(__SAMD21J15A__) || defined(__SAMD21J16A__) || defined(__SAMD21J17A__) || defined(__SAMD21J18A__) )
- #error This code is designed to run on SAMD21/SAMD51 platform! Please check your Tools->Board setting.
+#error This code is designed to run on SAMD21/SAMD51 platform! Please check your Tools->Board setting.
#endif
///////////////////////////////////////////
@@ -79,92 +81,92 @@
|| defined(__SAMD21E15A__) || defined(__SAMD21E16A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__) \
|| defined(__SAMD21G15A__) || defined(__SAMD21G16A__) || defined(__SAMD21G17A__) || defined(__SAMD21G18A__) \
|| defined(__SAMD21J15A__) || defined(__SAMD21J16A__) || defined(__SAMD21J17A__) || defined(__SAMD21J18A__) || defined(__SAMD21__) )
-
- #define TIMER_INTERRUPT_USING_SAMD21 true
-
- #if !defined(BOARD_NAME)
-
- #if defined(ARDUINO_QWIIC_MICRO)
- #define BOARD_NAME "Sparkfun SAMD21_QWIIC_MICRO"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning BOARD_NAME == Sparkfun SAMD21_QWIIC_MICRO
- #endif
-
- #elif defined(__SAMD21E15A__)
- #define BOARD_NAME "__SAMD21E15A__"
- #elif defined(__SAMD21E16A__)
- #define BOARD_NAME "__SAMD21E16A__"
- #elif defined(__SAMD21E17A__)
- #define BOARD_NAME "__SAMD21E17A__"
- #elif defined(__SAMD21E18A__)
- #define BOARD_NAME "__SAMD21E18A__"
- #elif defined(__SAMD21G15A__)
- #define BOARD_NAME "__SAMD21G15A__"
- #elif defined(__SAMD21G16A__)
- #define BOARD_NAME "__SAMD21G16A__"
- #elif defined(__SAMD21G17A__)
- #define BOARD_NAME "__SAMD21G17A__"
- #elif defined(__SAMD21G18A__)
- #define BOARD_NAME "__SAMD21G18A__"
- #elif defined(__SAMD21J15A__)
- #define BOARD_NAME "__SAMD21J15A__"
- #elif defined(__SAMD21J16A__)
- #define BOARD_NAME "__SAMD21J16A__"
- #elif defined(__SAMD21J17A__)
- #define BOARD_NAME "__SAMD21J17A__"
- #elif defined(__SAMD21J18A__)
- #define BOARD_NAME "__SAMD21J18A__"
- #else
- #define BOARD_NAME "Unknown SAMD21"
+
+#define TIMER_INTERRUPT_USING_SAMD21 true
+
+#if !defined(BOARD_NAME)
+
+ #if defined(ARDUINO_QWIIC_MICRO)
+ #define BOARD_NAME "Sparkfun SAMD21_QWIIC_MICRO"
+
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning BOARD_NAME == Sparkfun SAMD21_QWIIC_MICRO
#endif
-
- #endif
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using SAMD21 Hardware Timer
+
+ #elif defined(__SAMD21E15A__)
+ #define BOARD_NAME "__SAMD21E15A__"
+ #elif defined(__SAMD21E16A__)
+ #define BOARD_NAME "__SAMD21E16A__"
+ #elif defined(__SAMD21E17A__)
+ #define BOARD_NAME "__SAMD21E17A__"
+ #elif defined(__SAMD21E18A__)
+ #define BOARD_NAME "__SAMD21E18A__"
+ #elif defined(__SAMD21G15A__)
+ #define BOARD_NAME "__SAMD21G15A__"
+ #elif defined(__SAMD21G16A__)
+ #define BOARD_NAME "__SAMD21G16A__"
+ #elif defined(__SAMD21G17A__)
+ #define BOARD_NAME "__SAMD21G17A__"
+ #elif defined(__SAMD21G18A__)
+ #define BOARD_NAME "__SAMD21G18A__"
+ #elif defined(__SAMD21J15A__)
+ #define BOARD_NAME "__SAMD21J15A__"
+ #elif defined(__SAMD21J16A__)
+ #define BOARD_NAME "__SAMD21J16A__"
+ #elif defined(__SAMD21J17A__)
+ #define BOARD_NAME "__SAMD21J17A__"
+ #elif defined(__SAMD21J18A__)
+ #define BOARD_NAME "__SAMD21J18A__"
+ #else
+ #define BOARD_NAME "Unknown SAMD21"
#endif
+#endif
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using SAMD21 Hardware Timer
+#endif
+
///////////////////////////////////////////
-
+
#elif ( defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) )
- #define TIMER_INTERRUPT_USING_SAMD51 true
-
- #if !defined(BOARD_NAME)
-
- #if defined(ARDUINO_SAMD51_THING_PLUS)
- #define BOARD_NAME "Sparkfun SAMD51_THING_PLUS"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning BOARD_NAME == Sparkfun SAMD51_THING_PLUS
- #endif
-
- #elif defined(ARDUINO_SAMD51_MICROMOD)
- #define BOARD_NAME "Sparkfun SAMD51_MICROMOD"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning BOARD_NAME == Sparkfun SAMD51_MICROMOD
- #endif
- #elif defined(__SAMD51J20A__)
- #define BOARD_NAME "__SAMD51J20A__"
- #elif defined(__SAMD51J19A__)
- #define BOARD_NAME "__SAMD51J19A__"
- #elif defined(__SAMD51G19A__)
- #define BOARD_NAME "__SAMD51G19A__"
- #elif defined(__SAMD51P19A__)
- #define BOARD_NAME "__SAMD51P19A__"
- #else
- #define BOARD_NAME "Unknown SAMD51"
+#define TIMER_INTERRUPT_USING_SAMD51 true
+
+#if !defined(BOARD_NAME)
+
+ #if defined(ARDUINO_SAMD51_THING_PLUS)
+ #define BOARD_NAME "Sparkfun SAMD51_THING_PLUS"
+
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning BOARD_NAME == Sparkfun SAMD51_THING_PLUS
#endif
-
- #endif
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using SAMD51 Hardware Timer
+
+ #elif defined(ARDUINO_SAMD51_MICROMOD)
+ #define BOARD_NAME "Sparkfun SAMD51_MICROMOD"
+
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning BOARD_NAME == Sparkfun SAMD51_MICROMOD
+ #endif
+ #elif defined(__SAMD51J20A__)
+ #define BOARD_NAME "__SAMD51J20A__"
+ #elif defined(__SAMD51J19A__)
+ #define BOARD_NAME "__SAMD51J19A__"
+ #elif defined(__SAMD51G19A__)
+ #define BOARD_NAME "__SAMD51G19A__"
+ #elif defined(__SAMD51P19A__)
+ #define BOARD_NAME "__SAMD51P19A__"
+ #else
+ #define BOARD_NAME "Unknown SAMD51"
#endif
+
+#endif
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using SAMD51 Hardware Timer
+#endif
#else
- #error Unknown board
+#error Unknown board
#endif
///////////////////////////////////////////
@@ -173,12 +175,12 @@
// Have to exclude some from the list
#if ( defined(ARDUINO_SAMD_ZERO) && ! ( defined(ADAFRUIT_FEATHER_M0) || defined(ARDUINO_SAMD_FEATHER_M0) || defined(ADAFRUIT_METRO_M0_EXPRESS) || \
defined(ARDUINO_SAMD_HALLOWING_M0) || defined(ADAFRUIT_BLM_BADGE) ) )
-
- // Specific for SAMD21 SparkFun RedBoard Turbo
- #if !defined(Serial)
- #define Serial SerialUSB
- #endif
-
+
+// Specific for SAMD21 SparkFun RedBoard Turbo
+#if !defined(Serial)
+ #define Serial SerialUSB
+#endif
+
#endif
///////////////////////////////////////////
@@ -189,7 +191,7 @@
#ifndef SAMD_TIMER_INTERRUPT_VERSION
#define SAMD_TIMER_INTERRUPT_VERSION "SAMDTimerInterrupt v1.10.1"
-
+
#define SAMD_TIMER_INTERRUPT_VERSION_MAJOR 1
#define SAMD_TIMER_INTERRUPT_VERSION_MINOR 10
#define SAMD_TIMER_INTERRUPT_VERSION_PATCH 1
@@ -229,17 +231,17 @@ timerCallback TC3_callback;
////////////////////////////////////////////////////
-static inline void TC3_wait_for_sync()
+static inline void TC3_wait_for_sync()
{
while (TC3->COUNT16.SYNCBUSY.reg != 0);
}
////////////////////////////////////////////////////
-void TC3_Handler()
+void TC3_Handler()
{
// If this interrupt is due to the compare register matching the timer count
- if (TC3->COUNT16.INTFLAG.bit.MC0 == 1)
+ if (TC3->COUNT16.INTFLAG.bit.MC0 == 1)
{
TC3->COUNT16.INTFLAG.bit.MC0 = 1;
(*TC3_callback)();
@@ -252,99 +254,100 @@ void TC3_Handler()
class SAMDTimerInterrupt
{
private:
-
+
////////////////////////////////////////////////////
-
+
SAMDTimerNumber _timerNumber;
-
+
// point to timer struct, (TcCount16*) TC3 for SAMD51
void* _SAMDTimer = NULL;
-
+
timerCallback _callback; // pointer to the callback function
float _frequency; // Timer frequency
-
+
float _period;
int _prescaler;
int _compareValue;
-
+
////////////////////////////////////////////////////
public:
-
+
////////////////////////////////////////////////////
SAMDTimerInterrupt(const SAMDTimerNumber& timerNumber)
{
_timerNumber = timerNumber;
-
+
if (_timerNumber == TIMER_TC3)
{
- _SAMDTimer = (TcCount16*) TC3;
+ _SAMDTimer = (TcCount16*) TC3;
}
-
- _callback = NULL;
+
+ _callback = NULL;
};
-
+
////////////////////////////////////////////////////
~SAMDTimerInterrupt()
{
}
-
+
////////////////////////////////////////////////////
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to SAMD-hal-timer.c
bool setFrequency(const float& frequency, timerCallback callback)
- {
- _period = (1000000.0f / frequency);
-
- if (_timerNumber == TIMER_TC3)
- {
- TISR_LOGWARN3(F("SAMDTimerInterrupt: F_CPU (MHz) ="), F_CPU/1000000, F(", TIMER_HZ ="), TIMER_HZ/1000000);
- TISR_LOGWARN3(F("TC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC3 = 0x"), String((uint32_t) TC3, HEX));
+ {
+ _period = (1000000.0f / frequency);
+
+ if (_timerNumber == TIMER_TC3)
+ {
+ TISR_LOGWARN3(F("SAMDTimerInterrupt: F_CPU (MHz) ="), F_CPU / 1000000, F(", TIMER_HZ ="), TIMER_HZ / 1000000);
+ TISR_LOGWARN3(F("TC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC3 = 0x"),
+ String((uint32_t) TC3, HEX));
// maxPermittedPeriod = 1,398,101.33us for 48MHz timer clock
float maxPermittedPeriod = (65536.0f * 1024) / (TIMER_HZ / 1000000.0f );
-
+
if (_period > maxPermittedPeriod )
{
TISR_LOGERROR3(F("Max permissible _period (us) ="), maxPermittedPeriod, F(", current _period (us) ="), _period);
-
+
return false;
}
-
- // Enable the TC bus clock, use clock generator 0
- GCLK->PCHCTRL[TC3_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
-
- while (GCLK->SYNCBUSY.reg > 0);
-
- TC3->COUNT16.CTRLA.bit.ENABLE = 0;
-
- // Use match mode so that the timer counter resets when the count matches the
- // compare register
- TC3->COUNT16.WAVE.bit.WAVEGEN = TC_WAVE_WAVEGEN_MFRQ;
- TC3_wait_for_sync();
-
- // Enable the compare interrupt
- TC3->COUNT16.INTENSET.reg = 0;
- TC3->COUNT16.INTENSET.bit.MC0 = 1;
-
- // Enable IRQ
- NVIC_EnableIRQ(TC3_IRQn);
-
- _callback = callback;
- TC3_callback = callback;
-
- setPeriod_TIMER_TC3(_period);
-
- return true;
- }
- else
- return false;
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////
+
+ // Enable the TC bus clock, use clock generator 0
+ GCLK->PCHCTRL[TC3_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
+
+ while (GCLK->SYNCBUSY.reg > 0);
+
+ TC3->COUNT16.CTRLA.bit.ENABLE = 0;
+
+ // Use match mode so that the timer counter resets when the count matches the
+ // compare register
+ TC3->COUNT16.WAVE.bit.WAVEGEN = TC_WAVE_WAVEGEN_MFRQ;
+ TC3_wait_for_sync();
+
+ // Enable the compare interrupt
+ TC3->COUNT16.INTENSET.reg = 0;
+ TC3->COUNT16.INTENSET.bit.MC0 = 1;
+
+ // Enable IRQ
+ NVIC_EnableIRQ(TC3_IRQn);
+
+ _callback = callback;
+ TC3_callback = callback;
+
+ setPeriod_TIMER_TC3(_period);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to SAMD-hal-timer.c
@@ -353,15 +356,15 @@ class SAMDTimerInterrupt
return setFrequency((float) (1000000.0f / interval), callback);
}
- ////////////////////////////////////////////////////
-
+ ////////////////////////////////////////////////////
+
// interval (in milliseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be added in the future by adding similar functions here or to SAMD-hal-timer.c
bool setInterval_MS(const float& interval, timerCallback callback)
{
return setFrequency((float) (1000.0f / interval), callback);
}
-
+
///////////////////////////////////////////////////////////////////////////////////////
bool attachInterrupt(const float& frequency, timerCallback callback)
@@ -369,7 +372,7 @@ class SAMDTimerInterrupt
return setFrequency(frequency, callback);
}
- ///////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to SAMD-hal-timer.c
@@ -378,15 +381,15 @@ class SAMDTimerInterrupt
return setFrequency( (float) ( 1000000.0f / interval), callback);
}
- ////////////////////////////////////////////////////
-
+ ////////////////////////////////////////////////////
+
// interval (in milliseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be added in the future by adding similar functions here or to SAMD-hal-timer.c
bool attachInterruptInterval_MS(const float& interval, timerCallback callback)
{
return setFrequency( (float) ( 1000.0f / interval), callback);
}
-
+
////////////////////////////////////////////////////
void detachInterrupt()
@@ -394,23 +397,23 @@ class SAMDTimerInterrupt
// Disable Interrupt
if (_timerNumber == TIMER_TC3)
{
- NVIC_DisableIRQ(TC3_IRQn);
+ NVIC_DisableIRQ(TC3_IRQn);
}
}
- ///////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
void disableTimer()
{
// Disable Timer
if (_timerNumber == TIMER_TC3)
- {
+ {
// Disable TC3
TC3->COUNT16.CTRLA.bit.ENABLE = 0;
}
}
- ///////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void reattachInterrupt()
@@ -418,24 +421,24 @@ class SAMDTimerInterrupt
// Disable Interrupt
if (_timerNumber == TIMER_TC3)
{
- NVIC_EnableIRQ(TC3_IRQn);
+ NVIC_EnableIRQ(TC3_IRQn);
}
}
- ///////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void enableTimer()
- {
+ {
// Enable Timer
if (_timerNumber == TIMER_TC3)
- {
+ {
// Enable TC3
SAMD_TC3->CTRLA.reg |= TC_CTRLA_ENABLE;
}
}
- ///////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
// Just stop clock source, clear the count
void stopTimer()
@@ -444,7 +447,7 @@ class SAMDTimerInterrupt
disableTimer();
}
- ///////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
// Just reconnect clock source, start current count from 0
void restartTimer()
@@ -453,12 +456,12 @@ class SAMDTimerInterrupt
enableTimer();
}
- ///////////////////////////////////////////////////////////////////////////////////////
-
- private:
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ private:
+
+ ///////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////
-
void setPeriod_TIMER_TC3(const float& period)
{
uint32_t TC_CTRLA_PRESCALER_DIVN = 1;
@@ -480,50 +483,51 @@ class SAMDTimerInterrupt
TC3->COUNT16.CTRLA.reg &= ~TC_CTRLA_PRESCALER_DIV1;
TC3_wait_for_sync();
- if (period > 300000)
+ if (period > 300000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV1024;
_prescaler = 1024;
- }
- else if (80000 < period && period <= 300000)
+ }
+ else if (80000 < period && period <= 300000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV256;
_prescaler = 256;
- }
- else if (20000 < period && period <= 80000)
+ }
+ else if (20000 < period && period <= 80000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV64;
_prescaler = 64;
- }
- else if (10000 < period && period <= 20000)
+ }
+ else if (10000 < period && period <= 20000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV16;
_prescaler = 16;
- }
- else if (5000 < period && period <= 10000)
+ }
+ else if (5000 < period && period <= 10000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV8;
_prescaler = 8;
- }
- else if (2500 < period && period <= 5000)
+ }
+ else if (2500 < period && period <= 5000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV4;
_prescaler = 4;
- }
- else if (1000 < period && period <= 2500) {
+ }
+ else if (1000 < period && period <= 2500)
+ {
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV2;
_prescaler = 2;
- }
- else if (period <= 1000)
+ }
+ else if (period <= 1000)
{
TC_CTRLA_PRESCALER_DIVN = TC_CTRLA_PRESCALER_DIV1;
_prescaler = 1;
}
-
+
TC3->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIVN;
TC3_wait_for_sync();
- _compareValue = (int)(TIMER_HZ / (_prescaler/(period / 1000000.0))) - 1;
+ _compareValue = (int)(TIMER_HZ / (_prescaler / (period / 1000000.0))) - 1;
// Make sure the count is in a proportional position to where it was
// to prevent any jitter or disconnect when changing the compare value.
@@ -534,7 +538,7 @@ class SAMDTimerInterrupt
TC3->COUNT16.CTRLA.bit.ENABLE = 1;
TC3_wait_for_sync();
-
+
TISR_LOGDEBUG3(F("SAMD51 TC3 period ="), period, F(", _prescaler ="), _prescaler);
TISR_LOGDEBUG1(F("_compareValue ="), _compareValue);
}
@@ -544,7 +548,7 @@ class SAMDTimerInterrupt
////////////////////////////////////////////////////////////////////////////////////////////////
#elif (TIMER_INTERRUPT_USING_SAMD21)
-
+
////////////////////////////////////////////////////
typedef enum
@@ -563,7 +567,7 @@ typedef enum
static IRQn_Type TIMER_IRQ[MAX_TIMER] = { TC3_IRQn, TC4_IRQn, TC5_IRQn, TCC0_IRQn, TCC1_IRQn, TCC2_IRQn };
static uint16_t TC_GCLK_ID[MAX_TIMER] = { GCM_TCC2_TC3, GCM_TC4_TC5, GCM_TC4_TC5, GCM_TCC0_TCC1, GCM_TCC0_TCC1, GCM_TCC2_TC3 };
-
+
////////////////////////////////////////////////////
class SAMDTimerInterrupt;
@@ -572,7 +576,7 @@ typedef SAMDTimerInterrupt SAMDTimer;
typedef void (*timerCallback) ();
-timerCallback TC3_callback;
+timerCallback TC3_callback;
timerCallback TCC_callback;
timerCallback TCC1_callback;
timerCallback TCC2_callback;
@@ -590,351 +594,358 @@ timerCallback TC5_callback;
////////////////////////////////////////////////////////
#if USING_TIMER_TC3
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning USING_TIMER_TC3
- #endif
-
- void TC3_Handler()
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning USING_TIMER_TC3
+#endif
+
+void TC3_Handler()
+{
+ // get timer struct
+ TcCount16* TC = (TcCount16*) TC3;
+
+ // If the compare register matching the timer count, trigger this interrupt
+ if (TC->INTFLAG.bit.MC0 == 1)
{
- // get timer struct
- TcCount16* TC = (TcCount16*) TC3;
-
- // If the compare register matching the timer count, trigger this interrupt
- if (TC->INTFLAG.bit.MC0 == 1)
- {
- TC->INTFLAG.bit.MC0 = 1;
- (*TC3_callback)();
- }
+ TC->INTFLAG.bit.MC0 = 1;
+ (*TC3_callback)();
}
-
+}
+
#endif
-
+
////////////////////////////////////////////////////////
#if USING_TIMER_TC4
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning USING_TIMER_TC4
- #endif
-
- void TC4_Handler()
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning USING_TIMER_TC4
+#endif
+
+void TC4_Handler()
+{
+ // get timer struct
+ TcCount16* TC = (TcCount16*) TC4;
+
+ // If the compare register matching the timer count, trigger this interrupt
+ if (TC->INTFLAG.bit.MC0 == 1)
{
- // get timer struct
- TcCount16* TC = (TcCount16*) TC4;
-
- // If the compare register matching the timer count, trigger this interrupt
- if (TC->INTFLAG.bit.MC0 == 1)
- {
- TC->INTFLAG.bit.MC0 = 1;
- (*TC4_callback)();
- }
+ TC->INTFLAG.bit.MC0 = 1;
+ (*TC4_callback)();
}
+}
#endif
-
+
////////////////////////////////////////////////////////
#if USING_TIMER_TC5
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning USING_TIMER_TC5
- #endif
-
- void TC5_Handler()
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning USING_TIMER_TC5
+#endif
+
+void TC5_Handler()
+{
+ // get timer struct
+ TcCount16* TC = (TcCount16*) TC5;
+
+ // If the compare register matching the timer count, trigger this interrupt
+ if (TC->INTFLAG.bit.MC0 == 1)
{
- // get timer struct
- TcCount16* TC = (TcCount16*) TC5;
-
- // If the compare register matching the timer count, trigger this interrupt
- if (TC->INTFLAG.bit.MC0 == 1)
- {
- TC->INTFLAG.bit.MC0 = 1;
- (*TC5_callback)();
- }
+ TC->INTFLAG.bit.MC0 = 1;
+ (*TC5_callback)();
}
+}
#endif
-
+
////////////////////////////////////////////////////////
#if USING_TIMER_TCC
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning USING_TIMER_TCC
- #endif
-
- void TCC0_Handler()
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning USING_TIMER_TCC
+#endif
+
+void TCC0_Handler()
+{
+ // get timer struct
+ Tcc* TC = (Tcc*) TCC0;
+
+ // If the compare register matching the timer count, trigger this interrupt
+ if (TC->INTFLAG.bit.MC0 == 1)
{
- // get timer struct
- Tcc* TC = (Tcc*) TCC0;
-
- // If the compare register matching the timer count, trigger this interrupt
- if (TC->INTFLAG.bit.MC0 == 1)
- {
- // A compare to cc0 caused the interrupt
- TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
- }
+ // A compare to cc0 caused the interrupt
+ TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
+ }
- if (TC->INTFLAG.bit.OVF == 1)
- {
- (*TCC_callback)();
-
- TC->INTFLAG.bit.OVF = 1;
- }
+ if (TC->INTFLAG.bit.OVF == 1)
+ {
+ (*TCC_callback)();
+
+ TC->INTFLAG.bit.OVF = 1;
}
+}
#endif
-
+
////////////////////////////////////////////////////////
#if USING_TIMER_TCC1
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning USING_TIMER_TCC1
- #endif
-
- void TCC1_Handler()
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning USING_TIMER_TCC1
+#endif
+
+void TCC1_Handler()
+{
+ // get timer struct
+ Tcc* TC = (Tcc*) TCC1;
+
+ // If the compare register matching the timer count, trigger this interrupt
+ if (TC->INTFLAG.bit.MC0 == 1)
{
- // get timer struct
- Tcc* TC = (Tcc*) TCC1;
-
- // If the compare register matching the timer count, trigger this interrupt
- if (TC->INTFLAG.bit.MC0 == 1)
- {
- // A compare to cc0 caused the interrupt
- TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
- }
+ // A compare to cc0 caused the interrupt
+ TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
+ }
- if (TC->INTFLAG.bit.OVF == 1)
- {
- (*TCC1_callback)();
-
- TC->INTFLAG.bit.OVF = 1;
- }
+ if (TC->INTFLAG.bit.OVF == 1)
+ {
+ (*TCC1_callback)();
+
+ TC->INTFLAG.bit.OVF = 1;
}
+}
#endif
-
+
////////////////////////////////////////////////////////
#if USING_TIMER_TCC2
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning USING_TIMER_TCC2
- #endif
-
- void TCC2_Handler()
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning USING_TIMER_TCC2
+#endif
+
+void TCC2_Handler()
+{
+ // get timer struct
+ Tcc* TC = (Tcc*) TCC2;
+
+ // If the compare register matching the timer count, trigger this interrupt
+ if (TC->INTFLAG.bit.MC0 == 1)
{
- // get timer struct
- Tcc* TC = (Tcc*) TCC2;
-
- // If the compare register matching the timer count, trigger this interrupt
- if (TC->INTFLAG.bit.MC0 == 1)
- {
- // A compare to cc0 caused the interrupt
- TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
- }
+ // A compare to cc0 caused the interrupt
+ TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
+ }
- if (TC->INTFLAG.bit.OVF == 1)
- {
- (*TCC2_callback)();
-
- TC->INTFLAG.bit.OVF = 1;
- }
+ if (TC->INTFLAG.bit.OVF == 1)
+ {
+ (*TCC2_callback)();
+
+ TC->INTFLAG.bit.OVF = 1;
}
+}
#endif
///////////////////////////////////////////////////////////////////////////////
-
+
class SAMDTimerInterrupt
{
private:
-
+
////////////////////////////////////////////////////
-
+
SAMDTimerNumber _timerNumber;
-
+
// point to timer struct, (TcCount16*) TC3 or (Tcc*) TCC0 for SAMD21
void* _SAMDTimer = NULL;
-
+
timerCallback _callback; // pointer to the callback function
float _frequency; // Timer frequency
-
+
float _period;
int _prescaler;
int _compareValue;
-
+
////////////////////////////////////////////////////
public:
-
+
////////////////////////////////////////////////////
SAMDTimerInterrupt(const SAMDTimerNumber& timerNumber)
{
_timerNumber = timerNumber;
-
+
if (_timerNumber == TIMER_TC3)
{
- _SAMDTimer = (TcCount16*) TC3;
+ _SAMDTimer = (TcCount16*) TC3;
}
else if (_timerNumber == TIMER_TCC)
{
- _SAMDTimer = (Tcc*) TCC0;
+ _SAMDTimer = (Tcc*) TCC0;
}
else if (_timerNumber == TIMER_TCC1)
{
- _SAMDTimer = (Tcc*) TCC1;
+ _SAMDTimer = (Tcc*) TCC1;
}
else if (_timerNumber == TIMER_TCC2)
{
- _SAMDTimer = (Tcc*) TCC2;
+ _SAMDTimer = (Tcc*) TCC2;
}
else if (_timerNumber == TIMER_TC4)
{
- _SAMDTimer = (TcCount16*) TC4;
- }
+ _SAMDTimer = (TcCount16*) TC4;
+ }
else if (_timerNumber == TIMER_TC5)
{
- _SAMDTimer = (TcCount16*) TC5;
+ _SAMDTimer = (TcCount16*) TC5;
}
- _callback = NULL;
+ _callback = NULL;
};
-
+
////////////////////////////////////////////////////
-
+
~SAMDTimerInterrupt()
{
}
-
+
////////////////////////////////////////////////////
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to SAMD-hal-timer.c
bool setFrequency(const float& frequency, timerCallback callback)
- {
- _period = (1000000.0f / frequency);
-
- TISR_LOGDEBUG3(F("_period ="), _period, F(", frequency ="), frequency);
-
- if ( (_timerNumber == TIMER_TC3) || (_timerNumber == TIMER_TC4) || (_timerNumber == TIMER_TC5) )
- {
- TISR_LOGDEBUG1(F("_timerNumber ="), _timerNumber);
-
- // maxPermittedPeriod = 1,398,101.33us for 48MHz timer clock
+ {
+ _period = (1000000.0f / frequency);
+
+ TISR_LOGDEBUG3(F("_period ="), _period, F(", frequency ="), frequency);
+
+ if ( (_timerNumber == TIMER_TC3) || (_timerNumber == TIMER_TC4) || (_timerNumber == TIMER_TC5) )
+ {
+ TISR_LOGDEBUG1(F("_timerNumber ="), _timerNumber);
+
+ // maxPermittedPeriod = 1,398,101.33us for 48MHz timer clock
float maxPermittedPeriod = (65536.0f * 1024) / (TIMER_HZ / 1000000.0f );
-
+
if (_period > maxPermittedPeriod )
{
TISR_LOGERROR3(F("Max permissible _period (us) ="), maxPermittedPeriod, F(", current _period (us) ="), _period);
-
+
return false;
- }
-
- REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (TC_GCLK_ID[_timerNumber]));
-
- while ( GCLK->STATUS.bit.SYNCBUSY == 1 );
-
- TISR_LOGWARN3(F("SAMDTimerInterrupt: F_CPU (MHz) ="), F_CPU/1000000, F(", TIMER_HZ ="), TIMER_HZ/1000000);
-
- if (_timerNumber == TIMER_TC3)
- {
- TISR_LOGWARN3(F("TC3_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC3 = 0x"), String((uint32_t) TC3, HEX));
- }
- else if (_timerNumber == TIMER_TC4)
- {
- TISR_LOGWARN3(F("TC4_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC4 = 0x"), String((uint32_t) TC4, HEX));
- }
- else if (_timerNumber == TIMER_TC5)
- {
- TISR_LOGWARN3(F("TC5_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC5 = 0x"), String((uint32_t) TC5, HEX));
- }
-
- SAMD_TC3->CTRLA.reg &= ~TC_CTRLA_ENABLE;
-
- // Use the 16-bit timer
- SAMD_TC3->CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
-
- while (SAMD_TC3->STATUS.bit.SYNCBUSY == 1);
-
- // Use match mode so that the timer counter resets when the count matches the compare register
- SAMD_TC3->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
-
- while (SAMD_TC3->STATUS.bit.SYNCBUSY == 1);
-
- setPeriod_TIMER_TC3(_period);
-
- // Enable the compare interrupt
- SAMD_TC3->INTENSET.reg = 0;
- SAMD_TC3->INTENSET.bit.MC0 = 1;
-
- NVIC_EnableIRQ(TIMER_IRQ[_timerNumber]);
-
- SAMD_TC3->CTRLA.reg |= TC_CTRLA_ENABLE;
-
- while (SAMD_TC3->STATUS.bit.SYNCBUSY == 1);
-
- _callback = callback;
-
- if (_timerNumber == TIMER_TC3)
- TC3_callback = callback;
- else if (_timerNumber == TIMER_TC4)
- TC4_callback = callback;
- else if (_timerNumber == TIMER_TC5)
- TC5_callback = callback;
- }
- else if ( (_timerNumber == TIMER_TCC) ||(_timerNumber == TIMER_TCC1) || (_timerNumber == TIMER_TCC2) )
- {
- REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TC_GCLK_ID[_timerNumber]));
-
- while ( GCLK->STATUS.bit.SYNCBUSY == 1 );
-
- TISR_LOGWARN3(F("SAMDTimerInterrupt: F_CPU (MHz) ="), F_CPU/1000000, F(", TIMER_HZ ="), TIMER_HZ/1000000);
-
- if (_timerNumber == TIMER_TCC)
- {
- TISR_LOGWARN3(F("TCC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TCC0 = 0x"), String((uint32_t) TCC0, HEX));
- }
- else if (_timerNumber == TIMER_TCC1)
- {
- TISR_LOGWARN3(F("TCC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TCC1 = 0x"), String((uint32_t) TCC1, HEX));
- }
- else if (_timerNumber == TIMER_TCC2)
- {
- TISR_LOGWARN3(F("TCC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TCC2 = 0x"), String((uint32_t) TCC2, HEX));
- }
-
- SAMD_TCC->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TC
-
- while (SAMD_TCC->SYNCBUSY.bit.ENABLE == 1); // wait for sync
-
- setPeriod_TIMER_TCC(_period);
-
- // Use match mode so that the timer counter resets when the count matches the compare register
- SAMD_TCC->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ; // Set wave form configuration
-
- while (SAMD_TCC->SYNCBUSY.bit.WAVE == 1); // wait for sync
-
- // Enable the compare interrupt
- SAMD_TCC->INTENSET.reg = 0;
- SAMD_TCC->INTENSET.bit.OVF = 1;
- SAMD_TCC->INTENSET.bit.MC0 = 1;
-
- NVIC_EnableIRQ(TIMER_IRQ[_timerNumber]);
-
- SAMD_TCC->CTRLA.reg |= TCC_CTRLA_ENABLE;
-
- while (SAMD_TCC->SYNCBUSY.bit.ENABLE == 1); // wait for sync
-
- _callback = callback;
-
- if (_timerNumber == TIMER_TCC)
- TCC_callback = callback;
- else if (_timerNumber == TIMER_TCC1)
- TCC1_callback = callback;
- else if (_timerNumber == TIMER_TCC2)
- TCC2_callback = callback;
- }
-
- return true;
- }
+ }
+
+ REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (
+ TC_GCLK_ID[_timerNumber]));
+
+ while ( GCLK->STATUS.bit.SYNCBUSY == 1 );
+
+ TISR_LOGWARN3(F("SAMDTimerInterrupt: F_CPU (MHz) ="), F_CPU / 1000000, F(", TIMER_HZ ="), TIMER_HZ / 1000000);
+
+ if (_timerNumber == TIMER_TC3)
+ {
+ TISR_LOGWARN3(F("TC3_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC3 = 0x"),
+ String((uint32_t) TC3, HEX));
+ }
+ else if (_timerNumber == TIMER_TC4)
+ {
+ TISR_LOGWARN3(F("TC4_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC4 = 0x"),
+ String((uint32_t) TC4, HEX));
+ }
+ else if (_timerNumber == TIMER_TC5)
+ {
+ TISR_LOGWARN3(F("TC5_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TC5 = 0x"),
+ String((uint32_t) TC5, HEX));
+ }
+
+ SAMD_TC3->CTRLA.reg &= ~TC_CTRLA_ENABLE;
+
+ // Use the 16-bit timer
+ SAMD_TC3->CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
+
+ while (SAMD_TC3->STATUS.bit.SYNCBUSY == 1);
+
+ // Use match mode so that the timer counter resets when the count matches the compare register
+ SAMD_TC3->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
+
+ while (SAMD_TC3->STATUS.bit.SYNCBUSY == 1);
+
+ setPeriod_TIMER_TC3(_period);
+
+ // Enable the compare interrupt
+ SAMD_TC3->INTENSET.reg = 0;
+ SAMD_TC3->INTENSET.bit.MC0 = 1;
+
+ NVIC_EnableIRQ(TIMER_IRQ[_timerNumber]);
+
+ SAMD_TC3->CTRLA.reg |= TC_CTRLA_ENABLE;
+
+ while (SAMD_TC3->STATUS.bit.SYNCBUSY == 1);
+
+ _callback = callback;
+
+ if (_timerNumber == TIMER_TC3)
+ TC3_callback = callback;
+ else if (_timerNumber == TIMER_TC4)
+ TC4_callback = callback;
+ else if (_timerNumber == TIMER_TC5)
+ TC5_callback = callback;
+ }
+ else if ( (_timerNumber == TIMER_TCC) || (_timerNumber == TIMER_TCC1) || (_timerNumber == TIMER_TCC2) )
+ {
+ REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TC_GCLK_ID[_timerNumber]));
+
+ while ( GCLK->STATUS.bit.SYNCBUSY == 1 );
+
+ TISR_LOGWARN3(F("SAMDTimerInterrupt: F_CPU (MHz) ="), F_CPU / 1000000, F(", TIMER_HZ ="), TIMER_HZ / 1000000);
+
+ if (_timerNumber == TIMER_TCC)
+ {
+ TISR_LOGWARN3(F("TCC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TCC0 = 0x"),
+ String((uint32_t) TCC0, HEX));
+ }
+ else if (_timerNumber == TIMER_TCC1)
+ {
+ TISR_LOGWARN3(F("TCC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TCC1 = 0x"),
+ String((uint32_t) TCC1, HEX));
+ }
+ else if (_timerNumber == TIMER_TCC2)
+ {
+ TISR_LOGWARN3(F("TCC_Timer::startTimer _Timer = 0x"), String((uint32_t) _SAMDTimer, HEX), F(", TCC2 = 0x"),
+ String((uint32_t) TCC2, HEX));
+ }
+
+ SAMD_TCC->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // Disable TC
+
+ while (SAMD_TCC->SYNCBUSY.bit.ENABLE == 1); // wait for sync
+
+ setPeriod_TIMER_TCC(_period);
+
+ // Use match mode so that the timer counter resets when the count matches the compare register
+ SAMD_TCC->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ; // Set wave form configuration
+
+ while (SAMD_TCC->SYNCBUSY.bit.WAVE == 1); // wait for sync
+
+ // Enable the compare interrupt
+ SAMD_TCC->INTENSET.reg = 0;
+ SAMD_TCC->INTENSET.bit.OVF = 1;
+ SAMD_TCC->INTENSET.bit.MC0 = 1;
+
+ NVIC_EnableIRQ(TIMER_IRQ[_timerNumber]);
+
+ SAMD_TCC->CTRLA.reg |= TCC_CTRLA_ENABLE;
+
+ while (SAMD_TCC->SYNCBUSY.bit.ENABLE == 1); // wait for sync
+
+ _callback = callback;
+
+ if (_timerNumber == TIMER_TCC)
+ TCC_callback = callback;
+ else if (_timerNumber == TIMER_TCC1)
+ TCC1_callback = callback;
+ else if (_timerNumber == TIMER_TCC2)
+ TCC2_callback = callback;
+ }
+
+ return true;
+ }
////////////////////////////////////////////////////
@@ -944,23 +955,23 @@ class SAMDTimerInterrupt
{
return setFrequency((float) (1000000.0f / interval), callback);
}
-
+
////////////////////////////////////////////////////
-
+
// interval (in milliseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be added in the future by adding similar functions here or to SAMD-hal-timer.c
bool setInterval_MS(const float& interval, timerCallback callback)
{
return setFrequency((float) (1000.0f / interval), callback);
}
-
+
////////////////////////////////////////////////////
bool attachInterrupt(const float& frequency, timerCallback callback)
{
return setFrequency(frequency, callback);
}
-
+
////////////////////////////////////////////////////
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
@@ -969,68 +980,68 @@ class SAMDTimerInterrupt
{
return setFrequency( (float) ( 1000000.0f / interval), callback);
}
-
+
////////////////////////////////////////////////////
-
+
// interval (in milliseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be added in the future by adding similar functions here or to SAMD-hal-timer.c
bool attachInterruptInterval_MS(const float& interval, timerCallback callback)
{
return setFrequency( (float) ( 1000.0f / interval), callback);
}
-
+
////////////////////////////////////////////////////
void detachInterrupt()
{
// Disable Interrupt
- NVIC_DisableIRQ(TIMER_IRQ[_timerNumber]);
+ NVIC_DisableIRQ(TIMER_IRQ[_timerNumber]);
}
-
+
////////////////////////////////////////////////////
void disableTimer()
{
// Disable Timer
if ( (_timerNumber == TIMER_TC3) || (_timerNumber == TIMER_TC4) || (_timerNumber == TIMER_TC5) )
- {
+ {
// Disable TCx
SAMD_TC3->CTRLA.reg &= ~TC_CTRLA_ENABLE;
}
- else if ( (_timerNumber == TIMER_TCC) ||(_timerNumber == TIMER_TCC1) || (_timerNumber == TIMER_TCC2) )
- {
+ else if ( (_timerNumber == TIMER_TCC) || (_timerNumber == TIMER_TCC1) || (_timerNumber == TIMER_TCC2) )
+ {
// Disable TCCx
SAMD_TCC->CTRLA.reg &= ~TCC_CTRLA_ENABLE;
}
}
-
+
////////////////////////////////////////////////////
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void reattachInterrupt()
{
// Disable Interrupt
- NVIC_EnableIRQ(TIMER_IRQ[_timerNumber]);
+ NVIC_EnableIRQ(TIMER_IRQ[_timerNumber]);
}
-
+
////////////////////////////////////////////////////
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void enableTimer()
- {
+ {
// Enable Timer
if ( (_timerNumber == TIMER_TC3) || (_timerNumber == TIMER_TC4) || (_timerNumber == TIMER_TC5) )
- {
+ {
// Enable TCx
SAMD_TC3->CTRLA.reg |= TC_CTRLA_ENABLE;
}
- else if ( (_timerNumber == TIMER_TCC) ||(_timerNumber == TIMER_TCC1) || (_timerNumber == TIMER_TCC2) )
- {
+ else if ( (_timerNumber == TIMER_TCC) || (_timerNumber == TIMER_TCC1) || (_timerNumber == TIMER_TCC2) )
+ {
// Enable TCCx
SAMD_TCC->CTRLA.reg |= TCC_CTRLA_ENABLE;
}
}
-
+
////////////////////////////////////////////////////
// Just stop clock source, clear the count
@@ -1039,7 +1050,7 @@ class SAMDTimerInterrupt
// TODO, clear the count
disableTimer();
}
-
+
////////////////////////////////////////////////////
// Just reconnect clock source, start current count from 0
@@ -1048,83 +1059,84 @@ class SAMDTimerInterrupt
// TODO, clear the count
enableTimer();
}
-
+
////////////////////////////////////////////////////
-
- private:
-
+
+ private:
+
////////////////////////////////////////////////////
-
+
void setPeriod_TIMER_TC3(const float& period)
{
TcCount16* _Timer = (TcCount16*) _SAMDTimer;
- _Timer->CTRLA.reg &= ~( TC_CTRLA_ENABLE | TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCALER_DIV64 |
- TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_PRESCALER_DIV4 | TC_CTRLA_PRESCALER_DIV2 | TC_CTRLA_PRESCALER_DIV1 );
-
+ _Timer->CTRLA.reg &= ~( TC_CTRLA_ENABLE | TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_PRESCALER_DIV256 |
+ TC_CTRLA_PRESCALER_DIV64 |
+ TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_PRESCALER_DIV4 | TC_CTRLA_PRESCALER_DIV2 | TC_CTRLA_PRESCALER_DIV1 );
+
while (_Timer->STATUS.bit.SYNCBUSY == 1);
-
- if (period > 300000)
+
+ if (period > 300000)
{
// Set prescaler to 1024
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024;
_prescaler = 1024;
- }
- else if (80000 < period && period <= 300000)
+ }
+ else if (80000 < period && period <= 300000)
{
// Set prescaler to 256
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV256;
_prescaler = 256;
- }
- else if (20000 < period && period <= 80000)
+ }
+ else if (20000 < period && period <= 80000)
{
// Set prescaler to 64
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV64;
_prescaler = 64;
- }
- else if (10000 < period && period <= 20000)
+ }
+ else if (10000 < period && period <= 20000)
{
// Set prescaler to 16
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16;
_prescaler = 16;
- }
- else if (5000 < period && period <= 10000)
+ }
+ else if (5000 < period && period <= 10000)
{
// Set prescaler to 8
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV8;
_prescaler = 8;
- }
- else if (2500 < period && period <= 5000)
+ }
+ else if (2500 < period && period <= 5000)
{
// Set prescaler to 4
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV4;
_prescaler = 4;
- }
- else if (1000 < period && period <= 2500)
+ }
+ else if (1000 < period && period <= 2500)
{
// Set prescaler to 2
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV2;
_prescaler = 2;
- }
- else if (period <= 1000)
+ }
+ else if (period <= 1000)
{
// Set prescaler to 1
_Timer->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1;
_prescaler = 1;
}
-
+
while (_Timer->STATUS.bit.SYNCBUSY == 1);
_compareValue = (int)(TIMER_HZ / (_prescaler / (period / 1000000.0))) - 1;
-
+
// Make sure the count is in a proportional position to where it was
// to prevent any jitter or disconnect when changing the compare value.
_Timer->COUNT.reg = map(_Timer->COUNT.reg, 0, _Timer->CC[0].reg, 0, _compareValue);
_Timer->CC[0].reg = _compareValue;
-
+
while (_Timer->STATUS.bit.SYNCBUSY == 1);
-
+
if (_timerNumber == TIMER_TC3)
{
TISR_LOGDEBUG3(F("SAMD21 TC3 period ="), period, F(", _prescaler ="), _prescaler);
@@ -1137,74 +1149,75 @@ class SAMDTimerInterrupt
{
TISR_LOGDEBUG3(F("SAMD21 TC5 period ="), period, F(", _prescaler ="), _prescaler);
}
-
+
TISR_LOGDEBUG1(F("_compareValue ="), _compareValue);
}
-
+
////////////////////////////////////////////////////
-
+
void setPeriod_TIMER_TCC(const float& period)
{
Tcc* _Timer = (Tcc*) _SAMDTimer;
- _Timer->CTRLA.reg &= ~( TCC_CTRLA_ENABLE | TCC_CTRLA_PRESCALER_DIV1024 | TCC_CTRLA_PRESCALER_DIV256 | TCC_CTRLA_PRESCALER_DIV64 |
- TCC_CTRLA_PRESCALER_DIV16 | TCC_CTRLA_PRESCALER_DIV4 | TCC_CTRLA_PRESCALER_DIV2 | TCC_CTRLA_PRESCALER_DIV1 );
-
+ _Timer->CTRLA.reg &= ~( TCC_CTRLA_ENABLE | TCC_CTRLA_PRESCALER_DIV1024 | TCC_CTRLA_PRESCALER_DIV256 |
+ TCC_CTRLA_PRESCALER_DIV64 |
+ TCC_CTRLA_PRESCALER_DIV16 | TCC_CTRLA_PRESCALER_DIV4 | TCC_CTRLA_PRESCALER_DIV2 | TCC_CTRLA_PRESCALER_DIV1 );
+
while (_Timer->SYNCBUSY.bit.ENABLE == 1);
-
- if (period > 300000)
+
+ if (period > 300000)
{
// Set prescaler to 1024
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1024;
_prescaler = 1024;
- }
- else if (80000 < period && period <= 300000)
+ }
+ else if (80000 < period && period <= 300000)
{
// Set prescaler to 256
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV256;
_prescaler = 256;
- }
- else if (20000 < period && period <= 80000)
+ }
+ else if (20000 < period && period <= 80000)
{
// Set prescaler to 64
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV64;
_prescaler = 64;
- }
- else if (10000 < period && period <= 20000)
+ }
+ else if (10000 < period && period <= 20000)
{
// Set prescaler to 16
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV16;
_prescaler = 16;
- }
- else if (5000 < period && period <= 10000)
+ }
+ else if (5000 < period && period <= 10000)
{
// Set prescaler to 8
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV8;
_prescaler = 8;
- }
- else if (2500 < period && period <= 5000)
+ }
+ else if (2500 < period && period <= 5000)
{
// Set prescaler to 4
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV4;
_prescaler = 4;
- }
- else if (1000 < period && period <= 2500)
+ }
+ else if (1000 < period && period <= 2500)
{
// Set prescaler to 2
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV2;
_prescaler = 2;
- }
- else if (period <= 1000)
+ }
+ else if (period <= 1000)
{
// Set prescaler to 1
_Timer->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1;
_prescaler = 1;
}
-
+
_compareValue = (int)(TIMER_HZ / (_prescaler / (period / 1000000))) - 1;
- _Timer->PER.reg = _compareValue;
-
+ _Timer->PER.reg = _compareValue;
+
while (_Timer->SYNCBUSY.bit.PER == 1);
// Make sure the count is in a proportional position to where it was
@@ -1212,9 +1225,9 @@ class SAMDTimerInterrupt
//_Timer->COUNT.reg = map(_Timer->COUNT.reg, 0, _Timer->CC[0].reg, 0, _compareValue);
_Timer->CC[0].reg = 0xFFF;
-
+
while (_Timer->SYNCBUSY.bit.CC0 == 1);
-
+
if (_timerNumber == TIMER_TCC)
{
TISR_LOGDEBUG3(F("SAMD21 TCC period ="), period, F(", _prescaler ="), _prescaler);
@@ -1227,10 +1240,10 @@ class SAMDTimerInterrupt
{
TISR_LOGDEBUG3(F("SAMD21 TCC2 period ="), period, F(", _prescaler ="), _prescaler);
}
-
+
TISR_LOGDEBUG1(F("_compareValue ="), _compareValue);
}
-
+
////////////////////////////////////////////////////
}; // class SAMDTimerInterrupt
diff --git a/src/SAMDUETimerInterrupt_Generic.h b/src/SAMDUETimerInterrupt_Generic.h
index e2c48cb1..fa873c4a 100644
--- a/src/SAMDUETimerInterrupt_Generic.h
+++ b/src/SAMDUETimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -53,12 +55,12 @@
#ifndef SAMDUE_TIMER_INTERRUPT_VERSION
#define SAMDUE_TIMER_INTERRUPT_VERSION "SAMDUETimerInterrupt v1.3.0"
-
+
#define SAMDUE_TIMER_INTERRUPT_VERSION_MAJOR 1
#define SAMDUE_TIMER_INTERRUPT_VERSION_MINOR 3
#define SAMDUE_TIMER_INTERRUPT_VERSION_PATCH 0
- #define SAMDUE_TIMER_INTERRUPT_VERSION_INT 1003000
+ #define SAMDUE_TIMER_INTERRUPT_VERSION_INT 1003000
#endif
#ifndef TIMER_INTERRUPT_DEBUG
@@ -74,19 +76,19 @@
#define BOARD_NAME "SAM DUE"
/*
- This fixes compatibility for Arduino Servo Library.
- Uncomment to make it compatible.
+ This fixes compatibility for Arduino Servo Library.
+ Uncomment to make it compatible.
- Note that:
- + Timers: 0,2,3,4,5 WILL NOT WORK, and will
- neither be accessible by Timer0,...
+ Note that:
+ + Timers: 0,2,3,4,5 WILL NOT WORK, and will
+ neither be accessible by Timer0,...
*/
-// #define USING_SERVO_LIB true
+// #define USING_SERVO_LIB true
#if USING_SERVO_LIB
- // Arduino Servo library uses timers 0,2,3,4,5.
- // You must have `#define USING_SERVO_LIB true` in your sketch.
- #warning Using Servo Library, Timer0, 2, 3, 4 and 5 not available
+ // Arduino Servo library uses timers 0,2,3,4,5.
+ // You must have `#define USING_SERVO_LIB true` in your sketch.
+ #warning Using Servo Library, Timer0, 2, 3, 4 and 5 not available
#endif
#if defined TC2
@@ -99,16 +101,16 @@ typedef void (*timerCallback) ();
typedef struct
{
- Tc *tc;
- uint32_t channel;
- IRQn_Type irq;
+ Tc *tc;
+ uint32_t channel;
+ IRQn_Type irq;
} DueTimerIRQInfo;
typedef struct
{
- const char* tc;
- uint32_t channel;
- const char* irq;
+ const char* tc;
+ uint32_t channel;
+ const char* irq;
} DueTimerIRQInfoStr;
// For printing info of selected Timer
@@ -159,14 +161,14 @@ class DueTimerInterrupt
static const DueTimerIRQInfo Timers[NUM_TIMERS];
public:
-
+
DueTimerInterrupt(const unsigned short& timer) : _timerNumber(timer)
{
/*
The constructor of the class DueTimerInterrupt
*/
}
-
+
static DueTimerInterrupt getAvailable() __attribute__((always_inline))
{
/*
@@ -176,30 +178,31 @@ class DueTimerInterrupt
for (int i = 0; i < NUM_TIMERS; i++)
{
if (!_callbacks[i])
- {
+ {
TISR_LOGWARN3(F("Using Timer("), i, F(") ="), TimersInfo[i].tc);
TISR_LOGWARN3(F("Channel ="), TimersInfo[i].channel, F(", IRQ ="), TimersInfo[i].irq);
- return DueTimerInterrupt(i);
+ return DueTimerInterrupt(i);
}
}
// Default, return Timer0;
return DueTimerInterrupt(0);
}
-
- DueTimerInterrupt& attachInterruptInterval(const double& microseconds, timerCallback callback) __attribute__((always_inline))
+
+ DueTimerInterrupt& attachInterruptInterval(const double& microseconds,
+ timerCallback callback) __attribute__((always_inline))
{
_callbacks[_timerNumber] = callback;
return startTimer(microseconds);
}
-
+
DueTimerInterrupt& attachInterrupt(const float& frequency, timerCallback callback) __attribute__((always_inline))
{
return attachInterruptInterval((double) (1000000.0f / frequency), callback);
}
-
+
DueTimerInterrupt& attachInterrupt(timerCallback callback) __attribute__((always_inline))
{
/*
@@ -210,7 +213,7 @@ class DueTimerInterrupt
return *this;
}
-
+
DueTimerInterrupt& detachInterrupt() __attribute__((always_inline))
{
/*
@@ -223,8 +226,8 @@ class DueTimerInterrupt
return *this;
}
-
- DueTimerInterrupt& startTimer(const double& microseconds= -1) __attribute__((always_inline))
+
+ DueTimerInterrupt& startTimer(const double& microseconds = -1) __attribute__((always_inline))
{
/*
Start the timer
@@ -246,8 +249,8 @@ class DueTimerInterrupt
return *this;
}
-
- DueTimerInterrupt& restartTimer(const double& microseconds= -1) __attribute__((always_inline))
+
+ DueTimerInterrupt& restartTimer(const double& microseconds = -1) __attribute__((always_inline))
{
/*
Restart the timer
@@ -268,7 +271,7 @@ class DueTimerInterrupt
{
setPeriod(microseconds);
}
-
+
NVIC_ClearPendingIRQ(Timers[_timerNumber].irq);
NVIC_EnableIRQ(Timers[_timerNumber].irq);
@@ -289,7 +292,7 @@ class DueTimerInterrupt
return *this;
}
-
+
DueTimerInterrupt& disableTimer()
{
return stopTimer();
@@ -350,7 +353,7 @@ class DueTimerInterrupt
/*
Set the timer frequency (in Hz)
*/
-
+
double freqToUse = frequency;
// Prevent negative frequencies
@@ -383,12 +386,15 @@ class DueTimerInterrupt
case TC_CMR_TCCLKS_TIMER_CLOCK1:
_frequency[_timerNumber] = (double)SystemCoreClock / 2.0 / (double)rc;
break;
+
case TC_CMR_TCCLKS_TIMER_CLOCK2:
_frequency[_timerNumber] = (double)SystemCoreClock / 8.0 / (double)rc;
break;
+
case TC_CMR_TCCLKS_TIMER_CLOCK3:
_frequency[_timerNumber] = (double)SystemCoreClock / 32.0 / (double)rc;
break;
+
default: // TC_CMR_TCCLKS_TIMER_CLOCK4
_frequency[_timerNumber] = (double)SystemCoreClock / 128.0 / (double)rc;
break;
@@ -398,19 +404,19 @@ class DueTimerInterrupt
// in UP mode with automatic trigger on RC Compare
// and sets it up with the determined internal clock as clock input.
TC_Configure(timerIRQInfo.tc, timerIRQInfo.channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | clock);
-
+
// Reset counter and fire interrupt when RC value is matched:
TC_SetRC(timerIRQInfo.tc, timerIRQInfo.channel, rc);
-
+
// Enable the RC Compare Interrupt.
timerIRQInfo.tc->TC_CHANNEL[timerIRQInfo.channel].TC_IER = TC_IER_CPCS;
-
+
// ... and disable all others.
timerIRQInfo.tc->TC_CHANNEL[timerIRQInfo.channel].TC_IDR = ~TC_IER_CPCS;
return *this;
}
-
+
DueTimerInterrupt& setPeriod(const double& microseconds) __attribute__((always_inline))
{
/*
@@ -419,12 +425,12 @@ class DueTimerInterrupt
// Convert period in microseconds to frequency in Hz
double frequency = 1000000.0 / microseconds;
-
+
setFrequency(frequency);
return *this;
}
-
+
DueTimerInterrupt& setInterval(const double& microseconds) __attribute__((always_inline))
{
return setPeriod(microseconds);
@@ -445,7 +451,7 @@ class DueTimerInterrupt
*/
return 1.0 / getFrequency() * 1000000;
}
-
+
uint16_t getTimerNumber()
{
return _timerNumber;
@@ -483,31 +489,31 @@ const DueTimerIRQInfo DueTimerInterrupt::Timers[NUM_TIMERS] =
// Fix for compatibility with Servo library
#if USING_SERVO_LIB
- // Set _callbacks as used, allowing DueTimerInterrupt::getAvailable() to work
- void (*DueTimerInterrupt::_callbacks[NUM_TIMERS])() =
- {
- (void (*)()) 1, // Timer 0 - Occupied
- (void (*)()) 0, // Timer 1
- (void (*)()) 1, // Timer 2 - Occupied
- (void (*)()) 1, // Timer 3 - Occupied
- (void (*)()) 1, // Timer 4 - Occupied
- (void (*)()) 1, // Timer 5 - Occupied
-
- #if defined(TC2)
- (void (*)()) 0, // Timer 6
- (void (*)()) 0, // Timer 7
- (void (*)()) 0 // Timer 8
- #endif
- };
+// Set _callbacks as used, allowing DueTimerInterrupt::getAvailable() to work
+void (*DueTimerInterrupt::_callbacks[NUM_TIMERS])() =
+{
+ (void (*)()) 1, // Timer 0 - Occupied
+ (void (*)()) 0, // Timer 1
+ (void (*)()) 1, // Timer 2 - Occupied
+ (void (*)()) 1, // Timer 3 - Occupied
+ (void (*)()) 1, // Timer 4 - Occupied
+ (void (*)()) 1, // Timer 5 - Occupied
+
+#if defined(TC2)
+ (void (*)()) 0, // Timer 6
+ (void (*)()) 0, // Timer 7
+ (void (*)()) 0 // Timer 8
+#endif
+};
#else
- void (*DueTimerInterrupt::_callbacks[NUM_TIMERS])() = {};
+void (*DueTimerInterrupt::_callbacks[NUM_TIMERS])() = {};
#endif
#if defined(TC2)
- double DueTimerInterrupt::_frequency[NUM_TIMERS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1};
+double DueTimerInterrupt::_frequency[NUM_TIMERS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1};
#else
- double DueTimerInterrupt::_frequency[NUM_TIMERS] = { -1, -1, -1, -1, -1, -1};
+double DueTimerInterrupt::_frequency[NUM_TIMERS] = { -1, -1, -1, -1, -1, -1};
#endif
/*
@@ -532,26 +538,26 @@ DueTimerInterrupt Timer1(1);
DueTimerInterrupt Timer8(8);
#endif
-DueTimerInterrupt DueTimerPtr[NUM_TIMERS] =
-{
+DueTimerInterrupt DueTimerPtr[NUM_TIMERS] =
+{
#if ( !USING_SERVO_LIB || !defined(USING_SERVO_LIB) )
Timer0,
-#endif
+#endif
Timer1,
-
-#if ( !USING_SERVO_LIB || !defined(USING_SERVO_LIB) )
+
+#if ( !USING_SERVO_LIB || !defined(USING_SERVO_LIB) )
Timer2,
Timer3,
Timer4,
Timer5,
#endif
-
-#if defined(TC2)
- Timer6,
- Timer7,
+
+#if defined(TC2)
+ Timer6,
+ Timer7,
Timer8
-#endif
+#endif
};
///////////////////////////////////////////////////////////////////////
diff --git a/src/STM32TimerInterrupt_Generic.h b/src/STM32TimerInterrupt_Generic.h
index 21e07cc7..5f967f0d 100644
--- a/src/STM32TimerInterrupt_Generic.h
+++ b/src/STM32TimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -47,12 +49,12 @@
#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
defined(STM32WB) || defined(STM32MP1) || defined(STM32L5) )
- #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
+#error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
#endif
#ifndef STM32_TIMER_INTERRUPT_VERSION
#define STM32_TIMER_INTERRUPT_VERSION "STM32TimerInterrupt v1.3.0"
-
+
#define STM32_TIMER_INTERRUPT_VERSION_MAJOR 1
#define STM32_TIMER_INTERRUPT_VERSION_MINOR 3
#define STM32_TIMER_INTERRUPT_VERSION_PATCH 0
@@ -88,12 +90,12 @@ class STM32TimerInterrupt
STM32TimerInterrupt(TIM_TypeDef* timer)
{
_timer = timer;
-
+
_hwTimer = new HardwareTimer(_timer);
-
+
_callback = NULL;
};
-
+
~STM32TimerInterrupt()
{
if (_hwTimer)
@@ -106,13 +108,14 @@ class STM32TimerInterrupt
{
// select timer frequency is 1MHz for better accuracy and use MICROSEC_FORMAT. We don't use 16-bit prescaler for now.
// Will use later if very low frequency is needed.
- #define TIM_CLOCK_FREQ (1000000.0f)
-
+#define TIM_CLOCK_FREQ (1000000.0f)
+
_frequency = frequency;
-
+
_timerCount = (uint32_t) ( TIM_CLOCK_FREQ / frequency );
-
- TISR_LOGWARN3(F("Timer Input Freq (Hz) ="), _hwTimer->getTimerClkFreq(), F(", Timer Clock Frequency ="), TIM_CLOCK_FREQ);
+
+ TISR_LOGWARN3(F("Timer Input Freq (Hz) ="), _hwTimer->getTimerClkFreq(), F(", Timer Clock Frequency ="),
+ TIM_CLOCK_FREQ);
TISR_LOGWARN3(F("Timer Frequency ="), _frequency, F(", _count ="), (uint32_t) (_timerCount));
diff --git a/src/TeensyTimerInterrupt_Generic.h b/src/TeensyTimerInterrupt_Generic.h
index ebf6c45c..21064e93 100644
--- a/src/TeensyTimerInterrupt_Generic.h
+++ b/src/TeensyTimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
@@ -50,12 +52,12 @@
#ifndef TEENSY_TIMER_INTERRUPT_VERSION
#define TEENSY_TIMER_INTERRUPT_VERSION "TeensyTimerInterrupt v1.3.0"
-
+
#define TEENSY_TIMER_INTERRUPT_VERSION_MAJOR 1
#define TEENSY_TIMER_INTERRUPT_VERSION_MINOR 3
#define TEENSY_TIMER_INTERRUPT_VERSION_PATCH 0
- #define TEENSY_TIMER_INTERRUPT_VERSION_INT 1003000
+ #define TEENSY_TIMER_INTERRUPT_VERSION_INT 1003000
#endif
#ifndef TIMER_INTERRUPT_DEBUG
@@ -74,7 +76,7 @@ typedef enum
TEENSY_TIMER_3 = 1,
TEENSY_MAX_TIMER
} TeensyTimerNumber;
-
+
typedef TeensyTimerInterrupt TeensyTimer;
typedef void (*timerCallback) ();
@@ -83,25 +85,25 @@ typedef void (*timerCallback) ();
#if ( defined(__arm__) && defined(TEENSYDUINO) && defined(__IMXRT1062__) )
- // For Teensy 4.0/4.1
- #if defined(ARDUINO_TEENSY41)
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 4.1
- #endif
-
- #ifndef BOARD_NAME
- #define BOARD_NAME "Teensy 4.1"
- #endif
- #else
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 4.0
- #endif
-
- #ifndef BOARD_NAME
- #define BOARD_NAME "Teensy 4.0"
- #endif
+// For Teensy 4.0/4.1
+#if defined(ARDUINO_TEENSY41)
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 4.1
+ #endif
+
+ #ifndef BOARD_NAME
+ #define BOARD_NAME "Teensy 4.1"
#endif
-
+#else
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 4.0
+ #endif
+
+ #ifndef BOARD_NAME
+ #define BOARD_NAME "Teensy 4.0"
+ #endif
+#endif
+
class TeensyTimerInterrupt;
static void ext_isr();
@@ -118,21 +120,21 @@ class TeensyTimerInterrupt
// properties
//static unsigned short pwmPeriod;
//static unsigned char clockSelectBits;
-
+
uint8_t _timer = TEENSY_TIMER_1;
-
+
IRQ_NUMBER_t _timer_IRQ;
timerCallback _callback; // pointer to the callback function
-
+
float _frequency; // Timer frequency
uint32_t _timerCount; // count to activate timer
-
+
uint32_t _prescale = 0;
uint32_t _realPeriod;
-
+
public:
-
+
TeensyTimerInterrupt(uint8_t timer = TEENSY_TIMER_1) __attribute__((always_inline))
{
if (timer < TEENSY_MAX_TIMER)
@@ -142,24 +144,24 @@ class TeensyTimerInterrupt
// Error out of range, force to use TEENSY_TIMER_1
_timer = TEENSY_TIMER_1;
}
-
+
_timer_IRQ = teensy_timers_irq[_timer];
-
+
// Update to use in IRQHandler
TeensyTimers[_timer] = this;
-
+
_callback = NULL;
}
//////////////////////////////////////////////////////////
-
+
~TeensyTimerInterrupt() __attribute__((always_inline))
{
TeensyTimers[_timer] = NULL;
}
//////////////////////////////////////////////////////////
-
+
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c
bool setFrequency(const float& frequency, timerCallback callback) __attribute__((always_inline))
@@ -168,23 +170,23 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
// Interval (in microseconds)
// For Teensy 4.0/4.1, F_BUS_ACTUAL = 150 MHz => max interval/period is only 55922 us (~17.9 Hz)
bool setInterval(const unsigned long& interval, timerCallback callback) __attribute__((always_inline))
- {
+ {
// This function will be called when time out interrupt will occur
- if (callback)
+ if (callback)
{
- _callback = callback;
- }
- else
+ _callback = callback;
+ }
+ else
{
- TISR_LOGERROR(F("TeensyTimerInterrupt: ERROR: NULL callback function pointer."));
-
- return false;
+ TISR_LOGERROR(F("TeensyTimerInterrupt: ERROR: NULL callback function pointer."));
+
+ return false;
}
-
+
uint32_t period = ((float) F_BUS_ACTUAL / 2000000) * (float) interval;
uint32_t prescale = 0;
@@ -194,12 +196,12 @@ class TeensyTimerInterrupt
if (++prescale > 7)
{
- prescale = 7;
- period = 32767;
+ prescale = 7;
+ period = 32767;
break;
}
}
-
+
// when F_BUS is 150 MHz, longest period (_realPeriod) is 55922.3467 us (~17.881939 Hz)
// 55922.3467 us = (32767 * 2000000) / (150000000 >> 7)
_realPeriod = (uint32_t) ((period * 2000000.0f) / (F_BUS_ACTUAL >> prescale));
@@ -208,19 +210,19 @@ class TeensyTimerInterrupt
if (_timer == TEENSY_TIMER_1)
{
- TISR_LOGWARN1(F("TEENSY_TIMER_1: , F_BUS_ACTUAL (MHz) ="), F_BUS_ACTUAL/1000000);
+ TISR_LOGWARN1(F("TEENSY_TIMER_1: , F_BUS_ACTUAL (MHz) ="), F_BUS_ACTUAL / 1000000);
}
else if (_timer == TEENSY_TIMER_3)
{
- TISR_LOGWARN1(F("TEENSY_TIMER_3: , F_BUS_ACTUAL (MHz) ="), F_BUS_ACTUAL/1000000);
+ TISR_LOGWARN1(F("TEENSY_TIMER_3: , F_BUS_ACTUAL (MHz) ="), F_BUS_ACTUAL / 1000000);
}
-
+
TISR_LOGWARN3(F("Request interval ="), interval, F(", actual interval (us) ="), _realPeriod);
TISR_LOGWARN3(F("Prescale ="), _prescale, F(", _timerCount ="), _timerCount);
-
+
if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8); // logic high = fault
FLEXPWM1_FSTS0 = 0x0008; // clear fault status
FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
@@ -239,25 +241,25 @@ class TeensyTimerInterrupt
{
///////////// TEENSY_TIMER_3 code ////////////////////////
FLEXPWM2_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(4); // logic high = fault
- FLEXPWM2_FSTS0 = 0x0008; // clear fault status
- FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_CLDOK(4);
- FLEXPWM2_SM2CTRL2 = FLEXPWM_SMCTRL2_INDEP;
- FLEXPWM2_SM2CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale);
- FLEXPWM2_SM2INIT = -period;
- FLEXPWM2_SM2VAL0 = 0;
- FLEXPWM2_SM2VAL1 = period;
- FLEXPWM2_SM2VAL2 = 0;
- FLEXPWM2_SM2VAL3 = 0;
- FLEXPWM2_SM2VAL4 = 0;
- FLEXPWM2_SM2VAL5 = 0;
- FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_LDOK(4) | FLEXPWM_MCTRL_RUN(4);
+ FLEXPWM2_FSTS0 = 0x0008; // clear fault status
+ FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_CLDOK(4);
+ FLEXPWM2_SM2CTRL2 = FLEXPWM_SMCTRL2_INDEP;
+ FLEXPWM2_SM2CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale);
+ FLEXPWM2_SM2INIT = -period;
+ FLEXPWM2_SM2VAL0 = 0;
+ FLEXPWM2_SM2VAL1 = period;
+ FLEXPWM2_SM2VAL2 = 0;
+ FLEXPWM2_SM2VAL3 = 0;
+ FLEXPWM2_SM2VAL4 = 0;
+ FLEXPWM2_SM2VAL5 = 0;
+ FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_LDOK(4) | FLEXPWM_MCTRL_RUN(4);
}
-
+
attachInterruptVector(_timer_IRQ, &ext_isr);
-
+
if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_RIE;
}
@@ -265,16 +267,16 @@ class TeensyTimerInterrupt
{
///////////// TEENSY_TIMER_3 code ////////////////////////
FLEXPWM2_SM2STS = FLEXPWM_SMSTS_RF;
- FLEXPWM2_SM2INTEN = FLEXPWM_SMINTEN_RIE;
+ FLEXPWM2_SM2INTEN = FLEXPWM_SMINTEN_RIE;
}
-
+
NVIC_ENABLE_IRQ(_timer_IRQ);
-
+
return true;
}
//////////////////////////////////////////////////////////
-
+
bool attachInterrupt(const float& frequency, timerCallback callback) __attribute__((always_inline))
{
return setInterval((float) (1000000.0f / frequency), callback);
@@ -290,21 +292,21 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
void detachInterrupt() __attribute__((always_inline))
- {
+ {
NVIC_DISABLE_IRQ(_timer_IRQ);
-
+
if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FLEXPWM1_SM3INTEN = 0;
}
else if (_timer == TEENSY_TIMER_3)
{
///////////// TEENSY_TIMER_3 code ////////////////////////
FLEXPWM2_SM2INTEN = 0;
- }
+ }
}
//////////////////////////////////////////////////////////
@@ -315,7 +317,7 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
//****************************
// Run Control
//****************************
@@ -330,18 +332,18 @@ class TeensyTimerInterrupt
void stopTimer() __attribute__((always_inline))
{
if (_timer == TEENSY_TIMER_1)
- {
+ {
TISR_LOGWARN(F("TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FLEXPWM1_MCTRL &= ~FLEXPWM_MCTRL_RUN(8);
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:stopTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
- FLEXPWM2_MCTRL &= ~FLEXPWM_MCTRL_RUN(4);
+ FLEXPWM2_MCTRL &= ~FLEXPWM_MCTRL_RUN(4);
}
}
@@ -356,20 +358,20 @@ class TeensyTimerInterrupt
void resumeTimer() __attribute__((always_inline))
{
-
+
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_RUN(8);
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
- FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_RUN(4);
+ FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_RUN(4);
}
}
@@ -381,14 +383,14 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
uint32_t getPrescale() __attribute__((always_inline))
{
return _prescale;
}
//////////////////////////////////////////////////////////
-
+
// Real (actual) period in us
uint32_t getRealPeriod() __attribute__((always_inline))
{
@@ -396,14 +398,14 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
timerCallback getCallback() __attribute__((always_inline))
{
return _callback;
}
//////////////////////////////////////////////////////////
-
+
IRQ_NUMBER_t getTimerIRQn() __attribute__((always_inline))
{
return _timer_IRQ;
@@ -416,7 +418,7 @@ static void ext_isr()
{
if (TeensyTimers[TEENSY_TIMER_1])
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
(*(TeensyTimers[TEENSY_TIMER_1]->getCallback()))();
}
@@ -434,95 +436,95 @@ static void ext_isr()
// For Teensy 3.x and LC
#elif defined(__arm__) && defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL))
- #ifdef BOARD_NAME
- #undef BOARD_NAME
+#ifdef BOARD_NAME
+ #undef BOARD_NAME
+#endif
+
+#if defined(__MK66FX1M0__)
+ // For Teensy 3.6
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 3.6
+ #endif
+
+ #define BOARD_NAME "Teensy 3.6"
+#elif defined(__MK64FX512__)
+ // For Teensy 3.5
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 3.5
+ #endif
+
+ #define BOARD_NAME "Teensy 3.5"
+#elif defined(__MK20DX256__)
+ // For Teensy 3.2/3.1
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 3.2/3.1
#endif
-
- #if defined(__MK66FX1M0__)
- // For Teensy 3.6
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 3.6
- #endif
-
- #define BOARD_NAME "Teensy 3.6"
- #elif defined(__MK64FX512__)
- // For Teensy 3.5
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 3.5
- #endif
-
- #define BOARD_NAME "Teensy 3.5"
- #elif defined(__MK20DX256__)
- // For Teensy 3.2/3.1
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 3.2/3.1
- #endif
-
- #define BOARD_NAME "Teensy 3.2/3.1"
- #elif defined(__MK20DX128__)
- // For Teensy 3.0
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 3.0
- #endif
-
- #define BOARD_NAME "Teensy 3.0"
- #elif defined(__MKL26Z64__)
- // For Teensy LC
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy LC
- #endif
-
- #define BOARD_NAME "Teensy LC"
+
+ #define BOARD_NAME "Teensy 3.2/3.1"
+#elif defined(__MK20DX128__)
+ // For Teensy 3.0
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 3.0
#endif
- #if defined(KINETISK)
- #define F_TIMER F_BUS
- #elif defined(KINETISL)
- #define F_TIMER (F_PLL/2)
+ #define BOARD_NAME "Teensy 3.0"
+#elif defined(__MKL26Z64__)
+ // For Teensy LC
+ #if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy LC
#endif
- // Teensy 3.0 has only TEENSY_TIMER_1 and IRQ_FTM1, So force to use TEENSY_TIMER_1 and IRQ_FTM1
- #if defined(IRQ_FTM2)
- static IRQ_NUMBER_t teensy_timers_irq [TEENSY_MAX_TIMER] = { IRQ_FTM1, IRQ_FTM2 };
- #else
- static IRQ_NUMBER_t teensy_timers_irq [TEENSY_MAX_TIMER] = { IRQ_FTM1, IRQ_FTM1 };
- #endif
+ #define BOARD_NAME "Teensy LC"
+#endif
- static TeensyTimerInterrupt* TeensyTimers [TEENSY_MAX_TIMER] = { NULL, NULL };
+#if defined(KINETISK)
+ #define F_TIMER F_BUS
+#elif defined(KINETISL)
+ #define F_TIMER (F_PLL/2)
+#endif
+
+// Teensy 3.0 has only TEENSY_TIMER_1 and IRQ_FTM1, So force to use TEENSY_TIMER_1 and IRQ_FTM1
+#if defined(IRQ_FTM2)
+static IRQ_NUMBER_t teensy_timers_irq [TEENSY_MAX_TIMER] = { IRQ_FTM1, IRQ_FTM2 };
+#else
+static IRQ_NUMBER_t teensy_timers_irq [TEENSY_MAX_TIMER] = { IRQ_FTM1, IRQ_FTM1 };
+#endif
+
+static TeensyTimerInterrupt* TeensyTimers [TEENSY_MAX_TIMER] = { NULL, NULL };
//////////////////////////////////////////////////////////
class TeensyTimerInterrupt
{
- // Use only 15 bit resolution. From K66 reference manual, 45.5.7 page 1200:
- // The CPWM pulse width (duty cycle) is determined by 2 x (CnV - CNTIN) and the
- // period is determined by 2 x (MOD - CNTIN). See the following figure. MOD must be
- // kept in the range of 0x0001 to 0x7FFF because values outside this range can produce
- // ambiguous results.
+ // Use only 15 bit resolution. From K66 reference manual, 45.5.7 page 1200:
+ // The CPWM pulse width (duty cycle) is determined by 2 x (CnV - CNTIN) and the
+ // period is determined by 2 x (MOD - CNTIN). See the following figure. MOD must be
+ // kept in the range of 0x0001 to 0x7FFF because values outside this range can produce
+ // ambiguous results.
#undef TIMER_RESOLUTION
#define TIMER_RESOLUTION 32768
-
+
private:
-
+
uint8_t _timer = TEENSY_TIMER_1;
-
+
IRQ_NUMBER_t _timer_IRQ;
timerCallback _callback; // pointer to the callback function
-
+
float _frequency; // Timer frequency
uint32_t _timerCount; // count to activate timer
-
+
uint32_t _prescale = 0;
uint32_t _realPeriod;
-
+
public:
-
+
TeensyTimerInterrupt(uint8_t timer = TEENSY_TIMER_1) __attribute__((always_inline))
{
-
+
#if defined(IRQ_FTM2)
-
+
if (timer < TEENSY_MAX_TIMER)
_timer = timer;
else
@@ -530,29 +532,30 @@ class TeensyTimerInterrupt
// Error out of range, force to use TEENSY_TIMER_1
_timer = TEENSY_TIMER_1;
}
+
#else
// Teensy 3.0 has only TEENSY_TIMER_1 and IRQ_FTM1, So force to use TEENSY_TIMER_1 and IRQ_FTM1
_timer = TEENSY_TIMER_1;
-
+
#endif
-
+
_timer_IRQ = teensy_timers_irq[_timer];
-
+
// Update to use in IRQHandler
TeensyTimers[_timer] = this;
-
+
_callback = NULL;
}
//////////////////////////////////////////////////////////
-
+
~TeensyTimerInterrupt() __attribute__((always_inline))
{
TeensyTimers[_timer] = NULL;
}
//////////////////////////////////////////////////////////
-
+
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to NRF52-hal-timer.c
bool setFrequency(const float& frequency, timerCallback callback) __attribute__((always_inline))
@@ -561,141 +564,141 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
// Interval (in microseconds)
bool setInterval(const unsigned long& interval, timerCallback callback) __attribute__((always_inline))
- {
+ {
// This function will be called when time out interrupt will occur
- if (callback)
+ if (callback)
{
- _callback = callback;
- }
- else
+ _callback = callback;
+ }
+ else
{
- TISR_LOGERROR(F("TeensyTimerInterrupt: ERROR: NULL callback function pointer."));
-
- return false;
+ TISR_LOGERROR(F("TeensyTimerInterrupt: ERROR: NULL callback function pointer."));
+
+ return false;
}
-
+
uint32_t period = ((float) F_TIMER / 2000000) * (float) interval;
uint32_t prescale = 0;
-
+
#if 1
- while (period >= TIMER_RESOLUTION )
+ while (period >= TIMER_RESOLUTION )
{
- period = period >> 1;
-
- if (++prescale > 7)
- {
- prescale = 7;
- period = (TIMER_RESOLUTION - 1);
- break;
- }
- }
+ period = period >> 1;
+
+ if (++prescale > 7)
+ {
+ prescale = 7;
+ period = (TIMER_RESOLUTION - 1);
+ break;
+ }
+ }
#else
- if (period < TIMER_RESOLUTION)
+ if (period < TIMER_RESOLUTION)
{
- prescale = 0;
- }
- else if (period < TIMER_RESOLUTION * 2)
+ prescale = 0;
+ }
+ else if (period < TIMER_RESOLUTION * 2)
{
- prescale = 1;
- period = period >> 1;
- }
- else if (period < TIMER_RESOLUTION * 4)
+ prescale = 1;
+ period = period >> 1;
+ }
+ else if (period < TIMER_RESOLUTION * 4)
{
- prescale = 2;
- period = period >> 2;
- }
- else if (period < TIMER_RESOLUTION * 8)
+ prescale = 2;
+ period = period >> 2;
+ }
+ else if (period < TIMER_RESOLUTION * 8)
{
- prescale = 3;
- period = period >> 3;
- }
- else if (period < TIMER_RESOLUTION * 16)
+ prescale = 3;
+ period = period >> 3;
+ }
+ else if (period < TIMER_RESOLUTION * 16)
{
- prescale = 4;
- period = period >> 4;
- }
- else if (period < TIMER_RESOLUTION * 32)
+ prescale = 4;
+ period = period >> 4;
+ }
+ else if (period < TIMER_RESOLUTION * 32)
{
- prescale = 5;
- period = period >> 5;
- }
- else if (period < TIMER_RESOLUTION * 64)
+ prescale = 5;
+ period = period >> 5;
+ }
+ else if (period < TIMER_RESOLUTION * 64)
{
- prescale = 6;
- period = period >> 6;
- }
- else if (period < TIMER_RESOLUTION * 128)
+ prescale = 6;
+ period = period >> 6;
+ }
+ else if (period < TIMER_RESOLUTION * 128)
{
- prescale = 7;
- period = period >> 7;
- }
- else
+ prescale = 7;
+ period = period >> 7;
+ }
+ else
{
- prescale = 7;
- period = TIMER_RESOLUTION - 1;
+ prescale = 7;
+ period = TIMER_RESOLUTION - 1;
}
-
+
#endif
_realPeriod = (uint32_t) ((period * 2000000.0f) / (F_TIMER >> prescale));
- _prescale = prescale;
- _timerCount = period;
+ _prescale = prescale;
+ _timerCount = period;
if (_timer == TEENSY_TIMER_1)
{
- TISR_LOGWARN1(F("TEENSY_TIMER_1: , F_TIMER (MHz) ="), F_TIMER/1000000);
+ TISR_LOGWARN1(F("TEENSY_TIMER_1: , F_TIMER (MHz) ="), F_TIMER / 1000000);
}
else if (_timer == TEENSY_TIMER_3)
{
- TISR_LOGWARN1(F("TEENSY_TIMER_3: , F_TIMER (MHz) ="), F_TIMER/1000000);
+ TISR_LOGWARN1(F("TEENSY_TIMER_3: , F_TIMER (MHz) ="), F_TIMER / 1000000);
}
-
+
TISR_LOGWARN3(F("Request interval ="), interval, F(", actual interval (us) ="), _realPeriod);
TISR_LOGWARN3(F("Prescale ="), _prescale, F(", _timerCount ="), _timerCount);
-
-
- if (_timer == TEENSY_TIMER_1)
+
+
+ if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
-
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
+
uint32_t sc = FTM1_SC;
-
+
FTM1_SC = 0;
FTM1_MOD = _realPeriod;
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | _prescale | (sc & FTM_SC_TOIE);
-
+
attachInterruptVector(_timer_IRQ, &ftm1_isr);
-
+
FTM1_SC |= FTM_SC_TOIE;
}
else if (_timer == TEENSY_TIMER_3)
{
- ///////////// TEENSY_TIMER_3 code ////////////////////////
-
+ ///////////// TEENSY_TIMER_3 code ////////////////////////
+
uint32_t sc = FTM2_SC;
-
- FTM2_SC = 0;
- FTM2_MOD = _realPeriod;
- FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | _prescale | (sc & FTM_SC_TOIE);
-
- attachInterruptVector(_timer_IRQ, &ftm2_isr);
-
+
+ FTM2_SC = 0;
+ FTM2_MOD = _realPeriod;
+ FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | _prescale | (sc & FTM_SC_TOIE);
+
+ attachInterruptVector(_timer_IRQ, &ftm2_isr);
+
FTM2_SC |= FTM_SC_TOIE;
}
-
+
NVIC_ENABLE_IRQ(_timer_IRQ);
-
+
return true;
}
//////////////////////////////////////////////////////////
-
+
bool attachInterrupt(const float& frequency, timerCallback callback) __attribute__((always_inline))
{
return setInterval((float) (1000000.0f / frequency), callback);
@@ -711,14 +714,14 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
void detachInterrupt() __attribute__((always_inline))
- {
+ {
NVIC_DISABLE_IRQ(_timer_IRQ);
-
+
if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FTM1_SC &= ~FTM_SC_TOIE;
}
else if (_timer == TEENSY_TIMER_3)
@@ -726,7 +729,7 @@ class TeensyTimerInterrupt
///////////// TEENSY_TIMER_3 code ////////////////////////
FTM2_SC &= ~FTM_SC_TOIE;
}
-
+
NVIC_DISABLE_IRQ(_timer_IRQ);
}
@@ -738,29 +741,29 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
//****************************
// Run Control
//****************************
void startTimer() __attribute__((always_inline))
{
stopTimer();
-
+
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:startTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FTM1_CNT = 0;
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:startTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
FTM2_CNT = 0;
}
-
+
resumeTimer();
}
@@ -771,16 +774,16 @@ class TeensyTimerInterrupt
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:stopTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
- FTM2_SC = FTM2_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
+ FTM2_SC = FTM2_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
}
}
@@ -795,18 +798,18 @@ class TeensyTimerInterrupt
void resumeTimer() __attribute__((always_inline))
{
-
+
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
FTM2_SC = (FTM2_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);
}
@@ -820,14 +823,14 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
uint32_t getPrescale() __attribute__((always_inline))
{
return _prescale;
}
//////////////////////////////////////////////////////////
-
+
// Real (actual) period in us
uint32_t getRealPeriod() __attribute__((always_inline))
{
@@ -835,21 +838,21 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
timerCallback getCallback() __attribute__((always_inline))
{
return _callback;
}
//////////////////////////////////////////////////////////
-
+
IRQ_NUMBER_t getTimerIRQn() __attribute__((always_inline))
{
return _timer_IRQ;
}
//////////////////////////////////////////////////////////
-
+
};
@@ -858,13 +861,17 @@ class TeensyTimerInterrupt
void ftm1_isr()
{
uint32_t sc = FTM1_SC;
-
+
#ifdef KINETISL
- if (sc & 0x80)
+
+ if (sc & 0x80)
FTM1_SC = sc;
+
#else
- if (sc & 0x80)
+
+ if (sc & 0x80)
FTM1_SC = sc & 0x7F;
+
#endif
(*(TeensyTimers[TEENSY_TIMER_1]->getCallback()))();
@@ -875,13 +882,17 @@ void ftm1_isr()
void ftm2_isr()
{
uint32_t sc = FTM2_SC;
-
+
#ifdef KINETISL
- if (sc & 0x80)
+
+ if (sc & 0x80)
FTM2_SC = sc;
+
#else
- if (sc & 0x80)
+
+ if (sc & 0x80)
FTM2_SC = sc & 0x7F;
+
#endif
(*(TeensyTimers[TEENSY_TIMER_3]->getCallback()))();
@@ -894,55 +905,55 @@ void ftm2_isr()
#elif ( defined(ARDUINO_ARCH_AVR) || defined(__AVR__) )
- #ifdef BOARD_NAME
- #undef BOARD_NAME
- #endif
-
- // For Teensy 2.0 and Teensy++ 2.0
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Teensy 2.0 or Teensy++ 2.0
- #endif
-
- #define BOARD_NAME "Teensy 2.0 or Teensy++ 2.0"
-
- #if defined(KINETISK)
- #define F_TIMER F_BUS
- #elif defined(KINETISL)
- #define F_TIMER (F_PLL/2)
- #endif
-
- #define TIMER_RESOLUTION 65536UL // Timer1 and Timer 3 are 16 bit timers
+#ifdef BOARD_NAME
+ #undef BOARD_NAME
+#endif
+
+// For Teensy 2.0 and Teensy++ 2.0
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Teensy 2.0 or Teensy++ 2.0
+#endif
+
+#define BOARD_NAME "Teensy 2.0 or Teensy++ 2.0"
+
+#if defined(KINETISK)
+ #define F_TIMER F_BUS
+#elif defined(KINETISL)
+ #define F_TIMER (F_PLL/2)
+#endif
+
+#define TIMER_RESOLUTION 65536UL // Timer1 and Timer 3 are 16 bit timers
- static TeensyTimerInterrupt* TeensyTimers [TEENSY_MAX_TIMER] = { NULL, NULL };
+static TeensyTimerInterrupt* TeensyTimers [TEENSY_MAX_TIMER] = { NULL, NULL };
//////////////////////////////////////////////////////////
class TeensyTimerInterrupt
{
- // Use only 15 bit resolution. From K66 reference manual, 45.5.7 page 1200:
- // The CPWM pulse width (duty cycle) is determined by 2 x (CnV - CNTIN) and the
- // period is determined by 2 x (MOD - CNTIN). See the following figure. MOD must be
- // kept in the range of 0x0001 to 0x7FFF because values outside this range can produce
- // ambiguous results.
- #undef TIMER_RESOLUTION
- #define TIMER_RESOLUTION 32768
-
+ // Use only 15 bit resolution. From K66 reference manual, 45.5.7 page 1200:
+ // The CPWM pulse width (duty cycle) is determined by 2 x (CnV - CNTIN) and the
+ // period is determined by 2 x (MOD - CNTIN). See the following figure. MOD must be
+ // kept in the range of 0x0001 to 0x7FFF because values outside this range can produce
+ // ambiguous results.
+#undef TIMER_RESOLUTION
+#define TIMER_RESOLUTION 32768
+
private:
-
+
uint8_t _timer = TEENSY_TIMER_1;
-
+
timerCallback _callback; // pointer to the callback function
-
+
float _frequency; // Timer frequency
uint32_t _timerCount; // count to activate timer
-
+
uint32_t _prescale = 0;
uint32_t _realPeriod;
-
+
public:
-
+
TeensyTimerInterrupt(uint8_t timer = TEENSY_TIMER_1) __attribute__((always_inline))
- {
+ {
if (timer < TEENSY_MAX_TIMER)
_timer = timer;
else
@@ -950,22 +961,22 @@ class TeensyTimerInterrupt
// Error out of range, force to use TEENSY_TIMER_1
_timer = TEENSY_TIMER_1;
}
-
+
// Update to use in IRQHandler
TeensyTimers[_timer] = this;
-
+
_callback = NULL;
}
//////////////////////////////////////////////////////////
-
+
~TeensyTimerInterrupt() __attribute__((always_inline))
{
TeensyTimers[_timer] = NULL;
}
//////////////////////////////////////////////////////////
-
+
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be added in the future by adding similar functions here or to NRF52-hal-timer.c
bool setFrequency(const float& frequency, timerCallback callback) __attribute__((always_inline))
@@ -974,131 +985,131 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
// Interval (in microseconds)
bool setInterval(const unsigned long& interval, timerCallback callback) __attribute__((always_inline))
- {
+ {
// This function will be called when time out interrupt will occur
- if (callback)
+ if (callback)
{
- _callback = callback;
- }
- else
+ _callback = callback;
+ }
+ else
{
- TISR_LOGERROR(F("TeensyTimerInterrupt: ERROR: NULL callback function pointer."));
-
- return false;
+ TISR_LOGERROR(F("TeensyTimerInterrupt: ERROR: NULL callback function pointer."));
+
+ return false;
}
-
+
uint32_t period = ((float) F_CPU / 2000000) * (float) interval;
uint32_t prescale = 0;
-
+
if (_timer == TEENSY_TIMER_1)
{
///////////// TEENSY_TIMER_1 code ////////////////////////
- if (period < TIMER_RESOLUTION)
+ if (period < TIMER_RESOLUTION)
{
- prescale = _BV(CS10);
- }
- else if (period < TIMER_RESOLUTION * 8)
- {
- prescale = _BV(CS11);
- period = period >> 3;
- }
- else if (period < TIMER_RESOLUTION * 64)
- {
- prescale = _BV(CS11) | _BV(CS10);
- period = period >> 6;
- }
- else if (period < TIMER_RESOLUTION * 256)
- {
- prescale = _BV(CS12);
- period = period >> 8;
- }
- else if (period < TIMER_RESOLUTION * 1024)
- {
- prescale = _BV(CS12) | _BV(CS10);
- period = period >> 10;
- }
- else
- {
- prescale = _BV(CS12) | _BV(CS10);
- period = TIMER_RESOLUTION - 1;
- }
-
- ICR1 = period;
- TCCR1B = _BV(WGM13) | prescale;
- }
- else if (_timer == TEENSY_TIMER_3)
+ prescale = _BV(CS10);
+ }
+ else if (period < TIMER_RESOLUTION * 8)
+ {
+ prescale = _BV(CS11);
+ period = period >> 3;
+ }
+ else if (period < TIMER_RESOLUTION * 64)
+ {
+ prescale = _BV(CS11) | _BV(CS10);
+ period = period >> 6;
+ }
+ else if (period < TIMER_RESOLUTION * 256)
+ {
+ prescale = _BV(CS12);
+ period = period >> 8;
+ }
+ else if (period < TIMER_RESOLUTION * 1024)
+ {
+ prescale = _BV(CS12) | _BV(CS10);
+ period = period >> 10;
+ }
+ else
+ {
+ prescale = _BV(CS12) | _BV(CS10);
+ period = TIMER_RESOLUTION - 1;
+ }
+
+ ICR1 = period;
+ TCCR1B = _BV(WGM13) | prescale;
+ }
+ else if (_timer == TEENSY_TIMER_3)
{
- ///////////// TEENSY_TIMER_3 code ////////////////////////
- if (period < TIMER_RESOLUTION)
+ ///////////// TEENSY_TIMER_3 code ////////////////////////
+ if (period < TIMER_RESOLUTION)
+ {
+ prescale = _BV(CS30);
+ }
+ else if (period < TIMER_RESOLUTION * 8)
+ {
+ prescale = _BV(CS31);
+ period = period >> 3;
+ }
+ else if (period < TIMER_RESOLUTION * 64)
+ {
+ prescale = _BV(CS31) | _BV(CS30);
+ period = period >> 6;
+ }
+ else if (period < TIMER_RESOLUTION * 256)
+ {
+ prescale = _BV(CS32);
+ period = period >> 8;
+ }
+ else if (period < TIMER_RESOLUTION * 1024)
+ {
+ prescale = _BV(CS32) | _BV(CS30);
+ period = period >> 10;
+ }
+ else
{
- prescale = _BV(CS30);
- }
- else if (period < TIMER_RESOLUTION * 8)
- {
- prescale = _BV(CS31);
- period = period >> 3;
- }
- else if (period < TIMER_RESOLUTION * 64)
- {
- prescale = _BV(CS31) | _BV(CS30);
- period = period >> 6;
- }
- else if (period < TIMER_RESOLUTION * 256)
- {
- prescale = _BV(CS32);
- period = period >> 8;
- }
- else if (period < TIMER_RESOLUTION * 1024)
- {
- prescale = _BV(CS32) | _BV(CS30);
- period = period >> 10;
- }
- else
- {
- prescale = _BV(CS32) | _BV(CS30);
- period = TIMER_RESOLUTION - 1;
- }
-
- ICR3 = period;
- TCCR3B = _BV(WGM33) | prescale;
+ prescale = _BV(CS32) | _BV(CS30);
+ period = TIMER_RESOLUTION - 1;
+ }
+
+ ICR3 = period;
+ TCCR3B = _BV(WGM33) | prescale;
}
_realPeriod = (uint32_t) ((period * 2000000.0f) / (F_CPU >> prescale));
- _prescale = prescale;
- _timerCount = period;
+ _prescale = prescale;
+ _timerCount = period;
if (_timer == TEENSY_TIMER_1)
{
- TISR_LOGWARN1(F("TEENSY_TIMER_1: , F_CPU (MHz) ="), F_CPU/1000000);
+ TISR_LOGWARN1(F("TEENSY_TIMER_1: , F_CPU (MHz) ="), F_CPU / 1000000);
}
else if (_timer == TEENSY_TIMER_3)
{
- TISR_LOGWARN1(F("TEENSY_TIMER_3: , F_CPU (MHz) ="), F_CPU/1000000);
+ TISR_LOGWARN1(F("TEENSY_TIMER_3: , F_CPU (MHz) ="), F_CPU / 1000000);
}
-
+
TISR_LOGWARN3(F("Request interval ="), interval, F(", actual interval (us) ="), _realPeriod);
TISR_LOGWARN3(F("Prescale ="), _prescale, F(", _timerCount ="), _timerCount);
-
- // Interrupt attach and enable code
- if (_timer == TEENSY_TIMER_1)
+
+ // Interrupt attach and enable code
+ if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
TIMSK1 = _BV(TOIE1);
}
else if (_timer == TEENSY_TIMER_3)
{
- ///////////// TEENSY_TIMER_3 code ////////////////////////
+ ///////////// TEENSY_TIMER_3 code ////////////////////////
TIMSK3 = _BV(TOIE3);
}
-
+
return true;
}
//////////////////////////////////////////////////////////
-
+
bool attachInterrupt(const float& frequency, timerCallback callback) __attribute__((always_inline))
{
return setInterval((float) (1000000.0f / frequency), callback);
@@ -1114,12 +1125,12 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
void detachInterrupt() __attribute__((always_inline))
- {
+ {
if (_timer == TEENSY_TIMER_1)
{
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
TIMSK1 = 0;
}
else if (_timer == TEENSY_TIMER_3)
@@ -1137,29 +1148,29 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
//****************************
// Run Control
//****************************
void startTimer() __attribute__((always_inline))
- {
+ {
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:startTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
TCCR1B = 0;
- TCNT1 = 0;
+ TCNT1 = 0;
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:startTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
TCCR3B = 0;
- TCNT3 = 0;
+ TCNT3 = 0;
}
-
+
resumeTimer();
}
@@ -1170,14 +1181,14 @@ class TeensyTimerInterrupt
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
TCCR1B = _BV(WGM13);
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:stopTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
TCCR3B = _BV(WGM33);
}
@@ -1194,18 +1205,18 @@ class TeensyTimerInterrupt
void resumeTimer() __attribute__((always_inline))
{
-
+
if (_timer == TEENSY_TIMER_1)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1"));
-
- ///////////// TEENSY_TIMER_1 code ////////////////////////
+
+ ///////////// TEENSY_TIMER_1 code ////////////////////////
TCCR1B = _BV(WGM13) | _prescale;
}
else if (_timer == TEENSY_TIMER_3)
{
TISR_LOGWARN(F("TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_3"));
-
+
///////////// TEENSY_TIMER_3 code ////////////////////////
TCCR3B = _BV(WGM33) | _prescale;
}
@@ -1219,14 +1230,14 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
uint32_t getPrescale() __attribute__((always_inline))
{
return _prescale;
}
//////////////////////////////////////////////////////////
-
+
// Real (actual) period in us
uint32_t getRealPeriod() __attribute__((always_inline))
{
@@ -1234,14 +1245,14 @@ class TeensyTimerInterrupt
}
//////////////////////////////////////////////////////////
-
+
timerCallback getCallback() __attribute__((always_inline))
{
return _callback;
}
//////////////////////////////////////////////////////////
-
+
};
//////////////////////////////////////////////////////////
@@ -1263,8 +1274,8 @@ ISR(TIMER3_OVF_vect)
#else
- #error Not support board
-
+#error Not support board
+
#endif
diff --git a/src/TimerInterrupt_Generic.h b/src/TimerInterrupt_Generic.h
index 87bbb298..ee4b80d0 100644
--- a/src/TimerInterrupt_Generic.h
+++ b/src/TimerInterrupt_Generic.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
********************************************************************************************************************************/
#pragma once
@@ -45,13 +47,13 @@
#define TIMERINTERRUPT_GENERIC_H
#ifndef TIMER_INTERRUPT_GENERIC_VERSION
- #define TIMER_INTERRUPT_GENERIC_VERSION "TimerInterrupt_Generic v1.12.0"
-
+ #define TIMER_INTERRUPT_GENERIC_VERSION "TimerInterrupt_Generic v1.13.0"
+
#define TIMER_INTERRUPT_GENERIC_VERSION_MAJOR 1
- #define TIMER_INTERRUPT_GENERIC_VERSION_MINOR 12
+ #define TIMER_INTERRUPT_GENERIC_VERSION_MINOR 13
#define TIMER_INTERRUPT_GENERIC_VERSION_PATCH 0
- #define TIMER_INTERRUPT_GENERIC_VERSION_INT 1012000
+ #define TIMER_INTERRUPT_GENERIC_VERSION_INT 1013000
#endif
#include "TimerInterrupt_Generic_Debug.h"
@@ -60,138 +62,138 @@
#if ( defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || \
defined(__AVR_ATmega640__) || defined(__AVR_ATmega641__))
- #if defined(TIMER_INTERRUPT_USING_ATMEGA2560)
- #undef TIMER_INTERRUPT_USING_ATMEGA2560
- #endif
- #define TIMER_INTERRUPT_USING_ATMEGA2560 true
-
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Arduino AVR Mega2560/ADK"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Arduino AVR Mega, Mega640(P), Mega2560/ADK. Timer1-5 available
- #endif
-
+#if defined(TIMER_INTERRUPT_USING_ATMEGA2560)
+ #undef TIMER_INTERRUPT_USING_ATMEGA2560
+#endif
+#define TIMER_INTERRUPT_USING_ATMEGA2560 true
+
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Arduino AVR Mega2560/ADK"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Arduino AVR Mega, Mega640(P), Mega2560/ADK. Timer1-5 available
+#endif
+
#elif ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \
defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) || defined(ARDUINO_AVR_ETHERNET) || \
defined(ARDUINO_AVR_FIO) || defined(ARDUINO_AVR_BT) || defined(ARDUINO_AVR_LILYPAD) || defined(ARDUINO_AVR_PRO) || \
- defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) )
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Arduino AVR UNO, Nano, etc."
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Aduino AVR ATMega644(P), ATMega328(P) such as UNO, Nano. Only Timer1,2 available
- #endif
+ defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) )
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Arduino AVR UNO, Nano, etc."
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Aduino AVR ATMega644(P), ATMega328(P) such as UNO, Nano. Only Timer1,2 available
+#endif
#elif ( defined(ARDUINO_AVR_FEATHER328P) || defined(ARDUINO_AVR_METRO) || defined(ARDUINO_AVR_PROTRINKET5) || defined(ARDUINO_AVR_PROTRINKET3) || \
defined(ARDUINO_AVR_PROTRINKET5FTDI) || defined(ARDUINO_AVR_PROTRINKET3FTDI) )
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Adafruit AVR ATMega328(P)"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Adafruit ATMega328(P), such as AVR_FEATHER328P or AVR_METRO. Only Timer1,2 available
- #endif
-
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Adafruit AVR ATMega328(P)"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Adafruit ATMega328(P), such as AVR_FEATHER328P or AVR_METRO. Only Timer1,2 available
+#endif
+
#elif ( defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_LEONARDO_ETH) || defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_MICRO) || \
defined(ARDUINO_AVR_ESPLORA) || defined(ARDUINO_AVR_LILYPAD_USB) || defined(ARDUINO_AVR_ROBOT_CONTROL) || defined(ARDUINO_AVR_ROBOT_MOTOR) || \
defined(ARDUINO_AVR_CIRCUITPLAY) || defined(ARDUINO_AVR_YUNMINI) || defined(ARDUINO_AVR_INDUSTRIAL101) || defined(ARDUINO_AVR_LININO_ONE) )
- #if defined(TIMER_INTERRUPT_USING_ATMEGA_32U4)
- #undef TIMER_INTERRUPT_USING_ATMEGA_32U4
- #endif
- #define TIMER_INTERRUPT_USING_ATMEGA_32U4 true
-
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Arduino AVR ATMega32U4"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Arduino ATMega32U4, such as Leonardo or Leonardo ETH. Only Timer1,3,4 available
- #endif
-
+#if defined(TIMER_INTERRUPT_USING_ATMEGA_32U4)
+ #undef TIMER_INTERRUPT_USING_ATMEGA_32U4
+#endif
+#define TIMER_INTERRUPT_USING_ATMEGA_32U4 true
+
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Arduino AVR ATMega32U4"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Arduino ATMega32U4, such as Leonardo or Leonardo ETH. Only Timer1,3,4 available
+#endif
+
#elif ( defined(ARDUINO_AVR_FLORA8 ) || defined(ARDUINO_AVR_FEATHER32U4) || defined(ARDUINO_AVR_CIRCUITPLAY) || defined(ARDUINO_AVR_ITSYBITSY32U4_5V) || \
defined(ARDUINO_AVR_ITSYBITSY32U4_3V) || defined(ARDUINO_AVR_BLUEFRUITMICRO) || defined(ARDUINO_AVR_ADAFRUIT32U4) )
- #if defined(TIMER_INTERRUPT_USING_ATMEGA_32U4)
- #undef TIMER_INTERRUPT_USING_ATMEGA_32U4
- #endif
- #define TIMER_INTERRUPT_USING_ATMEGA_32U4 true
-
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Adafruit AVR ATMega32U4"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Adafruit ATMega32U4, such as Feather_32u4, AVR_CIRCUITPLAY, etc.. Only Timer1,3,4 available
- #endif
-
+#if defined(TIMER_INTERRUPT_USING_ATMEGA_32U4)
+ #undef TIMER_INTERRUPT_USING_ATMEGA_32U4
+#endif
+#define TIMER_INTERRUPT_USING_ATMEGA_32U4 true
+
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Adafruit AVR ATMega32U4"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Adafruit ATMega32U4, such as Feather_32u4, AVR_CIRCUITPLAY, etc.. Only Timer1,3,4 available
+#endif
+
#elif ( defined(__AVR_ATmega32U4__) || defined(ARDUINO_AVR_MAKEYMAKEY ) || defined(ARDUINO_AVR_PROMICRO) || defined(ARDUINO_AVR_FIOV3) || \
defined(ARDUINO_AVR_QDUINOMINI) || defined(ARDUINO_AVR_LILYPAD_ARDUINO_USB_PLUS_BOARD ) ) && !defined(TEENSYDUINO)
- #if defined(TIMER_INTERRUPT_USING_ATMEGA_32U4)
- #undef TIMER_INTERRUPT_USING_ATMEGA_32U4
- #endif
- #define TIMER_INTERRUPT_USING_ATMEGA_32U4 true
-
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Generic or Sparkfun AVR ATMega32U4"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Generic ATMega32U4, such as Sparkfun AVR_MAKEYMAKEY, AVR_PROMICRO, etc. Only Timer1,3,4 available
- #endif
+#if defined(TIMER_INTERRUPT_USING_ATMEGA_32U4)
+ #undef TIMER_INTERRUPT_USING_ATMEGA_32U4
+#endif
+#define TIMER_INTERRUPT_USING_ATMEGA_32U4 true
+
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Generic or Sparkfun AVR ATMega32U4"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Generic ATMega32U4, such as Sparkfun AVR_MAKEYMAKEY, AVR_PROMICRO, etc. Only Timer1,3,4 available
+#endif
#elif ( defined(__AVR_ATmega328P__) || defined(ARDUINO_AVR_DIGITAL_SANDBOX ) || defined(ARDUINO_REDBOT) || defined(ARDUINO_AVR_SERIAL_7_SEGMENT) )
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Generic or Sparkfun AVR ATMega328P"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Generic ATMega328P, such as Sparkfun AVR_DIGITAL_SANDBOX, REDBOT, etc.
- #endif
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Generic or Sparkfun AVR ATMega328P"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Generic ATMega328P, such as Sparkfun AVR_DIGITAL_SANDBOX, REDBOT, etc.
+#endif
#elif ( defined(__AVR_ATmega128RFA1__) || defined(ARDUINO_ATMEGA128RFA1_DEV_BOARD) )
- #define TIMER_INTERRUPT_USING_AVR true
-
- #define BOARD_TYPE "Generic or Sparkfun AVR ATMega128RFA1"
-
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using Generic ATMega128RFA1, such as Sparkfun ATMEGA128RFA1_DEV_BOARD, etc.
- #endif
-
+#define TIMER_INTERRUPT_USING_AVR true
+
+#define BOARD_TYPE "Generic or Sparkfun AVR ATMega128RFA1"
+
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using Generic ATMega128RFA1, such as Sparkfun ATMEGA128RFA1_DEV_BOARD, etc.
+#endif
+
#elif ( defined(ARDUINO_AVR_GEMMA) || defined(ARDUINO_AVR_TRINKET3) || defined(ARDUINO_AVR_TRINKET5) )
- #error These AVR boards are not supported! Please check your Tools->Board setting.
+#error These AVR boards are not supported! Please check your Tools->Board setting.
/////////////////////////////// ESP8266 ///////////////////////////////
#elif ( defined(ESP8266) || ESP8266 )
-
- #define TIMER_INTERRUPT_USING_ESP8266 true
+
+#define TIMER_INTERRUPT_USING_ESP8266 true
/////////////////////////////// ESP32 ///////////////////////////////
-
+
#elif ( defined(ESP32) || ESP32 )
- #define TIMER_INTERRUPT_USING_ESP32 true
+#define TIMER_INTERRUPT_USING_ESP32 true
/////////////////////////////// Nano-33-BLE ///////////////////////////////
#elif ( ARDUINO_ARCH_NRF52840 && TARGET_NAME == ARDUINO_NANO33BLE )
- #if(_TIMERINTERRUPT_LOGLEVEL_>3)
- #warning Using ARDUINO_NANO33BLE
- #endif
-
- #define TIMER_INTERRUPT_USING_NANO33BLE true
+#if(_TIMERINTERRUPT_LOGLEVEL_>3)
+ #warning Using ARDUINO_NANO33BLE
+#endif
+
+#define TIMER_INTERRUPT_USING_NANO33BLE true
/////////////////////////////// SAMD ///////////////////////////////
-
+
#elif ( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \
|| defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \
|| defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(__SAMD21G18A__) \
|| defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD21E18A__) || defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) \
|| defined(__SAMD51G19A__) || defined(__SAMD51P19A__) || defined(__SAMD21G18A__) )
- #define TIMER_INTERRUPT_USING_SAMD true
+#define TIMER_INTERRUPT_USING_SAMD true
/////////////////////////////// NRF52 ///////////////////////////////
@@ -199,50 +201,50 @@
defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \
defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || \
defined(MDBT50Q_RX) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) )
-
- #define TIMER_INTERRUPT_USING_NRF52 true
+
+#define TIMER_INTERRUPT_USING_NRF52 true
/////////////////////////////// SAM DUE ///////////////////////////////
-#elif ( defined(ARDUINO_SAM_DUE) || defined(__SAM3X8E__) )
-
- #define TIMER_INTERRUPT_USING_SAMDUE true
-
+#elif ( defined(ARDUINO_SAM_DUE) || defined(__SAM3X8E__) )
+
+#define TIMER_INTERRUPT_USING_SAMDUE true
+
/////////////////////////////// TEENSY ///////////////////////////////
#elif ( defined(CORE_TEENSY) || defined(__IMXRT1062__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) || \
defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK20DX128__) )
- #define TIMER_INTERRUPT_USING_TEENSY true
+#define TIMER_INTERRUPT_USING_TEENSY true
/////////////////////////////// STM32 ///////////////////////////////
#elif ( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
defined(STM32WB) || defined(STM32MP1) || defined(STM32L5) )
-
- #define TIMER_INTERRUPT_USING_STM32 true
+
+#define TIMER_INTERRUPT_USING_STM32 true
#elif ( defined(__AVR_ATmega4809__) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || \
defined(ARDUINO_AVR_ATmega4809) || defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \
defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || defined(ARDUINO_AVR_ATmega1608) || \
defined(ARDUINO_AVR_ATmega809) || defined(ARDUINO_AVR_ATmega808) )
-
- #define TIMER_INTERRUPT_USING_MEGA_AVR true
+
+#define TIMER_INTERRUPT_USING_MEGA_AVR true
#elif ( defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) ) && !defined(ARDUINO_ARCH_MBED)
- #define TIMER_INTERRUPT_USING_RPI_PICO true
-
+#define TIMER_INTERRUPT_USING_RPI_PICO true
+
#elif ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \
defined(ARDUINO_GENERIC_RP2040) ) && defined(ARDUINO_ARCH_MBED)
-
- #define TIMER_INTERRUPT_USING_MBED_RPI_PICO true
-
+
+#define TIMER_INTERRUPT_USING_MBED_RPI_PICO true
+
#else
- #error Unsupported Board! Please check your Tools->Board setting.
-
+#error Unsupported Board! Please check your Tools->Board setting.
+
#endif
////////////////////////////////////////////////////
@@ -250,27 +252,27 @@
#if TIMER_INTERRUPT_USING_AVR
#include "AVRTimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_ESP8266
- #include "ESP8266TimerInterrupt_Generic.h"
+ #include "ESP8266TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_ESP32
- #include "ESP32TimerInterrupt_Generic.h"
+ #include "ESP32TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_NANO33BLE
- #include "NRF52_MBED_TimerInterrupt_Generic.h"
+ #include "NRF52_MBED_TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_SAMD
#include "SAMDTimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_NRF52
- #include "NRF52TimerInterrupt_Generic.h"
+ #include "NRF52TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_SAMDUE
- #include "SAMDUETimerInterrupt_Generic.h"
+ #include "SAMDUETimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_TEENSY
- #include "TeensyTimerInterrupt_Generic.h"
+ #include "TeensyTimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_STM32
#include "STM32TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_MEGA_AVR
- #include "megaAVR_TimerInterrupt_Generic.h"
+ #include "megaAVR_TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_RPI_PICO
- #include "RP2040_TimerInterrupt_Generic.h"
+ #include "RP2040_TimerInterrupt_Generic.h"
#elif TIMER_INTERRUPT_USING_MBED_RPI_PICO
- #include "MBED_RP2040_TimerInterrupt_Generic.h"
+ #include "MBED_RP2040_TimerInterrupt_Generic.h"
#endif
////////////////////////////////////////////////////
diff --git a/src/TimerInterrupt_Generic_Debug.h b/src/TimerInterrupt_Generic_Debug.h
index 31f2dcc7..c5996db2 100644
--- a/src/TimerInterrupt_Generic_Debug.h
+++ b/src/TimerInterrupt_Generic_Debug.h
@@ -19,7 +19,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/TimerInterrupt_Generic
Licensed under MIT license
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -37,6 +37,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
*****************************************************************************************************************************/
#pragma once
diff --git a/src/megaAVR_TimerInterrupt_Generic.h b/src/megaAVR_TimerInterrupt_Generic.h
index f036003f..4f7e8d02 100644
--- a/src/megaAVR_TimerInterrupt_Generic.h
+++ b/src/megaAVR_TimerInterrupt_Generic.h
@@ -12,7 +12,7 @@
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
- Version: 1.12.0
+ Version: 1.13.0
Version Modified By Date Comments
------- ----------- ---------- -----------
@@ -30,6 +30,8 @@
1.10.0 K.Hoang 10/08/2022 Update to use latest ESP32_New_TimerInterrupt Library version
1.11.0 K.Hoang 12/08/2022 Add support to new ESP32_C3, ESP32_S2 and ESP32_S3 boards
1.12.0 K.Hoang 29/09/2022 Update for SAMD, RP2040, MBED_RP2040
+ 1.13.0 K.Hoang 16/11/2022 Fix doubled time for ESP32_C3,S2 and S3. Fix poor timer accuracy bug for MBED RP2040
+ Fix bug disabling TCB0 for megaAVR
****************************************************************************************************************************/
#pragma once
@@ -43,39 +45,39 @@
defined(ARDUINO_AVR_ATmega4809) || defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \
defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || defined(ARDUINO_AVR_ATmega1608) || \
defined(ARDUINO_AVR_ATmega809) || defined(ARDUINO_AVR_ATmega808) )
- #if !defined(BOARD_NAME)
- #if (ARDUINO_AVR_UNO_WIFI_REV2)
- #define BOARD_NAME "megaAVR UNO WiFi Rev2"
- #define TIMER_INTERRUPT_USING_ARDUINO_CORE true
- #elif (ARDUINO_AVR_NANO_EVERY)
- #define BOARD_NAME "megaAVR Nano Every"
- #define TIMER_INTERRUPT_USING_ARDUINO_CORE true
+#if !defined(BOARD_NAME)
+ #if (ARDUINO_AVR_UNO_WIFI_REV2)
+ #define BOARD_NAME "megaAVR UNO WiFi Rev2"
+ #define TIMER_INTERRUPT_USING_ARDUINO_CORE true
+ #elif (ARDUINO_AVR_NANO_EVERY)
+ #define BOARD_NAME "megaAVR Nano Every"
+ #define TIMER_INTERRUPT_USING_ARDUINO_CORE true
+ #else
+ #define TIMER_INTERRUPT_USING_ARDUINO_CORE false
+
+ #if (ARDUINO_AVR_ATmega4809)
+ #define BOARD_NAME "MegaCoreX ATmega4809"
+ #elif (ARDUINO_AVR_ATmega4808)
+ #define BOARD_NAME "MegaCoreX ATmega4808"
+ #elif (ARDUINO_AVR_ATmega3209)
+ #define BOARD_NAME "MegaCoreX ATmega3209"
+ #elif (ARDUINO_AVR_ATmega3208)
+ #define BOARD_NAME "MegaCoreX ATmega3208"
+ #elif (ARDUINO_AVR_ATmega1609)
+ #define BOARD_NAME "MegaCoreX ATmega1609"
+ #elif (ARDUINO_AVR_ATmega1608)
+ #define BOARD_NAME "MegaCoreX ATmega1608"
+ #elif (ARDUINO_AVR_ATmega809)
+ #define BOARD_NAME "MegaCoreX ATmega809"
+ #elif (ARDUINO_AVR_ATmega808)
+ #define BOARD_NAME "MegaCoreX ATmega808"
#else
- #define TIMER_INTERRUPT_USING_ARDUINO_CORE false
-
- #if (ARDUINO_AVR_ATmega4809)
- #define BOARD_NAME "MegaCoreX ATmega4809"
- #elif (ARDUINO_AVR_ATmega4808)
- #define BOARD_NAME "MegaCoreX ATmega4808"
- #elif (ARDUINO_AVR_ATmega3209)
- #define BOARD_NAME "MegaCoreX ATmega3209"
- #elif (ARDUINO_AVR_ATmega3208)
- #define BOARD_NAME "MegaCoreX ATmega3208"
- #elif (ARDUINO_AVR_ATmega1609)
- #define BOARD_NAME "MegaCoreX ATmega1609"
- #elif (ARDUINO_AVR_ATmega1608)
- #define BOARD_NAME "MegaCoreX ATmega1608"
- #elif (ARDUINO_AVR_ATmega809)
- #define BOARD_NAME "MegaCoreX ATmega809"
- #elif (ARDUINO_AVR_ATmega808)
- #define BOARD_NAME "MegaCoreX ATmega808"
- #else
- #define BOARD_NAME "megaAVR Unknown"
- #endif
+ #define BOARD_NAME "megaAVR Unknown"
#endif
#endif
+#endif
#else
- #error This is designed only for Arduino or MegaCoreX megaAVR board! Please check your Tools->Board setting
+#error This is designed only for Arduino or MegaCoreX megaAVR board! Please check your Tools->Board setting
#endif
///////////////////////////////////////////
@@ -91,13 +93,13 @@
///////////////////////////////////////////
#ifndef MEGA_AVR_TIMER_INTERRUPT_VERSION
- #define MEGA_AVR_TIMER_INTERRUPT_VERSION "megaAVR_TimerInterrupt v1.6.1"
-
+ #define MEGA_AVR_TIMER_INTERRUPT_VERSION "megaAVR_TimerInterrupt v1.7.0"
+
#define MEGA_AVR_TIMER_INTERRUPT_VERSION_MAJOR 1
- #define MEGA_AVR_TIMER_INTERRUPT_VERSION_MINOR 6
- #define MEGA_AVR_TIMER_INTERRUPT_VERSION_PATCH 1
+ #define MEGA_AVR_TIMER_INTERRUPT_VERSION_MINOR 7
+ #define MEGA_AVR_TIMER_INTERRUPT_VERSION_PATCH 0
- #define MEGA_AVR_TIMER_INTERRUPT_VERSION_INT 1006001
+ #define MEGA_AVR_TIMER_INTERRUPT_VERSION_INT 1007000
#endif
#include
@@ -126,24 +128,24 @@ enum
/*****************************************************************************************
-// From ~/.arduino15/packages/arduino/7.3.0-atmel3.6.1-arduino5/avr/include/avr/iom4809.h
+ // From ~/.arduino15/packages/arduino/7.3.0-atmel3.6.1-arduino5/avr/include/avr/iom4809.h
-//#define TCB0 (*(TCB_t *) 0x0A80) // 16-bit Timer Type B
-//#define TCB1 (*(TCB_t *) 0x0A90) // 16-bit Timer Type B
-//#define TCB2 (*(TCB_t *) 0x0AA0) // 16-bit Timer Type B
-//#define TCB3 (*(TCB_t *) 0x0AB0) // 16-bit Timer Type B
+ //#define TCB0 (*(TCB_t *) 0x0A80) // 16-bit Timer Type B
+ //#define TCB1 (*(TCB_t *) 0x0A90) // 16-bit Timer Type B
+ //#define TCB2 (*(TCB_t *) 0x0AA0) // 16-bit Timer Type B
+ //#define TCB3 (*(TCB_t *) 0x0AB0) // 16-bit Timer Type B
-//
-typedef enum TCB_CLKSEL_enum
-{
+ //
+ typedef enum TCB_CLKSEL_enum
+ {
TCB_CLKSEL_CLKDIV1_gc = (0x00<<1), // CLK_PER (No Prescaling)
TCB_CLKSEL_CLKDIV2_gc = (0x01<<1), // CLK_PER/2 (From Prescaler)
TCB_CLKSEL_CLKTCA_gc = (0x02<<1), // Use Clock from TCA
-} TCB_CLKSEL_t;
+ } TCB_CLKSEL_t;
-//
-typedef enum TCB_CNTMODE_enum
-{
+ //
+ typedef enum TCB_CNTMODE_enum
+ {
TCB_CNTMODE_INT_gc = (0x00<<0), // Periodic Interrupt
TCB_CNTMODE_TIMEOUT_gc = (0x01<<0), // Periodic Timeout
TCB_CNTMODE_CAPT_gc = (0x02<<0), // Input Capture Event
@@ -152,41 +154,41 @@ typedef enum TCB_CNTMODE_enum
TCB_CNTMODE_FRQPW_gc = (0x05<<0), // Input Capture Frequency and Pulse-Width measurement
TCB_CNTMODE_SINGLE_gc = (0x06<<0), // Single Shot
TCB_CNTMODE_PWM8_gc = (0x07<<0), // 8-bit PWM
-} TCB_CNTMODE_t;
+ } TCB_CNTMODE_t;
*****************************************************************************************/
#if ( defined(__AVR_ATmega4809__) || defined(__AVR_ATmega3209__) || defined(__AVR_ATmega1609__) || defined(__AVR_ATmega809__) )
- #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
- #warning Using __AVR_ATmegaXX09__ architecture
- #endif
-
- #define TIMER_INTERRUPT_USING_ATMEGA_XX09 true
-
- TCB_t* TimerTCB[ NUM_HW_TIMERS ] = { &TCB0, &TCB1, &TCB2, &TCB3 };
-
+#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
+ #warning Using __AVR_ATmegaXX09__ architecture
+#endif
+
+#define TIMER_INTERRUPT_USING_ATMEGA_XX09 true
+
+TCB_t* TimerTCB[ NUM_HW_TIMERS ] = { &TCB0, &TCB1, &TCB2, &TCB3 };
+
#elif ( defined(__AVR_ATmega4808__) || defined(__AVR_ATmega3208__) || defined(__AVR_ATmega1608__) || defined(__AVR_ATmega808__) )
- #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
- #warning Using __AVR_ATmegaXX08__ architecture
- #endif
-
- #define TIMER_INTERRUPT_USING_ATMEGA_XX08 true
-
- TCB_t* TimerTCB[ NUM_HW_TIMERS ] = { &TCB0, &TCB1, &TCB2 };
-
-#endif
+#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
+ #warning Using __AVR_ATmegaXX08__ architecture
+#endif
+
+#define TIMER_INTERRUPT_USING_ATMEGA_XX08 true
+
+TCB_t* TimerTCB[ NUM_HW_TIMERS ] = { &TCB0, &TCB1, &TCB2 };
+
+#endif
///////////////////////////////////////////
#define CLK_TCA_FREQ (250000L)
// Clock for UNO WiFi Rev2 and Nano Every is 16MHz
-#if USING_16MHZ
+#if USING_16MHZ
// Use no prescaler (prescaler 1) => 16MHz
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using no prescaler => 16MHz
#endif
-
+
#define TCB_CLKSEL_VALUE TCB_CLKSEL_CLKDIV1_gc
#define CLOCK_PRESCALER 1
#elif USING_8MHZ
@@ -194,7 +196,7 @@ typedef enum TCB_CNTMODE_enum
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using prescaler 2 => 8MHz
#endif
-
+
#define TCB_CLKSEL_VALUE TCB_CLKSEL_CLKDIV2_gc
#define CLOCK_PRESCALER 2
#elif USING_250KHZ
@@ -203,15 +205,15 @@ typedef enum TCB_CNTMODE_enum
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using prescaler 64 => 250KHz
#endif
-
- #define TCB_CLKSEL_VALUE TCB_CLKSEL_CLKTCA_gc
+
+ #define TCB_CLKSEL_VALUE TCB_CLKSEL_CLKTCA_gc
#define CLOCK_PRESCALER 64
#else
// Use Timer A as clock (prescaler 64) => 250KHz
#if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
#warning Using prescaler 64 => 250KHz
#endif
-
+
#define TCB_CLKSEL_VALUE TCB_CLKSEL_CLKTCA_gc
#define CLOCK_PRESCALER 64
#endif
@@ -237,7 +239,7 @@ class TimerInterrupt
///////////////////////////////////////////
-
+
void set_CCMP()
{
// Run with noInterrupt()
@@ -245,14 +247,14 @@ class TimerInterrupt
// set the toggle count,
// then turn on the interrupts
uint32_t _CCMPValueToUse;
-
+
_CCMPValueToUse = min(MAX_COUNT_16BIT, _CCMPValueRemaining);
_CCMPValueRemaining -= _CCMPValueToUse;
-
+
TimerTCB[_timer]->CCMP = _CCMPValueToUse; // Value to compare with.
-
+
TimerTCB[_timer]->INTCTRL = TCB_CAPT_bm; // Enable the interrupt
-
+
TISR_LOGDEBUG(F("=================="));
TISR_LOGDEBUG1(F("set_CCMP, Timer ="), _timer);
TISR_LOGDEBUG1(F("CTRLB ="), TimerTCB[_timer]->CTRLB);
@@ -266,7 +268,7 @@ class TimerInterrupt
_timerDone = true;
}
-
+
///////////////////////////////////////////
public:
@@ -282,7 +284,7 @@ class TimerInterrupt
_CCMPValueRemaining = 0;
_toggle_count = -1;
};
-
+
///////////////////////////////////////////
explicit TimerInterrupt(uint8_t timerNo)
@@ -296,7 +298,7 @@ class TimerInterrupt
_CCMPValueRemaining = 0;
_toggle_count = -1;
};
-
+
///////////////////////////////////////////
void callback() __attribute__((always_inline))
@@ -309,18 +311,18 @@ class TimerInterrupt
(*(timer_callback)_callback)();
}
}
-
+
///////////////////////////////////////////
void init(const int8_t& timer)
- {
+ {
// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
-
+
noInterrupts();
-
+
// 16 bit timer
TimerTCB[timer]->CTRLB = TCB_CNTMODE_INT_gc; // Use timer compare mode
TimerTCB[timer]->CCMP = MAX_COUNT_16BIT; // Value to compare with.
@@ -328,7 +330,7 @@ class TimerInterrupt
TimerTCB[timer]->CTRLA = TCB_CLKSEL_VALUE | TCB_ENABLE_bm; // Use Timer A as clock, enable timer
TISR_LOGWARN1(F("TCB"), timer);
-
+
TISR_LOGINFO(F("=================="));
TISR_LOGINFO1(F("Init, Timer ="), timer);
TISR_LOGINFO1(F("CTRLB ="), TimerTCB[timer]->CTRLB);
@@ -336,52 +338,53 @@ class TimerInterrupt
TISR_LOGINFO1(F("INTCTRL ="), TimerTCB[timer]->INTCTRL);
TISR_LOGINFO1(F("CTRLA ="), TimerTCB[timer]->CTRLA);
TISR_LOGINFO(F("=================="));
-
+
_timer = timer;
interrupts();
-
+
}
-
+
///////////////////////////////////////////
void init()
{
init(_timer);
};
-
+
///////////////////////////////////////////
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
//bool setFrequency(float frequency, timer_callback_p callback, /* void* */ uint32_t params, unsigned long duration = 0);
// frequency (in hertz) and duration (in milliseconds).
// Return true if frequency is OK with selected timer (CCMPValue is in range)
- bool setFrequency(const float& frequency, timer_callback_p callback, const uint32_t& params, const unsigned long& duration = 0)
- {
+ bool setFrequency(const float& frequency, timer_callback_p callback, const uint32_t& params,
+ const unsigned long& duration = 0)
+ {
//frequencyLimit must > 1
float frequencyLimit = frequency * 17179.840;
// Limit frequency to larger than (0.00372529 / 64) Hz or interval 17179.840s / 17179840 ms to avoid uint32_t overflow
- if ((_timer <= 0) || (callback == NULL) || ((frequencyLimit) < 1) )
+ if ((_timer < 0) || (callback == NULL) || ((frequencyLimit) < 1) )
{
TISR_LOGDEBUG(F("setFrequency error"));
-
+
return false;
}
- else
- {
+ else
+ {
// Calculate the toggle count. Duration must be at least longer then one cycle
if (duration > 0)
- {
+ {
_toggle_count = frequency * duration / 1000;
TISR_LOGINFO1(F("setFrequency => _toggle_count ="), _toggle_count);
TISR_LOGINFO3(F("Frequency ="), frequency, F(", duration ="), duration);
-
+
if (_toggle_count < 1)
{
TISR_LOGDEBUG(F("setFrequency: _toggle_count < 1 error"));
-
+
return false;
}
}
@@ -389,7 +392,7 @@ class TimerInterrupt
{
_toggle_count = -1;
}
-
+
//Timer0-3 are 16 bit timers, meaning it can store a maximum counter value of 65535.
noInterrupts();
@@ -399,23 +402,23 @@ class TimerInterrupt
_params = reinterpret_cast(params);
_timerDone = false;
-
+
_CCMPValue = _CCMPValueRemaining = (uint32_t) (CLK_TCB_FREQ / frequency);
TISR_LOGINFO3(F("Frequency ="), frequency, F(", CLK_TCB_FREQ ="), CLK_TCB_FREQ);
TISR_LOGINFO1(F("setFrequency: _CCMPValueRemaining = "), _CCMPValueRemaining);
-
+
// Set the CCMP for the given timer,
// set the toggle count,
- // then turn on the interrupts
+ // then turn on the interrupts
set_CCMP();
-
+
interrupts();
return true;
}
}
-
+
///////////////////////////////////////////
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
@@ -423,17 +426,19 @@ class TimerInterrupt
{
return setFrequency(frequency, reinterpret_cast(callback), /*NULL*/ 0, duration);
}
-
+
///////////////////////////////////////////
// interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
template
- bool setInterval(const unsigned long& interval, void (*callback)(TArg), const TArg& params, const unsigned long& duration = 0)
+ bool setInterval(const unsigned long& interval, void (*callback)(TArg), const TArg& params,
+ const unsigned long& duration = 0)
{
static_assert(sizeof(TArg) <= sizeof(uint32_t), "setInterval() callback argument size must be <= 4 bytes");
- return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), (uint32_t) params, duration);
+ return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), (uint32_t) params,
+ duration);
}
-
+
///////////////////////////////////////////
// interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
@@ -441,62 +446,66 @@ class TimerInterrupt
{
return setFrequency((float) (1000.0f / interval), reinterpret_cast(callback), /*NULL*/ 0, duration);
}
-
+
///////////////////////////////////////////
template
- bool attachInterrupt(const float& frequency, void (*callback)(TArg), const TArg& params, const unsigned long& duration = 0)
+ bool attachInterrupt(const float& frequency, void (*callback)(TArg), const TArg& params,
+ const unsigned long& duration = 0)
{
static_assert(sizeof(TArg) <= sizeof(uint32_t), "attachInterrupt() callback argument size must be <= 4 bytes");
return setFrequency(frequency, reinterpret_cast(callback), (uint32_t) params, duration);
}
-
+
///////////////////////////////////////////
bool attachInterrupt(const float& frequency, timer_callback callback, const unsigned long& duration = 0)
{
return setFrequency(frequency, reinterpret_cast(callback), /*NULL*/ 0, duration);
}
-
+
///////////////////////////////////////////
// Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
template
- bool attachInterruptInterval(const unsigned long& interval, void (*callback)(TArg), const TArg& params, const unsigned long& duration = 0)
+ bool attachInterruptInterval(const unsigned long& interval, void (*callback)(TArg), const TArg& params,
+ const unsigned long& duration = 0)
{
static_assert(sizeof(TArg) <= sizeof(uint32_t), "attachInterruptInterval() callback argument size must be <= 4 bytes");
- return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast(callback), (uint32_t) params, duration);
+ return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast(callback), (uint32_t) params,
+ duration);
}
-
+
///////////////////////////////////////////
// Interval (in ms) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
bool attachInterruptInterval(const unsigned long& interval, timer_callback callback, const unsigned long& duration = 0)
{
- return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast (callback), /*NULL*/ 0, duration);
+ return setFrequency( (float) ( 1000.0f / interval), reinterpret_cast (callback), /*NULL*/ 0,
+ duration);
}
-
+
///////////////////////////////////////////
void detachInterrupt()
{
noInterrupts();
-
+
// Clear interrupt flag
TimerTCB[_timer]->INTFLAGS = TCB_CAPT_bm;
TimerTCB[_timer]->INTCTRL &= ~TCB_CAPT_bm; // Disable the interrupt
TimerTCB[_timer]->CTRLA &= ~TCB_ENABLE_bm; // Disable timer
-
+
interrupts();
}
-
+
///////////////////////////////////////////
void disableTimer()
{
detachInterrupt();
}
-
+
///////////////////////////////////////////
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
@@ -513,14 +522,14 @@ class TimerInterrupt
{
_toggle_count = -1;
}
-
- // Set interrupt flag
+
+ // Set interrupt flag
TimerTCB[_timer]->INTCTRL |= TCB_CAPT_bm; // Enable the interrupt
TimerTCB[_timer]->CTRLA |= TCB_ENABLE_bm; // Enable timer
-
+
interrupts();
}
-
+
///////////////////////////////////////////
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
@@ -528,24 +537,24 @@ class TimerInterrupt
{
reattachInterrupt(duration);
}
-
+
///////////////////////////////////////////
// Just stop clock source, still keep the count
// To fix this.
void pauseTimer()
- {
+ {
detachInterrupt();
}
-
+
///////////////////////////////////////////
// Just reconnect clock source, continue from the current count
void resumeTimer()
- {
+ {
reattachInterrupt();
}
-
+
///////////////////////////////////////////
// Just stop clock source, clear the count
@@ -553,7 +562,7 @@ class TimerInterrupt
{
detachInterrupt();
}
-
+
///////////////////////////////////////////
// Just reconnect clock source, start current count from 0
@@ -561,21 +570,21 @@ class TimerInterrupt
{
reattachInterrupt(duration);
}
-
+
///////////////////////////////////////////
int8_t getTimer() __attribute__((always_inline))
{
return _timer;
};
-
+
///////////////////////////////////////////
long getCount() __attribute__((always_inline))
{
return _toggle_count;
};
-
+
///////////////////////////////////////////
void setCount(const long& countInput) __attribute__((always_inline))
@@ -586,33 +595,33 @@ class TimerInterrupt
//interrupts();
};
-
+
///////////////////////////////////////////
uint32_t get_CCMPValue() __attribute__((always_inline))
{
return _CCMPValue;
};
-
+
///////////////////////////////////////////
uint32_t get_CCMPValueRemaining() __attribute__((always_inline))
{
return _CCMPValueRemaining;
};
-
+
///////////////////////////////////////////
void adjust_CCMPValue() //__attribute__((always_inline))
{
noInterrupts();
-
+
if (_CCMPValueRemaining < MAX_COUNT_16BIT)
{
set_CCMP();
}
-
- interrupts();
+
+ interrupts();
_CCMPValueRemaining -= min(MAX_COUNT_16BIT, _CCMPValueRemaining);
@@ -620,29 +629,29 @@ class TimerInterrupt
{
// Reset value for next cycle
_CCMPValueRemaining = _CCMPValue;
-
+
TISR_LOGDEBUG1(F("adjust_CCMPValue: reset _CCMPValueRemaining = "), _CCMPValue);
_timerDone = true;
}
else
_timerDone = false;
};
-
+
///////////////////////////////////////////
void reload_CCMPValue() //__attribute__((always_inline))
{
noInterrupts();
- // Reset value for next cycle, have to deduct the value already loaded to CCMP register
+ // Reset value for next cycle, have to deduct the value already loaded to CCMP register
_CCMPValueRemaining = _CCMPValue;
set_CCMP();
-
+
_timerDone = false;
interrupts();
};
-
+
///////////////////////////////////////////
bool checkTimerDone() __attribute__((always_inline))
@@ -680,111 +689,111 @@ class TimerInterrupt
//////////////////////////////////////////////
#if USE_TIMER_0
- #ifndef TIMER0_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER0_INSTANTIATED
- TimerInterrupt ITimer0(HW_TIMER_0);
-
- ISR(TCB0_INT_vect)
- {
- long countLocal = ITimer0.getCount();
-
- if (ITimer0.getTimer() == 0)
+#ifndef TIMER0_INSTANTIATED
+// To force pre-instatiate only once
+#define TIMER0_INSTANTIATED
+TimerInterrupt ITimer0(HW_TIMER_0);
+
+ISR(TCB0_INT_vect)
+{
+ long countLocal = ITimer0.getCount();
+
+ if (ITimer0.getTimer() == 0)
+ {
+ if (countLocal != 0)
+ {
+ if (ITimer0.checkTimerDone())
{
- if (countLocal != 0)
- {
- if (ITimer0.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T0 callback, _CCMPValueRemaining ="), ITimer0.get_CCMPValueRemaining(), (", millis ="), millis());
-
- ITimer0.callback();
-
- // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT
- if (ITimer0.get_CCMPValue() > MAX_COUNT_16BIT)
- {
- // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT
- ITimer0.reload_CCMPValue();
- }
-
- if (countLocal > 0)
- ITimer0.setCount(countLocal - 1);
- }
- else
- {
- //Deduct _CCMPValue by min(MAX_COUNT_16BIT, _CCMPValue)
- // If _CCMPValue == 0, flag _timerDone for next cycle
- // If last one (_CCMPValueRemaining < MAX_COUNT_16BIT) => load _CCMP register _CCMPValueRemaining
- ITimer0.adjust_CCMPValue();
- }
- }
- else
+ TISR_LOGDEBUG3(("T0 callback, _CCMPValueRemaining ="), ITimer0.get_CCMPValueRemaining(), (", millis ="), millis());
+
+ ITimer0.callback();
+
+ // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT
+ if (ITimer0.get_CCMPValue() > MAX_COUNT_16BIT)
{
- TISR_LOGWARN(("T0 done"));
-
- ITimer0.detachInterrupt();
+ // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT
+ ITimer0.reload_CCMPValue();
}
+
+ if (countLocal > 0)
+ ITimer0.setCount(countLocal - 1);
+ }
+ else
+ {
+ //Deduct _CCMPValue by min(MAX_COUNT_16BIT, _CCMPValue)
+ // If _CCMPValue == 0, flag _timerDone for next cycle
+ // If last one (_CCMPValueRemaining < MAX_COUNT_16BIT) => load _CCMP register _CCMPValueRemaining
+ ITimer0.adjust_CCMPValue();
}
-
- // Clear interrupt flag
- TCB0.INTFLAGS = TCB_CAPT_bm;
}
- #endif //#ifndef TIMER0_INSTANTIATED
+ else
+ {
+ TISR_LOGWARN(("T0 done"));
+
+ ITimer0.detachInterrupt();
+ }
+ }
+
+ // Clear interrupt flag
+ TCB0.INTFLAGS = TCB_CAPT_bm;
+}
+#endif //#ifndef TIMER0_INSTANTIATED
#endif //#if USE_TIMER_0
///////////////////////////////////////////
-#if USE_TIMER_1
+#if USE_TIMER_1
#ifndef TIMER1_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER1_INSTANTIATED
- TimerInterrupt ITimer1(HW_TIMER_1);
-
- // Timer0 is used for micros(), millis(), delay(), etc and can't be used
- // Pre-instatiate
-
- ISR(TCB1_INT_vect)
+// To force pre-instatiate only once
+#define TIMER1_INSTANTIATED
+TimerInterrupt ITimer1(HW_TIMER_1);
+
+// Timer0 is used for micros(), millis(), delay(), etc and can't be used
+// Pre-instatiate
+
+ISR(TCB1_INT_vect)
+{
+ long countLocal = ITimer1.getCount();
+
+ if (ITimer1.getTimer() == 1)
{
- long countLocal = ITimer1.getCount();
-
- if (ITimer1.getTimer() == 1)
+ if (countLocal != 0)
{
- if (countLocal != 0)
+ if (ITimer1.checkTimerDone())
{
- if (ITimer1.checkTimerDone())
+ TISR_LOGDEBUG3(("T1 callback, _CCMPValueRemaining ="), ITimer1.get_CCMPValueRemaining(), (", millis ="), millis());
+
+ ITimer1.callback();
+
+ // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT if _CCMPValueRemaining > MAX_COUNT_16BIT
+ if (ITimer1.get_CCMPValue() > MAX_COUNT_16BIT)
{
- TISR_LOGDEBUG3(("T1 callback, _CCMPValueRemaining ="), ITimer1.get_CCMPValueRemaining(), (", millis ="), millis());
-
- ITimer1.callback();
-
- // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT if _CCMPValueRemaining > MAX_COUNT_16BIT
- if (ITimer1.get_CCMPValue() > MAX_COUNT_16BIT)
- {
- ITimer1.reload_CCMPValue();
- }
-
- if (countLocal > 0)
- ITimer1.setCount(countLocal - 1);
+ ITimer1.reload_CCMPValue();
}
- else
- {
- //Deduct _CCMPValue by min(MAX_COUNT_16BIT, _CCMPValue)
- // If _CCMPValue == 0, flag _timerDone for next cycle
- // If last one (_CCMPValueRemaining < MAX_COUNT_16BIT) => load _CCMP register _CCMPValueRemaining
- ITimer1.adjust_CCMPValue();
- }
+
+ if (countLocal > 0)
+ ITimer1.setCount(countLocal - 1);
}
else
{
- TISR_LOGWARN(("T1 done"));
-
- ITimer1.detachInterrupt();
+ //Deduct _CCMPValue by min(MAX_COUNT_16BIT, _CCMPValue)
+ // If _CCMPValue == 0, flag _timerDone for next cycle
+ // If last one (_CCMPValueRemaining < MAX_COUNT_16BIT) => load _CCMP register _CCMPValueRemaining
+ ITimer1.adjust_CCMPValue();
}
}
-
- // Clear interrupt flag
- TCB1.INTFLAGS = TCB_CAPT_bm;
+ else
+ {
+ TISR_LOGWARN(("T1 done"));
+
+ ITimer1.detachInterrupt();
+ }
}
-
+
+ // Clear interrupt flag
+ TCB1.INTFLAGS = TCB_CAPT_bm;
+}
+
#endif //#ifndef TIMER1_INSTANTIATED
#endif //#if USE_TIMER_1
@@ -792,51 +801,51 @@ class TimerInterrupt
#if USE_TIMER_2
#ifndef TIMER2_INSTANTIATED
- #define TIMER2_INSTANTIATED
- TimerInterrupt ITimer2(HW_TIMER_2);
-
- ISR(TCB2_INT_vect)
+#define TIMER2_INSTANTIATED
+TimerInterrupt ITimer2(HW_TIMER_2);
+
+ISR(TCB2_INT_vect)
+{
+ long countLocal = ITimer2.getCount();
+
+ if (ITimer2.getTimer() == 2)
{
- long countLocal = ITimer2.getCount();
-
- if (ITimer2.getTimer() == 2)
+ if (countLocal != 0)
{
- if (countLocal != 0)
+ if (ITimer2.checkTimerDone())
{
- if (ITimer2.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T2 callback, _CCMPValueRemaining ="), ITimer2.get_CCMPValueRemaining(), (", millis ="), millis());
-
- ITimer2.callback();
-
- // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT if _CCMPValueRemaining > MAX_COUNT_16BIT
- if (ITimer2.get_CCMPValue() > MAX_COUNT_16BIT)
- {
- ITimer2.reload_CCMPValue();
- }
+ TISR_LOGDEBUG3(("T2 callback, _CCMPValueRemaining ="), ITimer2.get_CCMPValueRemaining(), (", millis ="), millis());
- if (countLocal > 0)
- ITimer2.setCount(countLocal - 1);
+ ITimer2.callback();
+ // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT if _CCMPValueRemaining > MAX_COUNT_16BIT
+ if (ITimer2.get_CCMPValue() > MAX_COUNT_16BIT)
+ {
+ ITimer2.reload_CCMPValue();
}
- else
- {
- //Deduct _CCMPValue by min(MAX_COUNT_8BIT, _CCMPValue)
- // If _CCMPValue == 0, flag _timerDone for next cycle
- ITimer2.adjust_CCMPValue();
- }
- }
+
+ if (countLocal > 0)
+ ITimer2.setCount(countLocal - 1);
+
+ }
else
{
- TISR_LOGWARN(("T2 done"));
-
- ITimer2.detachInterrupt();
+ //Deduct _CCMPValue by min(MAX_COUNT_8BIT, _CCMPValue)
+ // If _CCMPValue == 0, flag _timerDone for next cycle
+ ITimer2.adjust_CCMPValue();
}
}
-
- // Clear interrupt flag
- TCB2.INTFLAGS = TCB_CAPT_bm;
- }
+ else
+ {
+ TISR_LOGWARN(("T2 done"));
+
+ ITimer2.detachInterrupt();
+ }
+ }
+
+ // Clear interrupt flag
+ TCB2.INTFLAGS = TCB_CAPT_bm;
+}
#endif //#ifndef TIMER2_INSTANTIATED
#endif //#if USE_TIMER_2
@@ -844,55 +853,55 @@ class TimerInterrupt
// Pre-instatiate
#if USE_TIMER_3
- #ifndef TIMER3_INSTANTIATED
- // To force pre-instatiate only once
- #define TIMER3_INSTANTIATED
- TimerInterrupt ITimer3(HW_TIMER_3);
-
- ISR(TCB3_INT_vect)
- {
- long countLocal = ITimer3.getCount();
-
- if (ITimer3.getTimer() == 3)
+#ifndef TIMER3_INSTANTIATED
+// To force pre-instatiate only once
+#define TIMER3_INSTANTIATED
+TimerInterrupt ITimer3(HW_TIMER_3);
+
+ISR(TCB3_INT_vect)
+{
+ long countLocal = ITimer3.getCount();
+
+ if (ITimer3.getTimer() == 3)
+ {
+ if (countLocal != 0)
+ {
+ if (ITimer3.checkTimerDone())
{
- if (countLocal != 0)
- {
- if (ITimer3.checkTimerDone())
- {
- TISR_LOGDEBUG3(("T3 callback, _CCMPValueRemaining ="), ITimer3.get_CCMPValueRemaining(), (", millis ="), millis());
-
- ITimer3.callback();
-
- // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT if _CCMPValueRemaining > MAX_COUNT_16BIT
- if (ITimer3.get_CCMPValue() > MAX_COUNT_16BIT)
- {
- ITimer3.reload_CCMPValue();
- }
-
- if (countLocal > 0)
- ITimer3.setCount(countLocal - 1);
- }
- else
- {
- //Deduct _CCMPValue by min(MAX_COUNT_16BIT, _CCMPValue)
- // If _CCMPValue == 0, flag _timerDone for next cycle
- // If last one (_CCMPValueRemaining < MAX_COUNT_16BIT) => load _CCMP register _CCMPValueRemaining
- ITimer3.adjust_CCMPValue();
- }
- }
- else
+ TISR_LOGDEBUG3(("T3 callback, _CCMPValueRemaining ="), ITimer3.get_CCMPValueRemaining(), (", millis ="), millis());
+
+ ITimer3.callback();
+
+ // To reload _CCMPValueRemaining as well as _CCMP register to MAX_COUNT_16BIT if _CCMPValueRemaining > MAX_COUNT_16BIT
+ if (ITimer3.get_CCMPValue() > MAX_COUNT_16BIT)
{
- TISR_LOGWARN(("T3 done"));
-
- ITimer3.detachInterrupt();
+ ITimer3.reload_CCMPValue();
}
+
+ if (countLocal > 0)
+ ITimer3.setCount(countLocal - 1);
}
-
- // Clear interrupt flag
- TCB3.INTFLAGS = TCB_CAPT_bm;
- }
-
- #endif //#ifndef TIMER3_INSTANTIATED
+ else
+ {
+ //Deduct _CCMPValue by min(MAX_COUNT_16BIT, _CCMPValue)
+ // If _CCMPValue == 0, flag _timerDone for next cycle
+ // If last one (_CCMPValueRemaining < MAX_COUNT_16BIT) => load _CCMP register _CCMPValueRemaining
+ ITimer3.adjust_CCMPValue();
+ }
+ }
+ else
+ {
+ TISR_LOGWARN(("T3 done"));
+
+ ITimer3.detachInterrupt();
+ }
+ }
+
+ // Clear interrupt flag
+ TCB3.INTFLAGS = TCB_CAPT_bm;
+}
+
+#endif //#ifndef TIMER3_INSTANTIATED
#endif //#if USE_TIMER_3
#endif //#ifndef MEGA_AVR_TIMERINTERRUPT_H
diff --git a/utils/astyle_library.conf b/utils/astyle_library.conf
new file mode 100644
index 00000000..8a73bc27
--- /dev/null
+++ b/utils/astyle_library.conf
@@ -0,0 +1,70 @@
+# Code formatting rules for Arduino libraries, modified from for KH libraries:
+#
+# https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf
+#
+
+# astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino
+
+--mode=c
+--lineend=linux
+--style=allman
+
+# -r or -R
+#--recursive
+
+# -c => Converts tabs into spaces
+convert-tabs
+
+# -s2 => 2 spaces indentation
+--indent=spaces=2
+
+# -t2 => tab =2 spaces
+#--indent=tab=2
+
+# -C
+--indent-classes
+
+# -S
+--indent-switches
+
+# -xW
+--indent-preproc-block
+
+# -Y => indent classes, switches (and cases), comments starting at column 1
+--indent-col1-comments
+
+# -M120 => maximum of 120 spaces to indent a continuation line
+--max-continuation-indent=120
+
+# -xC120 => max‑code‑length will break a line if the code exceeds # characters
+--max-code-length=120
+
+# -f =>
+--break-blocks
+
+# -p => put a space around operators
+--pad-oper
+
+# -xg => Insert space padding after commas
+--pad-comma
+
+# -H => put a space after if/for/while
+pad-header
+
+# -xb => Break one line headers (e.g. if/for/while)
+--break-one-line-headers
+
+# -c => Converts tabs into spaces
+#--convert-tabs
+
+# if you like one-liners, keep them
+#keep-one-line-statements
+
+# -xV
+--attach-closing-while
+
+#unpad-paren
+
+# -xp
+remove-comment-prefix
+
diff --git a/utils/restyle.sh b/utils/restyle.sh
new file mode 100644
index 00000000..bcd846f7
--- /dev/null
+++ b/utils/restyle.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+for dir in . ; do
+ find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \;
+done
+