- Important Change from v1.6.0
- Why do we need this SAMD_TimerInterrupt library
- Changelog
- Prerequisites
- Installation
- Packages' Patches
- Libraries' Patches
- HOWTO Fix
Multiple DefinitionsLinker Error - New from v1.0.0
- Usage
- Examples
- 1. Argument_None
- 2. Argument_None_uS
- 3. ISR_16_Timers_Array
- 4. ISR_RPM_Measure
- 5. ISR_Timer_Complex_Ethernet
- 6. ISR_Timer_Complex_WiFiNINA
- 7. RPM_Measure
- 8. SwitchDebounce
- 9. TimerInterruptTest
- 10. TimerInterruptLEDDemo
- 11. Change_Interval
- 12. ISR_16_Timers_Array_Complex
- 13. RepeatedAttachInterrupt_uS
- 14. multiFileProject
- 15. SAMD21_MultiTimers New
- Example ISR_16_Timers_Array_Complex
- Debug Terminal Output Samples
- 1. ISR_Timer_Complex_WiFiNINA on Arduino SAMD21 SAMD_NANO_33_IOT using WiFiNINA
- 2. TimerInterruptTest on Adafruit SAMD51 ITSYBITSY_M4
- 3. Argument_None on Arduino SAMD21 SAMD_NANO_33_IOT
- 4. ISR_16_Timers_Array on Arduino SAMD21 SAMD_NANO_33_IOT
- 5. Change_Interval on Arduino SAMD21 SAMD_NANO_33_IOT
- 6. RepeatedAttachInterrupt_uS on SAMD21 SEEED_XIAO_M0
- 7. SAMD21_MultiTimers on SAMD21 SAMD_NANO_33_IOT
- Debug
- Troubleshooting
- Issues
- TO DO
- DONE
- Contributions and Thanks
- Contributing
- License
- Copyright
Please have a look at HOWTO Fix Multiple Definitions Linker Error
Why do we need this SAMD_TimerInterrupt library
This library enables you to use Interrupt from Hardware Timers on an SAMD-based board, such as SAMD21 Nano-33-IoT, Adafruit SAMD51 Itsy-Bitsy M4, SparkFun SAMD51 MicroMod, etc.
As Hardware Timers are rare, and very precious assets of any board, this library now enables you to use up to 16 ISR-based Timers, while consuming only 1 Hardware Timer. Timers' interval is very long (ulong millisecs).
Now with these new 16 ISR-based timers, the maximum interval is practically unlimited (limited only by unsigned long miliseconds) while the accuracy is nearly perfect compared to software timers.
The most important feature is they're ISR-based timers. Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks.
The ISR_Timer_Complex example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs of each type of timers.
Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet and Blynk services. You can also have many (up to 16) timers to use.
This non-being-blocked important feature is absolutely necessary for mission-critical tasks.
You'll see blynkTimer Software is blocked while system is connecting to WiFi / Internet / Blynk, as well as by blocking task in loop(), using delay() function as an example. The elapsed time then is very unaccurate
Imagine you have a system with a mission-critical function, measuring water level and control the sump pump or doing something much more important. You normally use a software timer to poll, or even place the function in loop(). But what if another function is blocking the loop() or setup().
So your function might not be executed, and the result would be disastrous.
You'd prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.).
The correct choice is to use a Hardware Timer with Interrupt to call your function.
These hardware timers, using interrupt, still work even if other functions are blocking. 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.
Functions using normal software timers, relying on loop() and calling millis(), won't work if the loop() or setup() is blocked by certain operation. For example, certain function is blocking while it's connecting to WiFi or some services.
The catch is your function is now part of an ISR (Interrupt Service Routine), and must be lean / mean, and follow certain rules. More to read on:
- Arduino SAMD21 (ZERO, MKR, NANO_33_IOT, etc.).
- Adafruit SAM21 (Itsy-Bitsy M0, Metro M0, Feather M0, Gemma M0, etc.).
- Adafruit SAM51 (Itsy-Bitsy M4, Metro M4, Grand Central M4, Feather M4 Express, etc.).
- Seeeduino SAMD21/SAMD51 boards (SEEED_WIO_TERMINAL, SEEED_FEMTO_M0, SEEED_XIAO_M0, Wio_Lite_MG126, WIO_GPS_BOARD, SEEEDUINO_ZERO, SEEEDUINO_LORAWAN, SEEED_GROVE_UI_WIRELESS, etc.)
- Sparkfun SAMD21 boards such as SparkFun_RedBoard_Turbo, SparkFun_Qwiic_Micro, etc.
- Sparkfun SAMD51 boards such as SparkFun_SAMD51_Thing_Plus, SparkFun_SAMD51_MicroMod, etc.
-
Inside the attached function, delay() won’t work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.
-
Typically global variables are used to pass data between an ISR and the main program. To make sure variables shared between an ISR and the main program are updated correctly, declare them as volatile.
-
The maximum time you can use directly on SAMD TC3/TCC Timer is ~1398.11ms = 1.39811s. If you use time larger than 1398.11ms, the wrap-around will happen and you'll get much smaller time.
Arduino IDE 1.8.19+for Arduino.Arduino SAMD core 1.8.13+for SAMD ARM Cortex-M0+ boards.Adafruit SAMD core 1.7.10+for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.).Seeeduino SAMD core 1.8.3+for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.).Sparkfun SAMD core 1.8.7+for SAMD21/SAMD51 boards (SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc.).Blynk library 1.1.0.to use with some examples. Don't use Blynk beta versions.
- To use with some examples, depending on which Ethernet card you're using:
Ethernet_Generic library v2.6.1+for W5100, W5200 and W5500/WIZ550io/WIZ850io/USR-ES1 with Wiznet W5500 chip.EthernetENC library v2.0.3+for ENC28J60.. New and Better
UIPEthernet library v2.0.12+for ENC28J60.
- To use with some examples
SimpleTimer libraryfor ISR_16_Timers_Array and ISR_16_Timers_Array_Complex examples. New to avoid error witholdSparkfun core.
The best and easiest way is to use Arduino Library Manager. Search for SAMD_TimerInterrupt, then select / install the latest version. You can also use this link for more detailed instructions.
Another way to install is to:
- Navigate to SAMD_TimerInterrupt page.
- Download the latest release
SAMD_TimerInterrupt-master.zip. - Extract the zip file to
SAMD_TimerInterrupt-masterdirectory - Copy whole
SAMD_TimerInterrupt-masterfolder to Arduino libraries' directory such as~/Arduino/libraries/.
- Install VS Code
- Install PlatformIO
- Install SAMD_TimerInterrupt library by using Library Manager. Search for SAMD_TimerInterrupt in Platform.io Author's Libraries
- Use included platformio.ini file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at Project Configuration File
To be able to compile, run and automatically detect and display BOARD_NAME on Arduino SAMD (Nano-33-IoT, etc) boards, you have to copy the whole Arduino SAMD Packages_Patches directory into Arduino SAMD directory (~/.arduino15/packages/arduino/hardware/samd/1.8.13).
Supposing the Arduino SAMD version is 1.8.13. Now only one file must be copied into the directory:
~/.arduino15/packages/arduino/hardware/samd/1.8.13/platform.txt
Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz
This file must be copied into the directory:
~/.arduino15/packages/arduino/hardware/samd/x.yy.zz/platform.txt
Supposing the Arduino SAMD version is 1.8.9. These files must be copied into the directory:
~/.arduino15/packages/arduino/hardware/samd/1.8.9/platform.txt~/.arduino15/packages/arduino/hardware/samd/1.8.9/cores/arduino/Arduino.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/arduino/hardware/samd/x.yy.z/platform.txt~/.arduino15/packages/arduino/hardware/samd/x.yy.z/cores/arduino/Arduino.h
This is mandatory to fix the notorious Arduino SAMD compiler error. See Improve Arduino compatibility with the STL (min and max macro)
...\arm-none-eabi\include\c++\7.2.1\bits\stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2 min(const _Tp& __a, const _Tp& __b, _Compare __comp) Whenever the above-mentioned compiler error issue is fixed with the new Arduino SAMD release, you don't need to copy the Arduino.h file anymore.
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 directory into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.10).
Supposing the Adafruit SAMD core version is 1.7.10. This file 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
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:
~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/platform.txt~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.h~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.cpp
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 directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3).
Supposing the Seeeduino SAMD core version is 1.8.3. This file must be copied into the directory:
~/.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:
~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/platform.txt~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Arduino.h~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.h~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.cpp
Notes: These patches are totally optional and necessary only when you use the related Ethernet library and get certain error or issues.
If your application requires 2K+ HTML page, the current Ethernet library must be modified if you are using W5200/W5500 Ethernet shields. W5100 is not supported for 2K+ buffer. If you use boards requiring different CS/SS pin for W5x00 Ethernet shield, for example ESP32, ESP8266, nRF52, etc., you also have to modify the following libraries to be able to specify the CS/SS pin correctly.
To fix Ethernet library, just copy these following files into the Ethernet library directory to overwrite the old files:
To fix EthernetLarge library, just copy these following files into the EthernetLarge library directory to overwrite the old files:
To fix Ethernet2 library, just copy these following files into the Ethernet2 library directory to overwrite the old files:
To add UDP Multicast support, necessary for the UPnP_Generic library:
- To fix
Ethernet3 library, just copy these following files into theEthernet3 librarydirectory to overwrite the old files:
To be able to compile and run on nRF52 boards with ENC28J60 using UIPEthernet library, you have to copy these following files into the UIPEthernet utility directory to overwrite the old files:
To fix ESP32 compile error, just copy the following file into the ESP32 cores/esp32 directory (e.g. ./arduino-1.8.12/hardware/espressif/cores/esp32) to overwrite the old file:
The current library implementation, using xyz-Impl.h instead of standard xyz.cpp, possibly creates certain Multiple Definitions Linker error in certain use cases.
You can include .hpp
// Can be included as many times as necessary, without `Multiple Definitions` Linker Error #include "SAMDTimerInterrupt.hpp" //https://github.com/khoih-prog/SAMD_TimerInterrupt // Can be included as many times as necessary, without `Multiple Definitions` Linker Error #include "SAMD_ISR_Timer.hpp" //https://github.com/khoih-prog/SAMD_TimerInterruptin many files. But be sure to use the following .h files in just 1 .h, .cpp or .ino file, which must not be included in any other file, to avoid Multiple Definitions Linker Error
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error #include "SAMDTimerInterrupt.h" //https://github.com/khoih-prog/SAMD_TimerInterrupt // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error #include "SAMD_ISR_Timer.h" //https://github.com/khoih-prog/SAMD_TimerInterruptNow with these new 16 ISR-based timers (while consuming only 1 hardware timer), the maximum interval is practically unlimited (limited only by unsigned long miliseconds). The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks.
The ISR_Timer_Complex example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs of each type of timers. Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet and Blynk services. You can also have many (up to 16) timers to use. This non-being-blocked important feature is absolutely necessary for mission-critical tasks. You'll see blynkTimer Software is blocked while system is connecting to WiFi / Internet / Blynk, as well as by blocking task in loop(), using delay() function as an example. The elapsed time then is very unaccurate
Before using any Timer, you have to make sure the Timer has not been used by any other purpose.
// Select only one to be true for SAMD21. Must must be placed at the beginning before #include "SAMDTimerInterrupt.h" #define USING_TIMER_TC3 true // Only TC3 can be used for SAMD51 #define USING_TIMER_TC4 false // Not to use with Servo library #define USING_TIMER_TC5 false #define USING_TIMER_TCC false #define USING_TIMER_TCC1 false #define USING_TIMER_TCC2 false // Don't use this, can crash on some boards // Uncomment To test if conflict with Servo library //#include "Servo.h" ///////////////////////////////////////////////////////////////// // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error #include "SAMDTimerInterrupt.h" ////////////////////////////////////////////// // TC3, TC4, TC5 max permissible TIMER_INTERVAL_MS is 1398.101 ms, larger will overflow, therefore not permitted // Use TCC, TCC1, TCC2 for longer TIMER_INTERVAL_MS #define TIMER_INTERVAL_MS 1000 #if USING_TIMER_TC3 #define SELECTED_TIMER TIMER_TC3 #elif USING_TIMER_TC4 #define SELECTED_TIMER TIMER_TC4 #elif USING_TIMER_TC5 #define SELECTED_TIMER TIMER_TC5 #elif USING_TIMER_TCC #define SELECTED_TIMER TIMER_TCC #elif USING_TIMER_TCC1 #define SELECTED_TIMER TIMER_TCC1 #elif USING_TIMER_TCC2 #define SELECTED_TIMER TIMER_TCC #else #error You have to select 1 Timer #endif // Init selected SAMD timer SAMDTimer ITimer(SELECTED_TIMER);void TimerHandler() { // Doing something here inside ISR } // TC3, TC4, TC5 max permissible TIMER_INTERVAL_MS is 1398.101 ms, larger will overflow, therefore not permitted // Use TCC, TCC1, TCC2 for longer TIMER_INTERVAL_MS #define TIMER_INTERVAL_MS 1000 // 1s = 1000ms void setup() { .... // Interval in microsecs if (ITimer.attachInterruptInterval_MS(TIMER_INTERVAL_MS, TimerHandler0)) Serial.println("Starting ITimer OK, millis() = " + String(millis())); else Serial.println("Can't set ITimer. Select another freq. or timer"); } // Select only one to be true for SAMD21. Must must be placed at the beginning before #include "SAMDTimerInterrupt.h" #define USING_TIMER_TC3 true // Only TC3 can be used for SAMD51 #define USING_TIMER_TC4 false // Not to use with Servo library #define USING_TIMER_TC5 false #define USING_TIMER_TCC false #define USING_TIMER_TCC1 false #define USING_TIMER_TCC2 false // Don't use this, can crash on some boards // Uncomment To test if conflict with Servo library //#include "Servo.h" ///////////////////////////////////////////////////////////////// // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error #include "SAMDTimerInterrupt.h" ////////////////////////////////////////////// // TC3, TC4, TC5 max permissible TIMER_INTERVAL_MS is 1398.101 ms, larger will overflow, therefore not permitted // Use TCC, TCC1, TCC2 for longer TIMER_INTERVAL_MS #define TIMER_INTERVAL_MS 1000 #if USING_TIMER_TC3 #define SELECTED_TIMER TIMER_TC3 #elif USING_TIMER_TC4 #define SELECTED_TIMER TIMER_TC4 #elif USING_TIMER_TC5 #define SELECTED_TIMER TIMER_TC5 #elif USING_TIMER_TCC #define SELECTED_TIMER TIMER_TCC #elif USING_TIMER_TCC1 #define SELECTED_TIMER TIMER_TCC1 #elif USING_TIMER_TCC2 #define SELECTED_TIMER TIMER_TCC #else #error You have to select 1 Timer #endif // Init selected SAMD timer SAMDTimer ITimer(SELECTED_TIMER); // Init SAMD_ISR_Timer // Each SAMD_ISR_Timer can service 16 different ISR-based timers ISR_Timer SAMD_ISR_Timer;void TimerHandler(void) { ISR_Timer.run(); } #define HW_TIMER_INTERVAL_MS 50L #define TIMER_INTERVAL_2S 2000L #define TIMER_INTERVAL_5S 5000L #define TIMER_INTERVAL_11S 11000L #define TIMER_INTERVAL_101S 101000L // In SAMD, avoid doing something fancy in ISR, for example complex Serial.print with String() argument // The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment // Or you can get this run-time error / crash void doingSomething2s() { // Doing something here inside ISR } void doingSomething5s() { // Doing something here inside ISR } void doingSomething11s() { // Doing something here inside ISR } void doingSomething101s() { // Doing something here inside ISR } void setup() { .... // Interval in microsecs if (ITimer.attachInterruptInterval_MS(HW_TIMER_INTERVAL_MS, TimerHandler)) { lastMillis = millis(); Serial.println("Starting ITimer OK, millis() = " + String(lastMillis)); } else Serial.println("Can't set ITimer correctly. Select another freq. or interval"); // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary // You can use up to 16 timer for each ISR_Timer SAMD_ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s); SAMD_ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s); SAMD_ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s); SAMD_ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s); } - Argument_None
- Argument_None_uS.
- ISR_16_Timers_Array
- ISR_RPM_Measure
- ISR_Timer_Complex_Ethernet
- ISR_Timer_Complex_WiFiNINA
- RPM_Measure
- SwitchDebounce
- TimerInterruptTest
- TimerInterruptLEDDemo
- Change_Interval.
- ISR_16_Timers_Array_Complex.
- RepeatedAttachInterrupt_uS.
- multiFileProject.
- SAMD21_MultiTimers. New
Example ISR_16_Timers_Array_Complex
The following is the sample terminal output when running example ISR_Timer_Complex_WiFiNINA on SAMD_NANO_33_IOT using Built-in WiFiNINA to demonstrate the accuracy of ISR Hardware Timer, especially when system is very busy. The ISR timer is programmed for 2s, is activated exactly after 2.000s !!!
While software timer, programmed for 2s, is activated after 7.937s !!!. Then in loop(), it's also activated every 3s.
Starting ISR_Timer_Complex_WiFiNINA on SAMD_NANO_33_IOT SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Starting ITimer OK, millis() = 810 Start Blynk [1571] WiFiNINA Firmware Version: 1.4.1 [1572] Con2:HueNet1 2s: Delta ms = 2000 [5439] ConW OK [5439] IP:192.168.2.98 [5439] ___ __ __ / _ )/ /_ _____ / /__ / _ / / // / _ \/ '_/ /____/_/\_, /_//_/_/\_\ /___/ v0.6.1 on NANO_33_IOT [5440] BlynkArduinoClient.connect: Connecting to account.duckdns.org:8080 [5673] Ready (ping: 6ms). IP = 192.168.2.98 2s: Delta ms = 2000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 7937 2s: Delta ms = 2000 2s: Delta ms = 2000 5s: Delta ms = 5000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3002 2s: Delta ms = 2000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3002 2s: Delta ms = 2000 5s: Delta ms = 5000 2s: Delta ms = 2000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3002 2s: Delta ms = 2000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3004 2s: Delta ms = 2000 5s: Delta ms = 5000 2s: Delta ms = 2000 11s: Delta ms = 11000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3002 2s: Delta ms = 2000 5s: Delta ms = 5000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3003 2s: Delta ms = 2000 2s: Delta ms = 2000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3002 2s: Delta ms = 2000 5s: Delta ms = 5000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3004 2s: Delta ms = 2000 11s: Delta ms = 11000 2s: Delta ms = 2000 blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3002 5s: Delta ms = 5000 2s: Delta ms = 2000 The following is the sample terminal output when running example TimerInterruptTest on Adafruit SAMD51 ITSYBITSY_M4 to demonstrate how to start/stop Hardware Timers.
Starting TimerInterruptTest on ITSYBITSY_M4 SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 120 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 0x4101c000 , TC3 = 0x 0x4101c000 Starting ITimer1 OK, millis() = 1820 ITimer0: millis() = 2820, delta = 1000 ITimer0: millis() = 3820, delta = 1000 ITimer0: millis() = 4820, delta = 1000 Stop ITimer0, millis() = 5001 Start ITimer0, millis() = 10002 ITimer0: millis() = 11002, delta = 1000 ITimer0: millis() = 12002, delta = 1000 ITimer0: millis() = 13002, delta = 1000 ITimer0: millis() = 14002, delta = 1000 ITimer0: millis() = 15002, delta = 1000 Stop ITimer0, millis() = 15003 Start ITimer0, millis() = 20004 ITimer0: millis() = 21004, delta = 1000 ITimer0: millis() = 22004, delta = 1000 ITimer0: millis() = 23004, delta = 1000 ITimer0: millis() = 24004, delta = 1000 ITimer0: millis() = 25004, delta = 1000 Stop ITimer0, millis() = 25005 Start ITimer0, millis() = 30006 ITimer0: millis() = 31006, delta = 1000 ITimer0: millis() = 32006, delta = 1000 ITimer0: millis() = 33006, delta = 1000 ITimer0: millis() = 34006, delta = 1000 ITimer0: millis() = 35006, delta = 1000 Stop ITimer0, millis() = 35007 Start ITimer0, millis() = 40008 ITimer0: millis() = 41008, delta = 1000 ITimer0: millis() = 42008, delta = 1000 ITimer0: millis() = 43008, delta = 1000 ITimer0: millis() = 44008, delta = 1000 ITimer0: millis() = 45008, delta = 1000 Stop ITimer0, millis() = 45009 Start ITimer0, millis() = 50010 ITimer0: millis() = 51010, delta = 1000 ITimer0: millis() = 52010, delta = 1000 ITimer0: millis() = 53010, delta = 1000 ITimer0: millis() = 54010, delta = 1000 ITimer0: millis() = 55010, delta = 1000 Stop ITimer0, millis() = 55011 Start ITimer0, millis() = 60012 ITimer0: millis() = 61012, delta = 1000 ITimer0: millis() = 62012, delta = 1000 ITimer0: millis() = 63012, delta = 1000 ITimer0: millis() = 64012, delta = 1000 ITimer0: millis() = 65012, delta = 1000 Stop ITimer0, millis() = 65013 Start ITimer0, millis() = 70014 ITimer0: millis() = 71014, delta = 1000 ITimer0: millis() = 72014, delta = 1000 ITimer0: millis() = 73014, delta = 1000 ITimer0: millis() = 74014, delta = 1000 ITimer0: millis() = 75014, delta = 1000 Stop ITimer0, millis() = 75015 Start ITimer0, millis() = 80016 ITimer0: millis() = 81016, delta = 1000 ITimer0: millis() = 82016, delta = 1000 ITimer0: millis() = 83016, delta = 1000 ITimer0: millis() = 84016, delta = 1000 ITimer0: millis() = 85016, delta = 1000 Stop ITimer0, millis() = 85017 Start ITimer0, millis() = 90018 ITimer0: millis() = 91018, delta = 1000 The following is the sample terminal output when running example Argument_None on Arduino SAMD21 SAMD_NANO_33_IOT to demonstrate how to start/stop Multiple Hardware Timers.
Starting Argument_None on SAMD_NANO_33_IOT SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Starting ITimer1 OK, millis() = 910 F_CPU (MHz) = 48 TC_Timer::startTimer _Timer = 0x42002000, TCC0 = 0x42002000 Starting ITimer1 OK, millis() = 911 ITimer0: millis() = 1410, delta = 500 ITimer0: millis() = 1910, delta = 500 ITimer0: millis() = 2410, delta = 500 ITimer0: millis() = 2910, delta = 500 ITimer1: millis() = 2911, delta = 2000 ITimer0: millis() = 3410, delta = 500 ITimer0: millis() = 3910, delta = 500 ITimer0: millis() = 4410, delta = 500 ITimer0: millis() = 4910, delta = 500 ITimer1: millis() = 4911, delta = 2000 ITimer0: millis() = 5410, delta = 500 ITimer0: millis() = 5910, delta = 500 ITimer0: millis() = 6410, delta = 500 ITimer0: millis() = 6910, delta = 500 ITimer1: millis() = 6911, delta = 2000 ITimer0: millis() = 7410, delta = 500 ITimer0: millis() = 7910, delta = 500 ITimer0: millis() = 8410, delta = 500 ITimer0: millis() = 8910, delta = 500 ITimer1: millis() = 8911, delta = 2000 ITimer0: millis() = 9410, delta = 500 ITimer0: millis() = 9910, delta = 500 ITimer0: millis() = 10410, delta = 500 ITimer0: millis() = 10910, delta = 500 ITimer1: millis() = 10911, delta = 2000 ITimer0: millis() = 11410, delta = 500 ITimer0: millis() = 11910, delta = 500 The following is the sample terminal output when running example ISR_16_Timers_Array on Arduino SAMD21 SAMD_NANO_33_IOT to demonstrate the accuracy of ISR Hardware Timer, especially when system is very busy or blocked. The 16 independent ISR timers are programmed to be activated repetitively after certain intervals, is activated exactly after that programmed interval !!!
While software timer, programmed for 2s, is activated after 10.000s in loop()!!!.
In this example, 16 independent ISR Timers are used, yet utilized just one Hardware Timer. The Timer Intervals and Function Pointers are stored in arrays to facilitate the code modification.
Starting ISR_16_Timers_Array on SAMD_NANO_33_IOT SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Starting ITimer OK, millis() = 1421 1s: Delta ms = 1000, ms = 2421 1s: Delta ms = 1000, ms = 3421 2s: Delta ms = 2000, ms = 3421 1s: Delta ms = 1000, ms = 4421 3s: Delta ms = 3000, ms = 4421 1s: Delta ms = 1000, ms = 5421 2s: Delta ms = 2000, ms = 5421 4s: Delta ms = 4000, ms = 5421 1s: Delta ms = 1000, ms = 6421 5s: Delta ms = 5000, ms = 6421 1s: Delta ms = 1000, ms = 7421 2s: Delta ms = 2000, ms = 7421 3s: Delta ms = 3000, ms = 7421 6s: Delta ms = 6000, ms = 7421 1s: Delta ms = 1000, ms = 8421 7s: Delta ms = 7000, ms = 8421 1s: Delta ms = 1000, ms = 9421 2s: Delta ms = 2000, ms = 9421 4s: Delta ms = 4000, ms = 9421 8s: Delta ms = 8000, ms = 9421 1s: Delta ms = 1000, ms = 10421 3s: Delta ms = 3000, ms = 10421 9s: Delta ms = 9000, ms = 10421 1s: Delta ms = 1000, ms = 11421 2s: Delta ms = 2000, ms = 11421 5s: Delta ms = 5000, ms = 11421 10s: Delta ms = 10000, ms = 11421 simpleTimerDoingSomething2s: Delta programmed ms = 2000, actual = 10000 1s: Delta ms = 1000, ms = 12421 11s: Delta ms = 11000, ms = 12421 1s: Delta ms = 1000, ms = 13421 2s: Delta ms = 2000, ms = 13421 3s: Delta ms = 3000, ms = 13421 4s: Delta ms = 4000, ms = 13421 6s: Delta ms = 6000, ms = 13421 12s: Delta ms = 12000, ms = 13421 1s: Delta ms = 1000, ms = 14421 13s: Delta ms = 13000, ms = 14421 1s: Delta ms = 1000, ms = 15421 2s: Delta ms = 2000, ms = 15421 7s: Delta ms = 7000, ms = 15421 14s: Delta ms = 14000, ms = 15421 1s: Delta ms = 1000, ms = 16421 3s: Delta ms = 3000, ms = 16421 5s: Delta ms = 5000, ms = 16421 15s: Delta ms = 15000, ms = 16421 1s: Delta ms = 1000, ms = 17421 2s: Delta ms = 2000, ms = 17421 4s: Delta ms = 4000, ms = 17421 8s: Delta ms = 8000, ms = 17421 16s: Delta ms = 16000, ms = 17421 1s: Delta ms = 1000, ms = 18421 1s: Delta ms = 1000, ms = 19421 2s: Delta ms = 2000, ms = 19421 3s: Delta ms = 3000, ms = 19421 6s: Delta ms = 6000, ms = 19421 9s: Delta ms = 9000, ms = 19421 1s: Delta ms = 1000, ms = 20421 1s: Delta ms = 1000, ms = 21421 2s: Delta ms = 2000, ms = 21421 4s: Delta ms = 4000, ms = 21421 5s: Delta ms = 5000, ms = 21421 10s: Delta ms = 10000, ms = 21421 simpleTimerDoingSomething2s: Delta programmed ms = 2000, actual = 10000 1s: Delta ms = 1000, ms = 22421 3s: Delta ms = 3000, ms = 22421 7s: Delta ms = 7000, ms = 22421 1s: Delta ms = 1000, ms = 23421 2s: Delta ms = 2000, ms = 23421 11s: Delta ms = 11000, ms = 23421 1s: Delta ms = 1000, ms = 24421 1s: Delta ms = 1000, ms = 25421 2s: Delta ms = 2000, ms = 25421 3s: Delta ms = 3000, ms = 25421 4s: Delta ms = 4000, ms = 25421 6s: Delta ms = 6000, ms = 25421 8s: Delta ms = 8000, ms = 25421 12s: Delta ms = 12000, ms = 25421 1s: Delta ms = 1000, ms = 26421 5s: Delta ms = 5000, ms = 26421 1s: Delta ms = 1000, ms = 27421 2s: Delta ms = 2000, ms = 27421 13s: Delta ms = 13000, ms = 27421 1s: Delta ms = 1000, ms = 28421 3s: Delta ms = 3000, ms = 28421 9s: Delta ms = 9000, ms = 28421 1s: Delta ms = 1000, ms = 29421 2s: Delta ms = 2000, ms = 29421 4s: Delta ms = 4000, ms = 29421 7s: Delta ms = 7000, ms = 29421 14s: Delta ms = 14000, ms = 29421 1s: Delta ms = 1000, ms = 30421 1s: Delta ms = 1000, ms = 31421 2s: Delta ms = 2000, ms = 31421 3s: Delta ms = 3000, ms = 31421 5s: Delta ms = 5000, ms = 31421 6s: Delta ms = 6000, ms = 31421 10s: Delta ms = 10000, ms = 31421 15s: Delta ms = 15000, ms = 31421 simpleTimerDoingSomething2s: Delta programmed ms = 2000, actual = 10000 1s: Delta ms = 1000, ms = 32421 1s: Delta ms = 1000, ms = 33421 2s: Delta ms = 2000, ms = 33421 4s: Delta ms = 4000, ms = 33421 8s: Delta ms = 8000, ms = 33421 16s: Delta ms = 16000, ms = 33421 1s: Delta ms = 1000, ms = 34421 3s: Delta ms = 3000, ms = 34421 11s: Delta ms = 11000, ms = 34421 The following is the sample terminal output when running example Change_Interval on Arduino SAMD21 SAMD_NANO_33_IOT to demonstrate how to change Timer Interval on-the-fly
Starting Change_Interval on SAMD_NANO_33_IOT SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Starting ITimer OK, millis() = 1131 Time = 10001, TimerCount = 17 Time = 20002, TimerCount = 37 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 1000 Time = 30003, TimerCount = 47 Time = 40004, TimerCount = 57 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 500 Time = 50005, TimerCount = 77 Time = 60006, TimerCount = 97 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 1000 Time = 70007, TimerCount = 107 Time = 80008, TimerCount = 117 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 500 Time = 90009, TimerCount = 137 Time = 100010, TimerCount = 157 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 1000 Time = 110011, TimerCount = 167 Time = 120012, TimerCount = 177 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 500 Time = 130013, TimerCount = 197 Time = 140014, TimerCount = 217 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 1000 Time = 150015, TimerCount = 227 Time = 160016, TimerCount = 237 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 500 Time = 170017, TimerCount = 257 Time = 180018, TimerCount = 277 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 Changing Interval, Timer = 1000 Time = 190019, TimerCount = 287 Time = 200020, TimerCount = 297 The following is the sample terminal output when running example RepeatedAttachInterrupt_uS on SEEED_XIAO_M0 to demonstrate how to change Timer Interval on-the-fly
Starting RepeatedAttachInterrupt_uS on SEEED_XIAO_M0 SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] _period = 19995 , frequency = 50.01 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 19995 , _prescaler = 16 [TISR] _compareValue = 59984 myClockTimer (19995) = 19993 <========== OK===============================<=======OK [TISR] _period = 19995 , frequency = 50.01 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 19995 , _prescaler = 16 [TISR] _compareValue = 59984 myClockTimer (19995) = 19993 <========== OK===============================<=======OK [TISR] _period = 19995 , frequency = 50.01 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 19995 , _prescaler = 16 [TISR] _compareValue = 59984 myClockTimer (19995) = 19993 <========== OK===============================<=======OK [TISR] _period = 19000 , frequency = 52.63 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 19000 , _prescaler = 16 [TISR] _compareValue = 56999 myClockTimer (19000) = 18998 [TISR] _period = 20005 , frequency = 49.99 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 20005 , _prescaler = 64 [TISR] _compareValue = 15002 myClockTimer (20005) = 20002 [TISR] _period = 30000 , frequency = 33.33 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 30000 , _prescaler = 64 [TISR] _compareValue = 22498 myClockTimer (30000) = 29996 [TISR] _period = 19995 , frequency = 50.01 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 19995 , _prescaler = 16 [TISR] _compareValue = 59984 myClockTimer (19995) = 19993 <========== OK===============================<=======OK [TISR] _period = 30000 , frequency = 33.33 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 30000 , _prescaler = 64 [TISR] _compareValue = 22498 myClockTimer (30000) = 29997 [TISR] _period = 19995 , frequency = 50.01 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 19995 , _prescaler = 16 [TISR] _compareValue = 59984 The following is the sample terminal output when running example SAMD21_MultiTimers on SAMD_NANO_33_IOT to demonstrate demo the how to use all 6 SAMD21 timers simultaneously.
Starting SAMD21_MultiTimers on SAMD_NANO_33_IOT SAMDTimerInterrupt v1.10.1 CPU Frequency = 48 MHz [TISR] _period = 20000.00 , frequency = 50.00 [TISR] _timerNumber = 0 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC3_Timer::startTimer _Timer = 0x 42002c00 , TC3 = 0x 42002c00 [TISR] SAMD21 TC3 period = 20000.00 , _prescaler = 16 [TISR] _compareValue = 59999 Starting TIMER_TC3 OK, millis() = 962 [TISR] _period = 50000.00 , frequency = 20.00 [TISR] _timerNumber = 1 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC4_Timer::startTimer _Timer = 0x 42003000 , TC4 = 0x 42003000 [TISR] SAMD21 TC4 period = 50000.00 , _prescaler = 64 [TISR] _compareValue = 37499 Starting TIMER_TC4 OK, millis() = 964 [TISR] _period = 100000.00 , frequency = 10.00 [TISR] _timerNumber = 2 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TC5_Timer::startTimer _Timer = 0x 42003400 , TC5 = 0x 42003400 [TISR] SAMD21 TC5 period = 100000.00 , _prescaler = 256 [TISR] _compareValue = 18749 Starting TIMER_TC5 OK, millis() = 966 [TISR] _period = 200000.00 , frequency = 5.00 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002000 , TCC0 = 0x 42002000 [TISR] SAMD21 TCC period = 200000.00 , _prescaler = 256 [TISR] _compareValue = 37499 Starting TIMER_TCC OK, millis() = 968 [TISR] _period = 500000.00 , frequency = 2.00 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002400 , TCC1 = 0x 42002400 [TISR] SAMD21 TCC1 period = 500000.00 , _prescaler = 1024 [TISR] _compareValue = 23436 Starting TIMER_TCC1 OK, millis() = 970 [TISR] _period = 1000000.00 , frequency = 1.00 [TISR] SAMDTimerInterrupt: F_CPU (MHz) = 48 , TIMER_HZ = 48 [TISR] TCC_Timer::startTimer _Timer = 0x 42002800 , TCC2 = 0x 42002800 [TISR] SAMD21 TCC2 period = 1000000.00 , _prescaler = 1024 [TISR] _compareValue = 46874 ======================================== TC3 Actual/Programmed (ms) 20/20 TC4 Actual/Programmed (ms) 50/50 TC5 Actual/Programmed (ms) 100/100 TCC Actual/Programmed (ms) 200/200 TCC1 Actual/Programmed (ms) 500/500 ======================================== TC3 Actual/Programmed (ms) 20/20 TC4 Actual/Programmed (ms) 50/50 TC5 Actual/Programmed (ms) 100/100 TCC Actual/Programmed (ms) 200/200 TCC1 Actual/Programmed (ms) 500/500 Debug is enabled by default on Serial.
You can also change the debugging level (TIMERINTERRUPT_LOGLEVEL) from 0 to 4
// These define's must be placed at the beginning before #include "SAMD_TimerInterrupt.h" // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4 // Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. #define TIMER_INTERRUPT_DEBUG 0 #define _TIMERINTERRUPT_LOGLEVEL_ 0If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards.
Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions.
Submit issues to: SAMD_TimerInterrupt issues
- Search for bug and improvement.
- Similar features for remaining Arduino boards such as SAM-DUE
- Add more Timers to SAMD51
- Basic hardware timers for SAMD21 and SAMD51.
- More hardware-initiated software-enabled timers
- Longer time interval
- Similar features for remaining Arduino boards such as ESP32, ESP8266, STM32, nRF52, mbed-nRF52, Teensy, etc.
- Add Table of Contents
- Fix
multiple-definitionslinker error - Add support to many more boards, such as
SAMD21E1xA,SAMD21G1xAandSAMD21J1xA - Optimize library code by using
reference-passinginstead ofvalue-passing - Optimize code for
setInterval()of SAMD21 TC3 - Reverse the change in
setInterval()of SAMD21 TC3 to fix bug when using SAMD21 TC3. - Add TC4, TC5, TCC1 and TCC2 Timers to SAMD21
- Add example SAMD21_MultiTimers to demo the how to use all 6 SAMD21 timers simultaneously.
- Add functions
attachInterruptInterval_MS()andsetInterval_MS() - Avoid conflict with Servo library. Check Cannot use TimerInterrupt_Generic Library in the same time than Servo Library #11
- Prevent overflow of TCx by flagging error
- Using float instead of ulong for interval
Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library.
- Use some code from the Tamasa's ZeroTimer Library.
- Use some code from the Dennis van Gils' SAMD51_InterruptTimer Library.
- Thanks to generationmake to report the issue Doesn't compile with Adafruit Feather M0 #2 leading to new release v1.3.1.
- Thanks to thiagothimotti to report the interesting hard-to-find bug in Bug when going from a >20000us period to a <20000us period. The timer period become 4 times greater. #3 leading to new release v1.4.0.
- Thanks to generationmake to make a PR in change variable period from unsigned long to float #7 leading to new release v1.5.0.
- Thanks to Alexander Golovanov to propose a PR in Add more SAMD21 #10 leading to the support of many new boards in new release v1.6.0
- Thanks to Will Powell to report the bug in Multiple Definition Error Not fixed by swapping src_cpp or src_h with src #9 leading to new release v1.6.0.
- Thanks to Dave Hooper to report the bug and propose the fix in setInterval on a running timer results in a period significantly longer than the specified period #17 leading to new release v1.7.0
- Thanks to Rui Marinheiro to start the discussion in Do I have a brick? I'm unable to upload sketches after using this library! #21 leading to new release v1.8.0 to fix the bug
- Thanks to sriccardi-invn to start the discussion in Cannot use TimerInterrupt_Generic Library in the same time than Servo Library #11 leading to new release v1.10.0 to fix the bug and add more features
![]() ⭐️ Tamasa | ![]() Dennis van Gils | ![]() generationmake | ![]() thiagothimotti | ![]() generationmake | ![]() Alexander Golovanov |
![]() Will Powell | ![]() Dave Hooper | ![]() Rui Marinheiro | ![]() sriccardi-invn |
If you want to contribute to this project:
- Report bugs and errors
- Ask for enhancements
- Create issues and pull requests
- Tell other people about this library
- The library is licensed under MIT
Copyright 2020- Khoi Hoang









