khoih-prog / TimerInterrupt_Generic

This library enables you to use Interrupt from Hardware Timers on supported Arduino boards such as AVR, ESP8266, ESP32, SAMD, SAM DUE, nRF52, Teensy, etc. 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 mandatory if you need to measure some data requiring better accuracy. 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.
MIT License
38 stars 5 forks source link
accuracy avr esp32 esp8266 hardware-timers interrupt isr mbed megaavr nano-rp2040-connect nano33ble non-blocking nrf52 pico-w rp2040 samd samdue stm32 timer timer-interrupt

TimerInterrupt_Generic Library

arduino-library-badge GitHub release GitHub contributions welcome GitHub issues

Donate to my libraries using BuyMeACoffee



Table of Contents



Why do we need this TimerInterrupt_Generic library

Features

This library enables you to use Interrupt from Hardware Timers on supported Arduino boards such as AVR, Mega-AVR, ESP8266, ESP32, SAMD, SAM DUE, nRF52, STM32F/L/H/G/WB/MP1, Teensy, Nano-33-BLE, 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).

Why using ISR-based Hardware Timer Interrupt is better

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 on-time or not at all, 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:

HOWTO Attach Interrupt

Notes for Teensy boards

You'd certainly experienced that if using other Hardware Timer Libraries, such as TimerOne or TimerThree, the interval is short, in milliseconds range.

For example, Teensy 4.x, with super-high clock frequency of 600MHz and Timer1 and Timer3 clock of 150MHz, the maximum interval / frequency is only 55922.3467 us / 17.881939 Hz. This Teensy_TimerInterrupt library will provide you up to 16 super-long (ulong millisecs) ISR Timers for each used Timer1 or Timer3.

For Teensy 4.x, this library will be expanded to use other available hardware timers, such as FTM, GPT, QUAD, PIT, in addition to current Timer1 and Timer3.


Currently Supported Boards

Important Notes about ISR

  1. 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.

  2. 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.



Prerequisites

  1. Arduino IDE 1.8.19+ for Arduino. GitHub release


  2. ESP32 Core 2.0.5+ for ESP32-based boards. Latest release

  3. ESP8266 Core 3.0.2+ for ESP8266-based boards. Latest release. To use ESP8266 core 2.7.1+ for LittleFS.

  4. Arduino AVR core 1.8.6+ for Arduino (Use Arduino Board Manager) for AVR boards. GitHub release

  5. Adafruit AVR core 1.4.13+ for Adafruit AVR boards. Use Arduino Board Manager to install.

  6. Sparkfun AVR core 1.1.13+ for Sparkfun AVR boards. Use Arduino Board Manager to install.

  7. Teensy core v1.57+ 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+ for SAM DUE ARM Cortex-M3 boards.

  9. Arduino SAMD core 1.8.13+ for SAMD ARM Cortex-M0+ boards. GitHub release

    1. Adafruit SAMD core 1.7.11+ for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). GitHub release
    2. Seeeduino SAMD core 1.8.3+ for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). Latest release
    3. Sparkfun SAMD core 1.8.1+ for SAMD21/SAMD51 boards (SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc.).
    4. Adafruit nRF52 v1.3.0+ 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
    5. Arduino Core for STM32 v2.3.0+ for STM32F/L/H/G/WB/MP1 boards. GitHub release
    6. Arduino megaAVR core 1.8.7+ for Arduino megaAVR boards. Use Arduino Board Manager to install.
    7. Arduino mbed_rp2040 core 3.4.1+ for Arduino (Use Arduino Board Manager) RP2040-based boards, such as Arduino Nano RP2040 Connect, RASPBERRY_PI_PICO, etc.. GitHub release
    8. Earle Philhower's arduino-pico core v2.6.3+ for RP2040-based boards such as RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040, etc. GitHub release
    9. MegaCoreX megaAVR core 1.1.0+ for Arduino megaAVR boards. GitHub release. Follow How to install.

  1. Blynk library 1.1.0. Latest release to use with certain examples.

  1. For built-in LAN8742A Ethernet:

  2. For W5x00 Ethernet:

  3. For ENC28J60 Ethernet:


  1. WiFiNINA_Generic library v1.8.15-0+ to use WiFiNINA modules/shields. To install. check arduino-library-badge if using WiFiNINA for boards such as Nano 33 IoT, nRF52, Teensy, etc.

  2. Blynk_WiFiNINA_WM library 1.1.2+ to use with Blynk-WiFiNINA-related example. To install. check arduino-library-badge

  3. To use with certain examples



Installation

Use Arduino Library Manager

The best and easiest way is to use Arduino Library Manager. Search for TimerInterrupt_Generic, then select / install the latest version. You can also use this link arduino-library-badge for more detailed instructions.

Manual Install

Another way to install is to:

  1. Navigate to TimerInterrupt_Generic page.
  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

  1. Install VS Code
  2. Install PlatformIO
  3. Install TimerInterrupt_Generic library by using Library Manager. Search for TimerInterrupt_Generic in Platform.io Author's Libraries
  4. 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


Packages' Patches

1. For Adafruit nRF52840 and nRF52832 boards

To be able to compile, run and automatically detect and display BOARD_NAME on nRF52840/nRF52832 boards, you have to copy the whole nRF52 Packages_Patches directory into Adafruit nRF52 directory (~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0).

Supposing the Adafruit nRF52 version is 1.3.0. These files must be copied into the directory:

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:

2. For Teensy boards

To be able to compile and run on Teensy boards, you have to copy the files in Packages_Patches for Teensy directory into Teensy hardware directory (./arduino-1.8.19/hardware/teensy/avr/boards.txt).

Supposing the Arduino version is 1.8.19. These files must be copied into the directory:

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz These files must be copied into the directory:

3. For Arduino SAM DUE boards

To be able to compile and run on SAM DUE boards, you have to copy the whole SAM DUE directory into Arduino sam directory (~/.arduino15/packages/arduino/hardware/sam/1.6.12).

Supposing the Arduino SAM core version is 1.6.12. This file must be copied into the directory:

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:

4. For Arduino SAMD boards

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).

For core version v1.8.10+

Supposing the Arduino SAMD version is 1.8.13. Now only one file must be copied into the directory:

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:

For core version v1.8.9-

Supposing the Arduino SAMD version is 1.8.9. These files must be copied into the directory:

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:

 ...\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.

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 directory into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.11).

Supposing the Adafruit SAMD core version is 1.7.11. These files must be copied into the directory:

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz These files 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 directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3).

Supposing the Seeeduino SAMD core version is 1.8.3. These files must be copied into the directory:

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz These files must be copied into the directory:

7. For STM32 boards

7.1 For STM32 boards to use LAN8720

To use LAN8720 on some STM32 boards

you have to copy the files stm32f4xx_hal_conf_default.h and stm32f7xx_hal_conf_default.h into STM32 stm32 directory (~/.arduino15/packages/STM32/hardware/stm32/2.3.0/system) to overwrite the old files.

Supposing the STM32 stm32 core version is 2.3.0. These files must be copied into the directory:

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz, these files must be copied into the corresponding directory:

7.2 For STM32 boards to use Serial1

To use Serial1 on some STM32 boards without Serial1 definition (Nucleo-144 NUCLEO_F767ZI, Nucleo-64 NUCLEO_L053R8, etc.) boards, you have to copy the files STM32 variant.h into STM32 stm32 directory (~/.arduino15/packages/STM32/hardware/stm32/2.3.0). You have to modify the files corresponding to your boards, this is just an illustration how to do.

Supposing the STM32 stm32 core version is 2.3.0. These files must be copied into the directory:

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz, these files must be copied into the corresponding directory:

8. For RP2040-based boards using Earle Philhower arduino-pico core

8.1 To use BOARD_NAME

To be able to automatically detect and display BOARD_NAME on RP2040-based boards (RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040, GENERIC_RP2040, etc) boards, you have to copy the file RP2040 platform.txt into rp2040 directory (~/.arduino15/packages/rp2040/hardware/rp2040/1.4.0).

Supposing the rp2040 core version is 1.4.0. This file must be copied into the directory:

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:

With core after v1.5.0, this step is not necessary anymore thanks to the PR Add -DBOARD_NAME="{build.board}" #136.

8.2 To avoid compile error relating to microsecondsToClockCycles

Some libraries, such as Adafruit DHT-sensor-library, require the definition of microsecondsToClockCycles(). To be able to compile and run on RP2040-based boards, you have to copy the files in RP2040 Arduino.h into rp2040 directory (~/.arduino15/packages/rp2040/hardware/rp2040/1.4.0).

Supposing the rp2040 core version is 1.4.0. This file must be copied to replace:

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 to replace:

With core after v1.5.0, this step is not necessary anymore thanks to the PR Add defs for compatibility #142.

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 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.4.1
$ chmod 755 portenta_post_install.sh
$ sudo ./portenta_post_install.sh

This will create the file /etc/udev/rules.d/49-portenta_h7.rules as follows:

# Portenta H7 bootloader mode UDEV rules

SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="035b", GROUP="plugdev", MODE="0666"

Supposing the ArduinoCore-mbed core version is 3.4.1. Now only one file must be copied into the directory:

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:

10. For RTL8720DN boards using AmebaD core

To avoid compile error relating to PROGMEM, you have to copy the file Realtek AmebaD core pgmspace.h into Realtek AmebaD directory (~/.arduino15/packages/realtek/hardware/AmebaD/3.1.4/cores/ambd/avr/pgmspace.h).

Supposing the Realtek AmebaD core version is 3.1.4. This file must be copied into the directory:

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:

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 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.9.0. This file must be copied into the directory:

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:

12. For Seeeduino RP2040 boards

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 directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2).

Supposing the Seeeduino RP2040 core version is 2.7.2. These files must be copied into the directory:

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz These files must be copied into the directory:


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 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:

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:



Libraries' Patches

1. For application requiring 2K+ HTML page

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.

2. For Ethernet library

To fix Ethernet library, just copy these following files into the Ethernet library directory to overwrite the old files:

3. For EthernetLarge library

To fix EthernetLarge library, just copy these following files into the EthernetLarge library directory to overwrite the old files:

4. For Ethernet2 library

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:

5. For Ethernet3 library

  1. To fix Ethernet3 library, just copy these following files into the Ethernet3 library directory to overwrite the old files:

6. For UIPEthernet library

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:

7. For fixing ESP32 compile error

To fix ESP32 compile error, just copy the following file into the ESP32 cores/esp32 directory (e.g. ./arduino-1.8.13/hardware/espressif/cores/esp32) to overwrite the old file:

8. For fixing ESP8266 compile error

To fix ESP8266 compile error such as

error: 'class EthernetClass' has no member named 'init'
Ethernet.init (USE_THIS_SS_PIN);

just rename the following file in ./arduino-1.8.16/hardware/esp8266com/esp8266/libraries/Ethernet directory

9. For STM32 core F3 and F4 using UIPEthernet library

Check if you need to install the UIPEthernet patch new STM32 core F3/F4 compatibility to avoid errors #include HardwareSPI.h on some STM32 boards (Nucleo-32 F303K8, etc.)



HOWTO Fix Multiple Definitions Linker Error

The current library implementation, using xyz-Impl.h instead of standard xyz.cpp, possibly creates certain Multiple Definitions Linker error in certain use cases. Although it's simple to just modify several lines of code, either in the library or in the application, the library is adding 2 more source directories

  1. scr_h for new h-only files
  2. src_cpp for standard h/cpp files

besides the standard src directory.

To use the old standard cpp way, locate this library' directory, then just

  1. Delete the all the files in src directory.
  2. Copy all the files in src_cpp directory into src.
  3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch.

To re-use the new h-only way, just

  1. Delete the all the files in src directory.
  2. Copy the files in src_h directory into src.
  3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch.


HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE)

Please have a look at ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example to have more detailed description and solution of the issue.

1. ESP32 has 2 ADCs, named ADC1 and ADC2

2. ESP32 ADCs functions

3.. ESP32 WiFi uses ADC2 for WiFi functions

Look in file adc_common.c

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. 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 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.

adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.


HOWTO Use PWM analogWrite() with ESP8266 running Timer1 Interrupt

Please have a look at ESP8266TimerInterrupt Issue 8: ESP8266Timer and PWM --> wdt reset to have more detailed description and solution of the issue.

1. ESP8266 has only 2 hardware timers, named Timer0 and Timer1

2. ESP8266 hardware timers' functions

3. How to use PWM analogWrite() functions while using this library

  1. If possible, use software timer instead of ESP8266TimerInterrupt Hardware Timer1
  2. If using ESP8266TimerInterrupt Hardware Timer1 is a must, you can either


More useful Information

1. For ESP32


2. Notes for ESP8266

The ESP8266 timers are badly designed, using only 23-bit counter along with maximum 256 prescaler. They're only better than UNO / Mega.

The ESP8266 has two hardware timers, but timer0 has been used for WiFi and it's not advisable to use. Only timer1 is available.

The timer1's 23-bit counter terribly can count only up to 8,388,607. So the timer1 maximum interval is very short. Using 256 prescaler, maximum timer1 interval is only 26.843542 seconds !!!

The timer1 counters can be configured to support automatic reload.


3. For Arduino AVR

From Arduino 101: Timers and Interrupts

3.1. Timer0:

Timer0 is a 8-bit timer.

In the Arduino world timer0 is been used for the timer functions, like delay(), millis() and micros(). If you change Timer0 registers, this may influence the Arduino timer function. So you should know what you are doing.

3.2. Timer1:

Timer1 is a 16-bit timer. In the Arduino world the Servo library uses timer1 on Arduino Uno (Timer5 on Arduino Mega).

3.3. Timer2:

Timer2 is a 8-bit timer like Timer0. In the Arduino work the tone() function uses Timer2.

3.4. Timer3, Timer4, Timer5:

Timer 3,4,5 are only available on Arduino Mega boards. These timers are all 16-bit timers.


4. For STM32F/L/H/G/WB/MP1

The Timers of STM32s are numerous, yet very sophisticated and powerful.

In general, across the STM32 microcontrollers families, the timer peripherals that have the same name also have the same features set, but there are a few exceptions.

For example, the TIM1 timer peripheral is shared across the STM32F1 Series, STM32F2 Series and STM32F4 Series, but for the specific case of STM32F30x microcontrollers family, the TIM1 timer peripheral features a bit richer features set than the TIM1 present in the other families.

The general purpose timers embedded by the STM32 microcontrollers share the same backbone structure; they differ only on the level of features embedded by a given timer peripheral.

The level of features integration for a given timer peripheral is decided based on the applications field that it targets.

The timer peripherals can be classified as: • Advanced-configuration timers like TIM1 and TIM8 among others. • General-purpose configuration timers like TIM2 and TIM3 among others • Lite-configuration timers like TIM9, TIM10, TIM12 and TIM16 among others • Basic-configuration timers like TIM6 and TIM7 among others.

For example, STM32F103C8T6 has one advance timer, while STM32F103VET6 has two advanced timers. Nucleo-144 STM32F767ZI boards have 14 Timers, TIM1-TIM14.

More information can be found at Embedded-Lab STM32 TIMERS

To be sure which Timer is available for the board you're using, check the Core Package's related files. For example, for Nucleo-144 STM32F767ZI, check these files:

  1. ~/.arduino15/packages/STM32/hardware/stm32/1.9.0/system/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f7xx.h
  2. ~/.arduino15/packages/STM32/hardware/stm32/1.9.0/system/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f767xx.h

The information will be as follows:

typedef struct
{
  __IO uint32_t CR1;         /*!< TIM control register 1,              Address offset: 0x00 */
  __IO uint32_t CR2;         /*!< TIM control register 2,              Address offset: 0x04 */
  __IO uint32_t SMCR;        /*!< TIM slave mode control register,     Address offset: 0x08 */
  __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,   Address offset: 0x0C */
  __IO uint32_t SR;          /*!< TIM status register,                 Address offset: 0x10 */
  __IO uint32_t EGR;         /*!< TIM event generation register,       Address offset: 0x14 */
  __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1, Address offset: 0x18 */
  __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2, Address offset: 0x1C */
  __IO uint32_t CCER;        /*!< TIM capture/compare enable register, Address offset: 0x20 */
  __IO uint32_t CNT;         /*!< TIM counter register,                Address offset: 0x24 */
  __IO uint32_t PSC;         /*!< TIM prescaler,                       Address offset: 0x28 */
  __IO uint32_t ARR;         /*!< TIM auto-reload register,            Address offset: 0x2C */
  __IO uint32_t RCR;         /*!< TIM repetition counter register,     Address offset: 0x30 */
  __IO uint32_t CCR1;        /*!< TIM capture/compare register 1,      Address offset: 0x34 */
  __IO uint32_t CCR2;        /*!< TIM capture/compare register 2,      Address offset: 0x38 */
  __IO uint32_t CCR3;        /*!< TIM capture/compare register 3,      Address offset: 0x3C */
  __IO uint32_t CCR4;        /*!< TIM capture/compare register 4,      Address offset: 0x40 */
  __IO uint32_t BDTR;        /*!< TIM break and dead-time register,    Address offset: 0x44 */
  __IO uint32_t DCR;         /*!< TIM DMA control register,            Address offset: 0x48 */
  __IO uint32_t DMAR;        /*!< TIM DMA address for full transfer,   Address offset: 0x4C */
  __IO uint32_t OR;          /*!< TIM option register,                 Address offset: 0x50 */
  __IO uint32_t CCMR3;       /*!< TIM capture/compare mode register 3,      Address offset: 0x54 */
  __IO uint32_t CCR5;        /*!< TIM capture/compare mode register5,       Address offset: 0x58 */
  __IO uint32_t CCR6;        /*!< TIM capture/compare mode register6,       Address offset: 0x5C */
  __IO uint32_t AF1;         /*!< TIM Alternate function option register 1, Address offset: 0x60 */
  __IO uint32_t AF2;         /*!< TIM Alternate function option register 2, Address offset: 0x64 */

} TIM_TypeDef;

and

#define PERIPH_BASE            0x40000000UL /*!< Base address of : AHB/ABP Peripherals   
/*!< Peripheral memory map */
#define APB1PERIPH_BASE        PERIPH_BASE

/*!< APB1 peripherals */
#define TIM2_BASE             (APB1PERIPH_BASE + 0x0000UL)
#define TIM3_BASE             (APB1PERIPH_BASE + 0x0400UL)
#define TIM4_BASE             (APB1PERIPH_BASE + 0x0800UL)
#define TIM5_BASE             (APB1PERIPH_BASE + 0x0C00UL)
#define TIM6_BASE             (APB1PERIPH_BASE + 0x1000UL)
#define TIM7_BASE             (APB1PERIPH_BASE + 0x1400UL)
#define TIM12_BASE            (APB1PERIPH_BASE + 0x1800UL)
#define TIM13_BASE            (APB1PERIPH_BASE + 0x1C00UL)
#define TIM14_BASE            (APB1PERIPH_BASE + 0x2000UL)

/*!< APB2 peripherals */
#define TIM1_BASE             (APB2PERIPH_BASE + 0x0000UL)
#define TIM8_BASE             (APB2PERIPH_BASE + 0x0400UL)
#define TIM9_BASE             (APB2PERIPH_BASE + 0x4000UL)
#define TIM10_BASE            (APB2PERIPH_BASE + 0x4400UL)
#define TIM11_BASE            (APB2PERIPH_BASE + 0x4800UL)

...

#define TIM2                ((TIM_TypeDef *) TIM2_BASE)
#define TIM3                ((TIM_TypeDef *) TIM3_BASE)
#define TIM4                ((TIM_TypeDef *) TIM4_BASE)
#define TIM5                ((TIM_TypeDef *) TIM5_BASE)
#define TIM6                ((TIM_TypeDef *) TIM6_BASE)
#define TIM7                ((TIM_TypeDef *) TIM7_BASE)
#define TIM12               ((TIM_TypeDef *) TIM12_BASE)
#define TIM13               ((TIM_TypeDef *) TIM13_BASE)
#define TIM14               ((TIM_TypeDef *) TIM14_BASE)
...
#define TIM1                ((TIM_TypeDef *) TIM1_BASE)
#define TIM8                ((TIM_TypeDef *) TIM8_BASE)
...
#define TIM9                ((TIM_TypeDef *) TIM9_BASE)
#define TIM10               ((TIM_TypeDef *) TIM10_BASE)
#define TIM11               ((TIM_TypeDef *) TIM11_BASE)

5. For Arduino megaAVR

5.1. Documents

  1. Arduino 101: Timers and Interrupts
  2. megaAVR0-series-Family-Data-Sheet

5.2 Timer TCB0-TCB3

TCB0-TCB3 are 16-bit timers.



New from v1.1.0

Now with these new 16 ISR-based timers (while consuming only 1 hardware timer), the maximum interval is practically unlimited (limited only by unsigned long milliseconds). 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_16_Timers_Array_Complex and ISR_16_Timers_Array_Complex examples 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



Usage for ESP32

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

Timer0, Timer1, Timer2 and Timer3 are supported for ESP32.


Usage for NRF52

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware Timer

// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4)
// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1

// Init NRF52 timer NRF_TIMER1
NRF52Timer ITimer(NRF_TIMER_1);

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

void TimerHandler()
{
  // Doing something here inside ISR
}

#define TIMER_INTERVAL_MS        1000      // 1s = 1000ms
void setup()
{
  ....

  // Interval in microsecs
  if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler0))
    Serial.println("Starting  ITimer OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer. Select another freq. or timer");
}  

2. Using 16 ISR_based Timers from 1 Hardware Timers

2.1 Init Hardware Timer and ISR-based Timer

/// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4)
// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1

// Init NRF52 timer NRF_TIMER2
NRF52Timer ITimer(NRF_TIMER_2);

// Init NRF52_ISR_Timer
// Each NRF52_ISR_Timer can service 16 different ISR-based timers
ISR_Timer NRF52_ISR_Timer;

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

void TimerHandler()
{
  NRF52_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 NRF52, 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(HW_TIMER_INTERVAL_MS * 1000, 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
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s);
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s);
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s);
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s);
}  

Usage for SAMD

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware 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);

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

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");
}  

2. Using 16 ISR_based Timers from 1 Hardware Timer

2.1 Init Hardware Timer and ISR-based 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;

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

void TimerHandler()
{
  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);
}  

Usage for SAM DUE

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware Timer

// Interval in microsecs
attachDueInterrupt(TIMER1_INTERVAL_MS * 1000, TimerHandler1, "ITimer1");

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

void TimerHandler()
{
  // Doing something here inside ISR
}

#define TIMER_INTERVAL_MS        1000      // 1s = 1000ms

uint16_t attachDueInterrupt(double microseconds, timerCallback callback, const char* TimerName)
{
  DueTimerInterrupt dueTimerInterrupt = DueTimer.getAvailable();

  dueTimerInterrupt.attachInterruptInterval(microseconds, callback);

  uint16_t timerNumber = dueTimerInterrupt.getTimerNumber();

  Serial.print(TimerName);
  Serial.print(" attached to Timer(");
  Serial.print(timerNumber);
  Serial.println(")");

  return timerNumber;
}

void setup()
{
  ....

  // Interval in microsecs
  attachDueInterrupt(TIMER_INTERVAL_MS * 1000, TimerHandler, "ITimer");
}  

2. Using 16 ISR_based Timers from 1 Hardware Timers

2.1 Init Hardware Timer and ISR-based Timer

// Interval in microsecs
attachDueInterrupt(TIMER1_INTERVAL_MS * 1000, TimerHandler1, "ITimer1");

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

// Init SAMDUE_ISR_Timer
// Each SAMDUE_ISR_Timer can service 16 different ISR-based timers
ISR_Timer SAMDUE_ISR_Timer;

void TimerHandler()
{
  SAMDUE_ISR_Timer.run();
}

#define HW_TIMER_INTERVAL_MS          1L

#define TIMER_INTERVAL_2S             2000L
#define TIMER_INTERVAL_5S             5000L
#define TIMER_INTERVAL_11S            11000L
#define TIMER_INTERVAL_101S           101000L

// In SAM DUE, 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
}

uint16_t attachDueInterrupt(double microseconds, timerCallback callback, const char* TimerName)
{
  DueTimerInterrupt dueTimerInterrupt = DueTimer.getAvailable();

  dueTimerInterrupt.attachInterruptInterval(microseconds, callback);

  uint16_t timerNumber = dueTimerInterrupt.getTimerNumber();

  Serial.print(TimerName);
  Serial.print(" attached to Timer(");
  Serial.print(timerNumber);
  Serial.println(")");

  return timerNumber;
}

void setup()
{
  ....

  // Interval in microsecs
  attachDueInterrupt(HW_TIMER_INTERVAL_MS * 1000, TimerHandler, "ITimer");

  // 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
  SAMDUE_ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s);
  SAMDUE_ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s);
  SAMDUE_ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s);
  SAMDUE_ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s);
}  

Usage for Teensy

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware Timer

// You can select Teensy Hardware Timer  from TEENSY_TIMER_1 or TEENSY_TIMER_3

// Init Teensy timer TEENSY_TIMER_1
TeensyTimer ITimer0(TEENSY_TIMER_1);

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

void TimerHandler0()
{
  // Doing something here inside ISR
}

// For Teensy 4.0/4.1, F_BUS_ACTUAL = 150 MHz => max period is only 55922 us (~17.9 Hz)
#define TIMER0_INTERVAL_MS        50L

void setup()
{
  ....

  // Interval in microsecs
  if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
    Serial.println("Starting  ITimer0 OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer0. Select another freq. or timer");
}  

2. Using 16 ISR_based Timers from 1 Hardware Timers

2.1 Init Hardware Timer and ISR-based Timer

// You can select Teensy Hardware Timer  from TEENSY_TIMER_1 or TEENSY_TIMER_3

// Init Teensy timer TEENSY_TIMER_1
TeensyTimer ITimer(TEENSY_TIMER_1);

// Init Teensy_ISR_Timer
// Each Teensy_ISR_Timer can service 16 different ISR-based timers
ISR_Timer Teensy_ISR_Timer;

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

void TimerHandler()
{
  Teensy_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 Teensy, 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 every 2 seconds
}

void doingSomething5s()
{
  // Doing something here inside ISR every 5 seconds
}

void doingSomething11s()
{
  // Doing something here inside ISR  every 11 seconds
}

void doingSomething101s()
{
  // Doing something here inside ISR every 101 seconds
}

void setup()
{
  ....

  // Interval in microsecs
  if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, 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
  Teensy_ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s);
  Teensy_ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s);
  Teensy_ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s);
  Teensy_ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s);
}  

Usage for STM32F/L/H/G/WB/MP1

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware Timer

// Init STM32 timer TIM1
STM32Timer ITimer0(TIM1);

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

void TimerHandler0()
{
  // Doing something here inside ISR
}

#define TIMER0_INTERVAL_MS        1000      // 1s = 1000ms
void setup()
{
  ....

  // Interval in microsecs
  if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
    Serial.println("Starting  ITimer0 OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer0. Select another freq. or timer");
}  

2. Using 16 ISR_based Timers from 1 Hardware Timers

2.1 Init Hardware Timer and ISR-based Timer

// Init STM32 timer TIM1
STM32Timer ITimer(TIM1);

// Init STM32_ISR_Timer
// Each STM32_ISR_Timer can service 16 different ISR-based timers
ISR_Timer STM32_ISR_Timer;

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

void TimerHandler()
{
  STM32_ISR_Timer.run();
}

#define HW_TIMER_INTERVAL_US          100L

#define TIMER_INTERVAL_2S             2000L
#define TIMER_INTERVAL_5S             5000L
#define TIMER_INTERVAL_11S            11000L
#define TIMER_INTERVAL_101S           101000L

// In STM32, 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(HW_TIMER_INTERVAL_US, 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
  STM32_ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s);
  STM32_ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s);
  STM32_ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s);
  STM32_ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s);
}  

Usage for NRF52840-based board using mbed-RTOS such as Nano-33-BLE.

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware Timer

// For core mbed core 1.3.2-
// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1,NRF_TIMER_3,NRF_TIMER_4 (1,3 and 4)
// If you select the already-used NRF_TIMER_0 or NRF_TIMER_2, it'll be auto modified to use NRF_TIMER_1

// For core mbed core 2.0.0-
// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_3,NRF_TIMER_4 (3 and 4)
// If you select the already-used NRF_TIMER_0, NRF_TIMER_1 or NRF_TIMER_2, it'll be auto modified to use NRF_TIMER_3

// Init NRF52 timer NRF_TIMER4
NRF52_MBED_Timer ITimer0(NRF_TIMER_4);

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

void TimerHandler()
{
  // Doing something here inside ISR
}

#define TIMER_INTERVAL_MS        1000      // 1s = 1000ms
void setup()
{
  ....

  // Interval in microsecs
  if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler0))
    Serial.println("Starting  ITimer OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer. Select another freq. or timer");
}  

2. Using 16 ISR_based Timers from 1 Hardware Timers

2.1 Init Hardware Timer and ISR-based Timer

/// Depending on the board, you can select NRF52 Hardware Timer from NRF_TIMER_1-NRF_TIMER_4 (1 to 4)
// If you select the already-used NRF_TIMER_0, it'll be auto modified to use NRF_TIMER_1

// Init NRF52 timer NRF_TIMER2
NRF52_MBED_Timer ITimer(NRF_TIMER_2);

// Init NRF52_ISR_Timer
// Each NRF52_ISR_Timer can service 16 different ISR-based timers
ISR_Timer NRF52_ISR_Timer;

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

void TimerHandler()
{
  NRF52_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 NRF52, 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(HW_TIMER_INTERVAL_MS * 1000, 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
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_2S, doingSomething2s);
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_5S, doingSomething5s);
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_11S, doingSomething11s);
  NRF52_ISR_Timer.setInterval(TIMER_INTERVAL_101S, doingSomething101s);
}  

Usage for Arduino AVR

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

Only Timer1 and Timer2 are supported for Nano, UNO, etc. boards possessing 3 timers.

Timer3, Timer4 and Timer5 are only available for Arduino Mega boards.


Usage for Arduino megaAVR

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

Timer0, Timer1, Timer2 and Timer3 (TCB0-TCB3) are supported for Nano Every, UNO WiFi Rev2, etc. boards.

Before using any Timer, you have to make sure the Timer has not been used by any other purpose.

1. Using only Hardware Timer directly

1.1 Init Hardware Timer

#define USE_TIMER_0     false
#define USE_TIMER_1     true       // <======== This will enable ITimer1
#define USE_TIMER_2     false
#define USE_TIMER_3     false

1.2 Set Hardware Timer Interval and attach Timer Interrupt Handler function

void TimerHandler1()
{
  // Doing something here inside ISR
}

#define TIMER_INTERVAL_MS        1000      // 1s = 1000ms
void setup()
{
  ....

  // ITimer1 is initialized here
  ITimer1.init();

  // Interval in millisecs
  if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS, TimerHandler1))
  {
    Serial.print(F("Starting  ITimer1 OK, millis() = ")); Serial.println(millis());
  }
  else
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

  ...
}  

2. Using 16 ISR_based Timers from 1 Hardware Timers

2.1 Init Hardware Timer and ISR-based Timer

// Init ISR_Timer ISR_Timer1 to permit using 16 ISR_based Timers from 1 Hardware Timers (ITimer1)
ISR_Timer ISR_Timer1;

2.2 Set Hardware Timer Interval and attach Timer Interrupt Handler functions

#define USE_TIMER_0     false
#define USE_TIMER_1     true       // <======== This will enable ITimer1
#define USE_TIMER_2     false
#define USE_TIMER_3     false

void TimerHandler1()
{
  ISR_Timer1.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

// 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()
{
  ....

  // ITimer1 is initialized here
  ITimer1.init();

  // Interval in millisecs
  if (ITimer1.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler1))
  {
    Serial.print(F("Starting  ITimer1 OK, millis() = ")); Serial.println(millis());
  }
  else
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

  // 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
  ISR_Timer1.setInterval(TIMER_INTERVAL_2S, doingSomething2s);
  ISR_Timer1.setInterval(TIMER_INTERVAL_5S, doingSomething5s);
  ISR_Timer1.setInterval(TIMER_INTERVAL_11S, doingSomething11s);
  ISR_Timer1.setInterval(TIMER_INTERVAL_101S, doingSomething101s);
}  


Examples:

1. ESP32

  1. Argument_None
  2. RPM_Measure
  3. SwitchDebounce
  4. TimerInterruptTest
  5. Change_Interval.
  6. ISR_16_Timers_Array
  7. ISR_16_Timers_Array_Complex.

2. ESP8266

  1. Argument_None
  2. ISR_RPM_Measure
  3. RPM_Measure
  4. SwitchDebounce
  5. TimerInterruptTest
  6. Change_Interval.
  7. ISR_16_Timers_Array New
  8. ISR_16_Timers_Array_Complex New

3. NRF52

  1. Argument_None
  2. ISR_16_Timers_Array
  3. ISR_RPM_Measure
  4. ISR_Timer_Complex_Ethernet
  5. ISR_Timer_Complex_WiFiNINA
  6. RPM_Measure
  7. SwitchDebounce
  8. TimerInterruptLEDDemo.
  9. TimerInterruptTest
    1. ISR_16_Timers_Array_Complex.
    2. Change_Interval.
    3. FakeAnalogWrite.

4. SAMD21/SAMD51

  1. Argument_None
  2. ISR_16_Timers_Array
  3. ISR_RPM_Measure
  4. ISR_Timer_Complex_Ethernet
  5. ISR_Timer_Complex_WiFiNINA
  6. RPM_Measure
  7. SwitchDebounce
  8. TimerInterruptTest
  9. TimerInterruptLEDDemo
    1. ISR_16_Timers_Array_Complex
    2. Change_Interval
    3. SAMD21_MultiTimers New

5. SAM DUE

  1. Argument_None
  2. ISR_16_Timers_Array
  3. ISR_RPM_Measure
  4. ISR_Timer_Complex_Ethernet
  5. RPM_Measure
  6. SwitchDebounce
  7. TimerInterruptTest
  8. TimerInterruptLEDDemo
  9. ISR_16_Timers_Array_Complex.
    1. Change_Interval.

6. STM32F/L/H/G/WB/MP1

  1. Argument_None
  2. ISR_16_Timers_Array
  3. ISR_RPM_Measure
  4. RPM_Measure
  5. SwitchDebounce
  6. TimerInterruptTest
  7. TimerInterruptLEDDemo
  8. ISR_16_Timers_Array_Complex.
  9. Change_Interval.

7. Teensy

  1. Argument_None
  2. ISR_16_Timers_Array
  3. ISR_RPM_Measure
  4. ISR_Timer_Complex
  5. RPM_Measure
  6. SwitchDebounce
  7. TimerInterruptTest
  8. TimerInterruptLEDDemo
  9. ISR_16_Timers_Array_Complex.
    1. Change_Interval.

8. Arduino AVR

  1. Argument_Complex
  2. Argument_None
  3. Argument_Simple
  4. Change_Interval
  5. FakeAnalogWrite
  6. ISR_16_Timers_Array_Complex
  7. ISR_RPM_Measure
  8. ISR_Timers_Array_Simple
  9. RPM_Measure
    1. SwitchDebounce
    2. TimerDuration
    3. TimerInterruptTest
    4. Change_Interval_HF. New.

9. Nano-33-BLE

  1. Argument_None
  2. ISR_16_Timers_Array
  3. ISR_16_Timers_Array_Complex
  4. SwitchDebounce
  5. TimerInterruptLEDDemo
  6. TimerInterruptTest
  7. FakeAnalogWrite.
  8. Change_Interval.

10. Arduino megaAVR

  1. Argument_Complex
  2. Argument_None
  3. Argument_Simple
  4. Change_Interval.
  5. FakeAnalogWrite.
  6. ISR_16_Timers_Array_Complex.
  7. ISR_RPM_Measure
  8. Change_Interval_HF
  9. ISR_Timers_Array_Simple.
    1. RPM_Measure
    2. SwitchDebounce
    3. TimerDuration
    4. TimerInterruptTest

11. RP2040

  1. Argument_Complex
  2. Argument_None
  3. Argument_Simple
  4. Change_Interval
  5. ISR_16_Timers_Array_Complex
  6. ISR_Timers_Array_Simple
  7. RPM_Measure
  8. SwitchDebounce
  9. TimerInterruptTest

12. MBED RP2040

  1. Argument_Complex
  2. Argument_None
  3. Argument_Simple
  4. Change_Interval
  5. ISR_16_Timers_Array_Complex
  6. ISR_Timers_Array_Simple
  7. SwitchDebounce
  8. TimerInterruptTest


Example ISR_16_Timers_Array_Complex for MBED RP2040 boards

https://github.com/khoih-prog/TimerInterrupt_Generic/blob/ee0a22f5ee6bdc5c7f283f345e08356aab543aa3/examples/MBED_RP2040/ISR_16_Timers_Array_Complex/ISR_16_Timers_Array_Complex.ino#L48-L397



Debug Terminal Output Samples

1. ISR_Timer_Complex_Ethernet on Arduino SAM DUE

The following is the sample terminal output when running example ISR_Timer_Complex_Ethernet on Arduino SAM DUE 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 10.917s !!!. Then in loop(), it's also activated every 3s.

Starting ISR_Timer_Complex_Ethernet on SAM DUE
SAMDUETimerInterrupt v1.3.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)
[5] Getting IP...
[7] MAC: FE-8A-F1-EA-DE-82
_pinCS = 0
W5100 init, using SS_PIN_DEFAULT = 10, new ss_pin = 10, W5100Class::ss_pin = 10
W5100::init: W5100, SSIZE =4096
2s: Delta ms = 2000
2s: Delta ms = 2000
[7728] IP:192.168.2.134
[7728] 
    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ v0.6.1 on Arduino Due

[7732] BlynkArduinoClient.connect: Connecting to account.duckdns.org:8080
[7849] Ready (ping: 6ms).
IP = 192.168.2.134
2s: Delta ms = 2000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 10917
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
2s: Delta ms = 2000
11s: Delta ms = 11000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
11s: Delta ms = 11000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
11s: Delta ms = 11000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
11s: Delta ms = 11000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000

2. ISR_Timer_Complex_Ethernet on Adafruit NRF52840_FEATHER EXPRESS

The following is the sample terminal output when running example ISR_Timer_Complex_Ethernet on *Adafruit NRF52840_FEATHER EXPRESS using W5500 Ethernet 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 4.867s !!!. Then in loop(), it's also activated every 3s.

Starting ISR_Timer_Complex_Ethernet on NRF52840_FEATHER
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
[1419] Getting IP...
[1419] MAC: FE-BE-97-DA-C3-EA
_pinCS = 0
W5100 init, using SS_PIN_DEFAULT = 10, new ss_pin = 10, W5100Class::ss_pin = 10
W5100::init: W5500, SSIZE =4096
[3104] IP:192.168.2.129
[3104] 
    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ v0.6.1 on ARDUINO_NRF52_ADAFRUIT

[3106] BlynkArduinoClient.connect: Connecting to account.duckdns.org:8080
[3218] Ready (ping: 8ms).
IP = 192.168.2.129
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 4867
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
2s: Delta ms = 2000
11s: Delta ms = 11000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
11s: Delta ms = 11000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
2s: Delta ms = 2000
5s: Delta ms = 5000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
21s: Delta ms = 21000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
11s: Delta ms = 11000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
2s: Delta ms = 2000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000
2s: Delta ms = 2000
5s: Delta ms = 5000
11s: Delta ms = 11000
blynkDoingSomething2s: Delta programmed ms = 2000, actual = 3000

3. ISR_16_Timers_Array_Complex on Arduino SAMD21 SAMD_NANO_33_IOT

The following is the sample terminal output when running example ISR_16_Timers_Array_Complex 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 !!!

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_Complex on SAMD_NANO_33_IOT
SAMDTimerInterrupt v1.10.1
TimerInterrupt_Generic v1.13.0
CPU Frequency = 48 MHz
Starting ITimer OK, millis() = 1180
SimpleTimer : 2, ms : 11180, Dms : 10000
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 21184, Dms : 10004
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 31187, Dms : 10003
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 41190, Dms : 10003
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 51194, Dms : 10004
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 61197, Dms : 10003
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 71200, Dms : 10003
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 65000
Timer : 13, programmed : 70000, actual : 70000
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 81203, Dms : 10003
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 65000
Timer : 13, programmed : 70000, actual : 70000
Timer : 14, programmed : 75000, actual : 75000
Timer : 15, programmed : 80000, actual : 80000
SimpleTimer : 2, ms : 91206, Dms : 10003

4. TimerInterruptTest on Teensy 4.1

The following is the sample terminal output when running example TimerInterruptTest on Teensy 4.1 to demonstrate how to start/stop and the accuracy of Hardware Timers.

Starting TimerInterruptTest on Teensy 4.0
Teensy_TimerInterrupt v1.3.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
Starting  ITimer0 OK, millis() = 1128
Stop ITimer0, millis() = 5001
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
Start ITimer0, millis() = 10002
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1
Stop ITimer0, millis() = 15003
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
Start ITimer0, millis() = 20004
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1
Stop ITimer0, millis() = 25005
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
Start ITimer0, millis() = 30006
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1
Stop ITimer0, millis() = 35007
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
Start ITimer0, millis() = 40008
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1
Stop ITimer0, millis() = 45009
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
Start ITimer0, millis() = 50010
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1
TeensyTimerInterrupt:resumeTimer TEENSY_TIMER_1
Stop ITimer0, millis() = 55011
TeensyTimerInterrupt:stopTimer TEENSY_TIMER_1

5. ISR_16_Timers_Array_Complex on ESP32_DEV

The following is the sample terminal output when running example ISR_16_Timers_Array_Complex on ESP32_DEV to demonstrate the accuracy of ISR Hardware Timer.

Starting ISR_16_Timers_Array_Complex on ESP32_DEV
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
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 0
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 22097, Dms : 10053
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 32160, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 42223, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 52286, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 62349, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 72412, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 65000
Timer : 13, programmed : 70000, actual : 70000
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 82475, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 65000
Timer : 13, programmed : 70000, actual : 70000
Timer : 14, programmed : 75000, actual : 75000
Timer : 15, programmed : 80000, actual : 80000
SimpleTimer : 2, ms : 92538, Dms : 10063

6. ISR_16_Timers_Array_Complex on ESP8266_NODEMCU_ESP12E

The following is the sample terminal output when running example ISR_16_Timers_Array_Complex on ESP8266_NODEMCU_ESP12E to demonstrate 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 !!!

Starting ISR_16_Timers_Array_Complex on ESP8266_NODEMCU_ESP12E
ESP8266TimerInterrupt v1.6.0
TimerInterrupt_Generic v1.13.0
CPU Frequency = 160 MHz
Starting ITimer OK, millis() = 177
SimpleTimer : 2, ms : 10179, Dms : 10000
Timer : 0, programmed : 5000, actual : 5008
Timer : 1, programmed : 10000, actual : 0
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 20232, Dms : 10053
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15008
Timer : 3, programmed : 20000, actual : 20008
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 30286, Dms : 10054
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20008
Timer : 4, programmed : 25000, actual : 25008
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 40341, Dms : 10055
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25008
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35008
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 50396, Dms : 10055
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35008
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45008
Timer : 9, programmed : 50000, actual : 50008
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 60452, Dms : 10056
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35008
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45008
Timer : 9, programmed : 50000, actual : 50008
Timer : 10, programmed : 55000, actual : 55008
Timer : 11, programmed : 60000, actual : 60008
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 70509, Dms : 10057
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45008
Timer : 9, programmed : 50000, actual : 50008
Timer : 10, programmed : 55000, actual : 55008
Timer : 11, programmed : 60000, actual : 60008
Timer : 12, programmed : 65000, actual : 65008
Timer : 13, programmed : 70000, actual : 70008
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 80566, Dms : 10057
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45008
Timer : 9, programmed : 50000, actual : 50008
Timer : 10, programmed : 55000, actual : 55008
Timer : 11, programmed : 60000, actual : 60008
Timer : 12, programmed : 65000, actual : 65008
Timer : 13, programmed : 70000, actual : 70008
Timer : 14, programmed : 75000, actual : 75008
Timer : 15, programmed : 80000, actual : 80008

7. ISR_16_Timers_Array_Complex on STM32F7 Nucleo-144 F767ZI

The following is the sample terminal output when running example ISR_16_Timers_Array_Complex on STM32F7 Nucleo-144 F767ZI to demonstrate 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 !!!

Starting ISR_16_Timers_Array_Complex on NUCLEO_F767ZI
STM32_TimerInterrupt v1.3.0
TimerInterrupt_Generic v1.13.0
CPU Frequency = 216 MHz
Starting ITimer OK, millis() = 105
SimpleTimer : 2, ms : 10110, Dms : 10005
Timer : 0, programmed : 5000, actual : 5010
Timer : 1, programmed : 10000, actual : 10010
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 20169, Dms : 10059
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15010
Timer : 3, programmed : 20000, actual : 20010
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 30230, Dms : 10061
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20010
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30010
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 40293, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30010
Timer : 6, programmed : 35000, actual : 35010
Timer : 7, programmed : 40000, actual : 40010
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 50357, Dms : 10064
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30010
Timer : 6, programmed : 35000, actual : 35010
Timer : 7, programmed : 40000, actual : 40010
Timer : 8, programmed : 45000, actual : 45010
Timer : 9, programmed : 50000, actual : 50010
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 60421, Dms : 10064
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35010
Timer : 7, programmed : 40000, actual : 40010
Timer : 8, programmed : 45000, actual : 45010
Timer : 9, programmed : 50000, actual : 50010
Timer : 10, programmed : 55000, actual : 55010
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 70484, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40010
Timer : 8, programmed : 45000, actual : 45010
Timer : 9, programmed : 50000, actual : 50010
Timer : 10, programmed : 55000, actual : 55010
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65010
Timer : 13, programmed : 70000, actual : 70010
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 80552, Dms : 10068
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45010
Timer : 9, programmed : 50000, actual : 50010
Timer : 10, programmed : 55000, actual : 55010
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65010
Timer : 13, programmed : 70000, actual : 70010
Timer : 14, programmed : 75000, actual : 75010
Timer : 15, programmed : 80000, actual : 80010
SimpleTimer : 2, ms : 90618, Dms : 10066

8. TimerInterruptTest on STM32F7 Nucleo-144 F767ZI

The following is the sample terminal output when running example TimerInterruptTest on STM32F7 Nucleo-144 F767ZI to demonstrate how to start/stop Hardware Timers.

Starting TimerInterruptTest on NUCLEO_F767ZI
STM32_TimerInterrupt v1.3.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
STM32TimerInterrupt: Timer Input Freq (Hz) = 108000000, _fre = 1000000.00, _count = 3000000
Starting  ITimer1 OK, millis() = 119
Stop ITimer0, millis() = 5001
Start ITimer0, millis() = 10002
Stop ITimer1, millis() = 15001
Stop ITimer0, millis() = 15003
Start ITimer0, millis() = 20004
Stop ITimer0, millis() = 25005
Start ITimer1, millis() = 30002
Start ITimer0, millis() = 30006
Stop ITimer0, millis() = 35007
Start ITimer0, millis() = 40008
Stop ITimer1, millis() = 45003
Stop ITimer0, millis() = 45009
Start ITimer0, millis() = 50010
Stop ITimer0, millis() = 55011
Start ITimer1, millis() = 60004
Start ITimer0, millis() = 60012
Stop ITimer0, millis() = 65013
Start ITimer0, millis() = 70014
Stop ITimer1, millis() = 75005
Stop ITimer0, millis() = 75015
Start ITimer0, millis() = 80016
Stop ITimer0, millis() = 85017
Start ITimer1, millis() = 90006
Start ITimer0, millis() = 90018
Stop ITimer0, millis() = 95019
Start ITimer0, millis() = 100020
Stop ITimer1, millis() = 105007
Stop ITimer0, millis() = 105021
Start ITimer0, millis() = 110022
Stop ITimer0, millis() = 115023
Start ITimer1, millis() = 120008
Start ITimer0, millis() = 120024
Stop ITimer0, millis() = 125025
Start ITimer0, millis() = 130026
Stop ITimer1, millis() = 135009
Stop ITimer0, millis() = 135027
Start ITimer0, millis() = 140028

9. ISR_16_Timers_Array_Complex on Nano 33 BLE

The following is the sample terminal output when running example ISR_16_Timers_Array_Complex on Nano 33 BLE 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 more than 3.000s in loop().

Starting ISR_16_Timers_Array_Complex on Nano 33 BLE
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
Timer : 1, programmed : 10000, actual : 0
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 6822, Dms : 3012
Timer : 0, programmed : 5000, actual : 5006
Timer : 1, programmed : 10000, actual : 0
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 9834, Dms : 3012
Timer : 0, programmed : 5000, actual : 5006
Timer : 1, programmed : 10000, actual : 0
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 12845, Dms : 3011
Timer : 0, programmed : 5000, actual : 4995
Timer : 1, programmed : 10000, actual : 10001
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 15857, Dms : 3012
Timer : 0, programmed : 5000, actual : 5006
Timer : 1, programmed : 10000, actual : 10001
Timer : 2, programmed : 15000, actual : 15007
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 18868, Dms : 3011
Timer : 0, programmed : 5000, actual : 5006
Timer : 1, programmed : 10000, actual : 10001
Timer : 2, programmed : 15000, actual : 15007
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 21880, Dms : 3012
Timer : 0, programmed : 5000, actual : 4997
Timer : 1, programmed : 10000, actual : 10003
Timer : 2, programmed : 15000, actual : 15007
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 24892, Dms : 3012
Timer : 0, programmed : 5000, actual : 4997
Timer : 1, programmed : 10000, actual : 10003
Timer : 2, programmed : 15000, actual : 15007
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 27903, Dms : 3011
Timer : 0, programmed : 5000, actual : 5006
Timer : 1, programmed : 10000, actual : 10003
Timer : 2, programmed : 15000, actual : 15007
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 30914, Dms : 3011
Timer : 0, programmed : 5000, actual : 4992
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 14995
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 33926, Dms : 3012
Timer : 0, programmed : 5000, actual : 4992
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 14995
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 36938, Dms : 3012
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 14995
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 39950, Dms : 3012
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 14995
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 42961, Dms : 3011
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 14995
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 45972, Dms : 3011
Timer : 0, programmed : 5000, actual : 4993
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 14999
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 48983, Dms : 3011
Timer : 0, programmed : 5000, actual : 4993
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 14999
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 25010
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 51994, Dms : 3011
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 9996
Timer : 2, programmed : 15000, actual : 14999
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 55006, Dms : 3012
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 9996
Timer : 2, programmed : 15000, actual : 14999
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 58017, Dms : 3011
Timer : 0, programmed : 5000, actual : 5002
Timer : 1, programmed : 10000, actual : 9996
Timer : 2, programmed : 15000, actual : 14999
Timer : 3, programmed : 20000, actual : 20004
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30002
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 61029, Dms : 3012
Timer : 0, programmed : 5000, actual : 5004
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 15009
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 64040, Dms : 3011
Timer : 0, programmed : 5000, actual : 5004
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 15009
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 67051, Dms : 3011
Timer : 0, programmed : 5000, actual : 4995
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 15009
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65005
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 70062, Dms : 3011
Timer : 0, programmed : 5000, actual : 4995
Timer : 1, programmed : 10000, actual : 10006
Timer : 2, programmed : 15000, actual : 15009
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35005
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65005
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 73073, Dms : 3011
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 15009
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24994
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35003
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65005
Timer : 13, programmed : 70000, actual : 70008
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 76085, Dms : 3012
Timer : 0, programmed : 5000, actual : 4994
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 14992
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24998
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35003
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65005
Timer : 13, programmed : 70000, actual : 70008
Timer : 14, programmed : 75000, actual : 75002
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 79096, Dms : 3011
Timer : 0, programmed : 5000, actual : 4994
Timer : 1, programmed : 10000, actual : 9998
Timer : 2, programmed : 15000, actual : 14992
Timer : 3, programmed : 20000, actual : 20002
Timer : 4, programmed : 25000, actual : 24998
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35003
Timer : 7, programmed : 40000, actual : 40008
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65005
Timer : 13, programmed : 70000, actual : 70008
Timer : 14, programmed : 75000, actual : 75002
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 82107, Dms : 3011
Timer : 0, programmed : 5000, actual : 5003
Timer : 1, programmed : 10000, actual : 9997
Timer : 2, programmed : 15000, actual : 14992
Timer : 3, programmed : 20000, actual : 19995
Timer : 4, programmed : 25000, actual : 24998
Timer : 5, programmed : 30000, actual : 30008
Timer : 6, programmed : 35000, actual : 35003
Timer : 7, programmed : 40000, actual : 39997
Timer : 8, programmed : 45000, actual : 45001
Timer : 9, programmed : 50000, actual : 50004
Timer : 10, programmed : 55000, actual : 55006
Timer : 11, programmed : 60000, actual : 60010
Timer : 12, programmed : 65000, actual : 65005
Timer : 13, programmed : 70000, actual : 70008
Timer : 14, programmed : 75000, actual : 75002
Timer : 15, programmed : 80000, actual : 80005
SimpleTimer : 2, ms : 85118, Dms : 3011

10. ISR_16_Timers_Array_Complex on Arduino megaAVR Nano Every to show accuracy difference.

10.1. TCB Clock Frequency 16MHz for highest accuracy

Starting ISR_16_Timers_Array_Complex on megaAVR Nano Every
megaAVR_TimerInterrupt v1.7.0
TimerInterrupt_Generic v1.13.0
CPU Frequency = 16 MHz
TCB Clock Frequency = 16MHz for highest accuracy
[TISR] TCB 1
[TISR] ==================
[TISR] Init, Timer = 1
[TISR] CTRLB   = 0
[TISR] CCMP    = 65535
[TISR] INTCTRL = 0
[TISR] CTRLA   = 1
[TISR] ==================
[TISR] Frequency = 200.00 , CLK_TCB_FREQ = 16000000
[TISR] setFrequency: _CCMPValueRemaining =  80000
Starting  ITimer1 OK, millis() = 15
SimpleTimer : 2, ms : 10016, Dms : 10016
Timer : 0, programmed : 5000, actual : 5018
Timer : 1, programmed : 10000, actual : 10018
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 20075, Dms : 10059
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10001
Timer : 2, programmed : 15000, actual : 15019
Timer : 3, programmed : 20000, actual : 20019
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 30135, Dms : 10060
Timer : 0, programmed : 5000, actual : 5000   <========== Very accurate @ clock 16MHz
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20019
Timer : 4, programmed : 25000, actual : 25019
Timer : 5, programmed : 30000, actual : 30019
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 40195, Dms : 10060
...
Timer : 0, programmed : 5000, actual : 4996
Timer : 1, programmed : 10000, actual : 9996
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20001
Timer : 4, programmed : 25000, actual : 25001
Timer : 5, programmed : 30000, actual : 30001
Timer : 6, programmed : 35000, actual : 34997
Timer : 7, programmed : 40000, actual : 40019
Timer : 8, programmed : 45000, actual : 45020
Timer : 9, programmed : 50000, actual : 50020
Timer : 10, programmed : 55000, actual : 55020
Timer : 11, programmed : 60000, actual : 60020
Timer : 12, programmed : 65000, actual : 65020
Timer : 13, programmed : 70000, actual : 70016
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 80442, Dms : 10063
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 14996
Timer : 3, programmed : 20000, actual : 19996
Timer : 4, programmed : 25000, actual : 24996
Timer : 5, programmed : 30000, actual : 30001
Timer : 6, programmed : 35000, actual : 34997
Timer : 7, programmed : 40000, actual : 39997
Timer : 8, programmed : 45000, actual : 45020
Timer : 9, programmed : 50000, actual : 50020
Timer : 10, programmed : 55000, actual : 55020
Timer : 11, programmed : 60000, actual : 60020
Timer : 12, programmed : 65000, actual : 65020
Timer : 13, programmed : 70000, actual : 70016
Timer : 14, programmed : 75000, actual : 75016
Timer : 15, programmed : 80000, actual : 80016
SimpleTimer : 2, ms : 90506, Dms : 10064

10.2. TCB Clock Frequency 8MHz for very high accuracy


Starting ISR_16_Timers_Array_Complex on megaAVR Nano Every
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
SimpleTimer : 2, ms : 10011, Dms : 10011
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10011
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0

...

SimpleTimer : 2, ms : 160949, Dms : 10064
Timer : 0, programmed : 5000, actual : 5000            <========== Very accurate @ clock 8MHz
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 65000
Timer : 13, programmed : 70000, actual : 70000
Timer : 14, programmed : 75000, actual : 75000
Timer : 15, programmed : 80000, actual : 80000
SimpleTimer : 2, ms : 171013, Dms : 10064
Timer : 0, programmed : 5000, actual : 5000
Timer : 1, programmed : 10000, actual : 10000
Timer : 2, programmed : 15000, actual : 15000
Timer : 3, programmed : 20000, actual : 20000
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30000
Timer : 6, programmed : 35000, actual : 35000
Timer : 7, programmed : 40000, actual : 40000
Timer : 8, programmed : 45000, actual : 45000
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55000
Timer : 11, programmed : 60000, actual : 60000
Timer : 12, programmed : 65000, actual : 65000
Timer : 13, programmed : 70000, actual : 70000
Timer : 14, programmed : 75000, actual : 75000
Timer : 15, programmed : 80000, actual : 80000

10.3. TCB Clock Frequency 250KHz for lower accuracy but longer time

Starting ISR_16_Timers_Array_Complex on megaAVR Nano Every
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
SimpleTimer : 2, ms : 10012, Dms : 10012
Timer : 0, programmed : 5000, actual : 5021
Timer : 1, programmed : 10000, actual : 10015
Timer : 2, programmed : 15000, actual : 0
Timer : 3, programmed : 20000, actual : 0
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0
SimpleTimer : 2, ms : 20071, Dms : 10059
Timer : 0, programmed : 5000, actual : 4994
Timer : 1, programmed : 10000, actual : 9999
Timer : 2, programmed : 15000, actual : 15020
Timer : 3, programmed : 20000, actual : 20014
Timer : 4, programmed : 25000, actual : 0
Timer : 5, programmed : 30000, actual : 0
Timer : 6, programmed : 35000, actual : 0
Timer : 7, programmed : 40000, actual : 0
Timer : 8, programmed : 45000, actual : 0
Timer : 9, programmed : 50000, actual : 0
Timer : 10, programmed : 55000, actual : 0
Timer : 11, programmed : 60000, actual : 0
Timer : 12, programmed : 65000, actual : 0
Timer : 13, programmed : 70000, actual : 0
Timer : 14, programmed : 75000, actual : 0
Timer : 15, programmed : 80000, actual : 0

...

SimpleTimer : 2, ms : 845278, Dms : 10063
Timer : 0, programmed : 5000, actual : 4994            <========== Less accurate @ clock 250KHz
Timer : 1, programmed : 10000, actual : 9997
Timer : 2, programmed : 15000, actual : 15001
Timer : 3, programmed : 20000, actual : 20005
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30004
Timer : 6, programmed : 35000, actual : 34998
Timer : 7, programmed : 40000, actual : 40001
Timer : 8, programmed : 45000, actual : 44995
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55004
Timer : 11, programmed : 60000, actual : 59998
Timer : 12, programmed : 65000, actual : 64992
Timer : 13, programmed : 70000, actual : 70005
Timer : 14, programmed : 75000, actual : 75000
Timer : 15, programmed : 80000, actual : 80004
SimpleTimer : 2, ms : 855342, Dms : 10064
Timer : 0, programmed : 5000, actual : 5004
Timer : 1, programmed : 10000, actual : 9999
Timer : 2, programmed : 15000, actual : 15003
Timer : 3, programmed : 20000, actual : 20005
Timer : 4, programmed : 25000, actual : 25000
Timer : 5, programmed : 30000, actual : 30004
Timer : 6, programmed : 35000, actual : 34998
Timer : 7, programmed : 40000, actual : 40001
Timer : 8, programmed : 45000, actual : 45007
Timer : 9, programmed : 50000, actual : 50000
Timer : 10, programmed : 55000, actual : 55004
Timer : 11, programmed : 60000, actual : 59998
Timer : 12, programmed : 65000, actual : 64992
Timer : 13, programmed : 70000, actual : 70005
Timer : 14, programmed : 75000, actual : 75000
Timer : 15, programmed : 80000, actual : 80004


Debug

Debug is enabled by default on Serial.

You can also change the debugging level (_TIMERINTERRUPTLOGLEVEL) from 0 to 4

// These define's must be placed at the beginning before #include "TimerInterrupt_Generic.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_     0

Troubleshooting

If 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.



Issues

Submit issues to: TimerInterrupt_Generic issues


TO DO

  1. Search for bug and improvement.

DONE

  1. Basic hardware timers for


Contributions and Thanks

Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library.

  1. Use some code from the Ivan Seidel's DueTimer Library.
  2. Use some code from the Tamasa's ZeroTimer Library.
  3. Use some code from the Dennis van Gils' SAMD51_InterruptTimer Library.
  4. Thanks to good work of Miguel Wisintainer for working with, developing, debugging and testing.
  5. Thanks to Holger Lembke to report ESP8266TimerInterrupt Issue 8: ESP8266Timer and PWM --> wdt reset, leading to the HOWTO Use PWM analogWrite() with ESP8266 running Timer1 Interrupt notes.
  6. Thanks to Jelmer to report and make PR in Moved the implementation header file to a separate .cpp file.
  7. Thanks to Django0 to provide the following PR Fixed warnings from cppcheck (platformio) and -Wall arduino-cli. PR#10
  8. 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 of SAMD_TimerInterrupt to fix the bug and add more features
ivanseidel
⭐️ Ivan Seidel

EHbtj
⭐️ Tamasa

Dennis-van-Gils
Dennis van Gils

tcpipchip
Miguel Wisintainer

holgerlembke
Holger Lembke

jjwbruijn
Jelmer

Django0
Django0

sriccardi-invn
sriccardi-invn


Contributing

If you want to contribute to this project:


License


Copyright

Copyright (C) 2020- Khoi Hoang