├── .codespellrc
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
├── stale.yml
└── workflows
│ ├── auto-github-actions.yml
│ ├── report-size-deltas.yml
│ └── spell-check.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── changelog.md
├── examples
├── Argument_None
│ └── Argument_None.ino
├── Change_Interval
│ └── Change_Interval.ino
├── ISR_16_Timers_Array
│ └── ISR_16_Timers_Array.ino
├── ISR_16_Timers_Array_Complex
│ └── ISR_16_Timers_Array_Complex.ino
├── RPM_Measure
│ └── RPM_Measure.ino
├── SwitchDebounce
│ └── SwitchDebounce.ino
└── TimerInterruptTest
│ └── TimerInterruptTest.ino
├── keywords.txt
├── library.json
├── library.properties
├── platformio
└── platformio.ini
├── src
├── ESP32_New_ISR_Timer-Impl.h
├── ESP32_New_ISR_Timer.h
├── ESP32_New_ISR_Timer.hpp
├── ESP32_New_TimerInterrupt.h
└── TimerInterrupt_Generic_Debug.h
└── utils
├── astyle_library.conf
└── restyle.sh
/.codespellrc:
--------------------------------------------------------------------------------
1 | # See: https://github.com/codespell-project/codespell#using-a-config-file
2 | [codespell]
3 | # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
4 | ignore-words-list = ,
5 | check-filenames =
6 | check-hidden =
7 | skip = ./.git,./src,./examples
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Describe the bug
11 |
12 | A clear and concise description of what the bug is.
13 |
14 | ### Steps to Reproduce
15 |
16 | Steps to reproduce the behavior. Including the [MRE](https://stackoverflow.com/help/minimal-reproducible-example) sketches
17 |
18 | ### Expected behavior
19 |
20 | A clear and concise description of what you expected to happen.
21 |
22 | ### Actual behavior
23 |
24 | A clear and concise description of what you expected to happen.
25 |
26 | ### Debug and AT-command log (if applicable)
27 |
28 | A clear and concise description of what you expected to happen.
29 |
30 | ### Screenshots
31 |
32 | If applicable, add screenshots to help explain your problem.
33 |
34 | ### Information
35 |
36 | Please ensure to specify the following:
37 |
38 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version
39 | * `ESP32` Core Version (e.g. ESP32 core v2.0.5)
40 | * `ESP32` Board type (e.g. ESP32_DEV Module, etc.)
41 | * `ESP32-S2` Board type (e.g. ESP32S2_DEV Module, ESP32_S2_Saola, etc.)
42 | * `ESP32_S3` Board type (e.g. ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.)
43 | * `ESP32-C3` Board type (e.g. ESP32C3_DEV Module, LOLIN_C3_MINI, DFROBOT_BEETLE_ESP32_C3, ADAFRUIT_QTPY_ESP32C3, AirM2M_CORE_ESP32C3, XIAO_ESP32C3, etc.)
44 | * Contextual information (e.g. what you were trying to achieve)
45 | * Simplest possible steps to reproduce
46 | * Anything that might be relevant in your opinion, such as:
47 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
48 | * Network configuration
49 |
50 |
51 | ### Example
52 |
53 | ```
54 | Arduino IDE version: 1.8.19
55 | ESP32 core v2.0.5
56 | ESP32S3_DEV Module
57 | OS: Ubuntu 20.04 LTS
58 | Linux xy-Inspiron-3593 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
59 |
60 | Context:
61 | I encountered a crash while using this library
62 | Steps to reproduce:
63 | 1. ...
64 | 2. ...
65 | 3. ...
66 | 4. ...
67 | ```
68 |
69 | ### Additional context
70 |
71 | Add any other context about the problem here.
72 |
73 | ---
74 |
75 | ### Sending Feature Requests
76 |
77 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
78 |
79 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
80 |
81 | ---
82 |
83 | ### Sending Pull Requests
84 |
85 | Pull Requests with changes and fixes are also welcome!
86 |
87 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux)
88 |
89 | 1. Change directory to the library GitHub
90 |
91 | ```
92 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESP32_New_TimerInterrupt_GitHub/
93 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_New_TimerInterrupt_GitHub$
94 | ```
95 |
96 | 2. Issue astyle command
97 |
98 | ```
99 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_New_TimerInterrupt_GitHub$ bash utils/restyle.sh
100 | ```
101 |
102 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Is your feature request related to a problem? Please describe.
11 |
12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
13 |
14 | ### Describe the solution you'd like
15 |
16 | A clear and concise description of what you want to happen.
17 |
18 | ### Describe alternatives you've considered
19 |
20 | A clear and concise description of any alternative solutions or features you've considered.
21 |
22 | ### Additional context
23 |
24 | Add any other context or screenshots about the feature request here.
25 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file
2 | version: 2
3 |
4 | updates:
5 | # Configure check for outdated GitHub Actions actions in workflows.
6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot
7 | - package-ecosystem: github-actions
8 | directory: / # Check the repository's workflows under /.github/workflows/
9 | schedule:
10 | interval: daily
11 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Configuration for probot-stale - https://github.com/probot/stale
2 |
3 | daysUntilStale: 60
4 | daysUntilClose: 14
5 | limitPerRun: 30
6 | staleLabel: stale
7 | exemptLabels:
8 | - pinned
9 | - security
10 | - "to be implemented"
11 | - "for reference"
12 | - "move to PR"
13 | - "enhancement"
14 |
15 | only: issues
16 | onlyLabels: []
17 | exemptProjects: false
18 | exemptMilestones: false
19 | exemptAssignees: false
20 |
21 | markComment: >
22 | [STALE_SET] This issue has been automatically marked as stale because it has not had
23 | recent activity. It will be closed in 14 days if no further activity occurs. Thank you
24 | for your contributions.
25 |
26 | unmarkComment: >
27 | [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it opening the future.
28 |
29 | closeComment: >
30 | [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.
31 |
32 |
--------------------------------------------------------------------------------
/.github/workflows/auto-github-actions.yml:
--------------------------------------------------------------------------------
1 | name: auto-github-actions
2 | on: [push]
3 | jobs:
4 | check-bats-version:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v3
8 | - uses: actions/setup-node@v3
9 | with:
10 | node-version: '14'
11 | - run: npm install -g bats
12 | - run: bats -v
13 |
--------------------------------------------------------------------------------
/.github/workflows/report-size-deltas.yml:
--------------------------------------------------------------------------------
1 | name: Report Size Deltas
2 |
3 | on:
4 | schedule:
5 | - cron: '*/5 * * * *'
6 |
7 | jobs:
8 | report:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Comment size deltas reports to PRs
13 | uses: arduino/report-size-deltas@v1
14 | with:
15 | # The name of the workflow artifact created by the "Compile Examples" workflow
16 | sketches-reports-source: sketches-reports
17 |
--------------------------------------------------------------------------------
/.github/workflows/spell-check.yml:
--------------------------------------------------------------------------------
1 | name: Spell Check
2 |
3 | on:
4 | pull_request:
5 | push:
6 | schedule:
7 | # run every Tuesday at 3 AM UTC
8 | - cron: "0 3 * * 2"
9 | workflow_dispatch:
10 | repository_dispatch:
11 |
12 | jobs:
13 | spellcheck:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v3
19 |
20 | # See: https://github.com/codespell-project/actions-codespell/blob/master/README.md
21 | - name: Spell check
22 | uses: codespell-project/actions-codespell@master
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to ESP32_New_TimerInterrupt
2 |
3 | ### Reporting Bugs
4 |
5 | Please report bugs in [ESP32_New_TimerInterrupt Issues](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues) if you find them.
6 |
7 | However, before reporting a bug please check through the following:
8 |
9 | * [Existing Open Issues](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues) - someone might have already encountered this.
10 |
11 | If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues/new).
12 |
13 | ### How to submit a bug report
14 |
15 | Please ensure to specify the following:
16 |
17 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version
18 | * `ESP32` Core Version (e.g. ESP32 core v2.0.5)
19 | * `ESP32` Board type (e.g. ESP32_DEV Module, etc.)
20 | * `ESP32-S2` Board type (e.g. ESP32S2_DEV Module, ESP32_S2_Saola, etc.)
21 | * `ESP32_S3` Board type (e.g. ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.)
22 | * `ESP32-C3` Board type (e.g. ESP32C3_DEV Module, LOLIN_C3_MINI, DFROBOT_BEETLE_ESP32_C3, ADAFRUIT_QTPY_ESP32C3, AirM2M_CORE_ESP32C3, XIAO_ESP32C3, etc.)
23 | * Contextual information (e.g. what you were trying to achieve)
24 | * Simplest possible steps to reproduce
25 | * Anything that might be relevant in your opinion, such as:
26 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
27 | * Network configuration
28 |
29 |
30 | ### Example
31 |
32 | ```
33 | Arduino IDE version: 1.8.19
34 | ESP32 core v2.0.5
35 | ESP32S3_DEV Module
36 | OS: Ubuntu 20.04 LTS
37 | Linux xy-Inspiron-3593 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
38 |
39 | Context:
40 | I encountered a crash while using this library
41 | Steps to reproduce:
42 | 1. ...
43 | 2. ...
44 | 3. ...
45 | 4. ...
46 | ```
47 |
48 | ### Additional context
49 |
50 | Add any other context about the problem here.
51 |
52 | ---
53 |
54 | ### Sending Feature Requests
55 |
56 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
57 |
58 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
59 |
60 | ---
61 |
62 | ### Sending Pull Requests
63 |
64 | Pull Requests with changes and fixes are also welcome!
65 |
66 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux)
67 |
68 | 1. Change directory to the library GitHub
69 |
70 | ```
71 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESP32_New_TimerInterrupt_GitHub/
72 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_New_TimerInterrupt_GitHub$
73 | ```
74 |
75 | 2. Issue astyle command
76 |
77 | ```
78 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_New_TimerInterrupt_GitHub$ bash utils/restyle.sh
79 | ```
80 |
81 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Khoi Hoang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ESP32_New_TimerInterrupt Library
2 |
3 | [](https://www.ardu-badge.com/ESP32_New_TimerInterrupt)
4 | [](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/releases)
5 | [](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/blob/main/LICENSE)
6 | [](#Contributing)
7 | [](http://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues)
8 |
9 |
10 |
11 |
12 |
13 | ---
14 | ---
15 |
16 | ## Table of Contents
17 |
18 | * [Why do we need this ESP32_New_TimerInterrupt library](#why-do-we-need-this-esp32_new_timerinterrupt-library)
19 | * [Important Notes](#Important-Notes)
20 | * [Features](#features)
21 | * [Why using ISR-based Hardware Timer Interrupt is better](#why-using-isr-based-hardware-timer-interrupt-is-better)
22 | * [Currently supported Boards](#currently-supported-boards)
23 | * [Important Notes about ISR](#important-notes-about-isr)
24 | * [Changelog](changelog.md)
25 | * [Prerequisites](#prerequisites)
26 | * [Installation](#installation)
27 | * [Use Arduino Library Manager](#use-arduino-library-manager)
28 | * [Manual Install](#manual-install)
29 | * [VS Code & PlatformIO](#vs-code--platformio)
30 | * [HOWTO Fix `Multiple Definitions` Linker Error](#howto-fix-multiple-definitions-linker-error)
31 | * [HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE)](#howto-use-analogread-with-esp32-running-wifi-andor-bluetooth-btble)
32 | * [1. ESP32 has 2 ADCs, named ADC1 and ADC2](#1--esp32-has-2-adcs-named-adc1-and-adc2)
33 | * [2. ESP32 ADCs functions](#2-esp32-adcs-functions)
34 | * [3. ESP32 WiFi uses ADC2 for WiFi functions](#3-esp32-wifi-uses-adc2-for-wifi-functions)
35 | * [More useful Information](#more-useful-information)
36 | * [How to use](#how-to-use)
37 | * [Examples](#examples)
38 | * [ 1. Argument_None](examples/Argument_None)
39 | * [ 2. Change_Interval](examples/Change_Interval).
40 | * [ 3. RPM_Measure](examples/RPM_Measure)
41 | * [ 4. SwitchDebounce](examples/SwitchDebounce)
42 | * [ 5. TimerInterruptTest](examples/TimerInterruptTest)
43 | * [ 6. ISR_16_Timers_Array](examples/ISR_16_Timers_Array)
44 | * [ 7. ISR_16_Timers_Array_Complex](examples/ISR_16_Timers_Array_Complex)
45 | * [Example ISR_16_Timers_Array_Complex](#example-isr_16_timers_array_complex)
46 | * [Debug Terminal Output Samples](#debug-terminal-output-samples)
47 | * [1. TimerInterruptTest on ESP32C3_DEV](#1-timerinterrupttest-on-esp32c3_dev)
48 | * [2. Change_Interval on ESP32_DEV](#2-change_interval-on-esp32_dev)
49 | * [3. Argument_None on ESP32S2_DEV](#3-argument_none-on-esp32s2_dev)
50 | * [4. ISR_16_Timers_Array_Complex on ESP32C3_DEV](#4-isr_16_timers_array_complex-on-esp32c3_dev)
51 | * [5. ISR_16_Timers_Array on ESP32S2_DEV](#5-isr_16_timers_array-on-esp32s2_dev)
52 | * [6. ISR_16_Timers_Array_Complex on ESP32S3_DEV](#6-isr_16_timers_array_complex-on-ESP32S3_DEV) **New**
53 | * [Debug](#debug)
54 | * [Troubleshooting](#troubleshooting)
55 | * [Issues](#issues)
56 | * [TO DO](#to-do)
57 | * [DONE](#done)
58 | * [Contributions and Thanks](#contributions-and-thanks)
59 | * [Contributing](#contributing)
60 | * [License](#license)
61 | * [Copyright](#copyright)
62 |
63 | ---
64 | ---
65 |
66 | ### Why do we need this [ESP32_New_TimerInterrupt library](https://github.com/khoih-prog/ESP32_New_TimerInterrupt)
67 |
68 | ### Important Notes
69 |
70 | 1. Avoid using `PIN_D1 (GPIO1)` in your code due to issue with core v2.0.0 and v2.0.1. Check [ESP32 Core v2.0.1 / 2.0.1 RC1 crashes if using pinMode with GPIO1 #5868](https://github.com/espressif/arduino-esp32/issues/5868). Only OK with core v1.0.6-
71 | 2. Don't use `float` in `ISR` due to issue with core v2.0.0 and v2.0.1. Check [ESP32 Core v2.0.1 / 2.0.1 RC1 crashes if using float in ISR #5892](https://github.com/espressif/arduino-esp32/issues/5892). Only OK with core v1.0.6-.
72 |
73 | ### Features
74 |
75 | This library enables you to use Interrupt from Hardware Timers on an ESP32, ESP32_S2/S3/C3-based board.
76 |
77 | ---
78 |
79 | 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**).
80 |
81 | Now with these new **16 ISR-based timers**, the maximum interval is **practically unlimited** (limited only by unsigned long milliseconds) while **the accuracy is nearly perfect** compared to software timers.
82 |
83 | 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.
84 |
85 | The [**ISR_Timer_Complex**](examples/ISR_Timer_Complex) example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs of each type of timers.
86 |
87 | 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.
88 |
89 | This non-being-blocked important feature is absolutely necessary for mission-critical tasks.
90 |
91 | You'll see blynkTimer Software is blocked while system is connecting to WiFi / Internet / Blynk, as well as by blocking task
92 | in loop(), using delay() function as an example. The elapsed time then is very unaccurate
93 |
94 | ### Why using ISR-based Hardware Timer Interrupt is better
95 |
96 | 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().
97 |
98 | So your function **might not be executed, and the result would be disastrous.**
99 |
100 | You'd prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.).
101 |
102 | The correct choice is to use a Hardware Timer with **Interrupt** to call your function.
103 |
104 | 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.
105 |
106 | 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.
107 |
108 | 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:
109 |
110 | [**HOWTO Attach Interrupt**](https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/)
111 |
112 | ---
113 |
114 | ### Currently supported Boards
115 |
116 | 1. ESP32 boards, such as `ESP32_DEV`, etc.
117 | 2. ESP32_S2-based boards, such as `ESP32S2_DEV`, `ESP32_S2 Saola`, Adafruit QTPY_ESP32S2, ESP32S2 Native USB, UM FeatherS2 Neo, UM TinyS2, UM RMP, microS2, etc.
118 | 3. ESP32_C3-based boards, such as `ESP32C3_DEV`, LOLIN_C3_MINI, DFROBOT_BEETLE_ESP32_C3, ADAFRUIT_QTPY_ESP32C3, AirM2M_CORE_ESP32C3, XIAO_ESP32C3, etc. **New**
119 | 4. ESP32_S3-based boards, such as ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, FEATHER_ESP32S3_NOPSRAM, QTPY_ESP32S3_NOPSRAM, etc. **New**
120 |
121 |
122 | ---
123 |
124 | ### Important Notes about ISR
125 |
126 | 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.**
127 |
128 | 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.
129 |
130 |
131 | ---
132 | ---
133 |
134 | ## Prerequisites
135 |
136 | 1. [`Arduino IDE 1.8.19+` for Arduino](https://github.com/arduino/Arduino). [](https://github.com/arduino/Arduino/releases/latest)
137 | 2. [`ESP32 Core 2.0.5+`](https://github.com/espressif/arduino-esp32) for ESP32-based boards (ESP32, ESP32_S2, ESP32_S3 and ESP32_C3). [](https://github.com/espressif/arduino-esp32/releases/latest/).
138 |
139 | ---
140 | ---
141 |
142 | ## Installation
143 |
144 | ### Use Arduino Library Manager
145 |
146 | The best and easiest way is to use `Arduino Library Manager`. Search for [**ESP32_New_TimerInterrupt**](https://github.com/khoih-prog/ESP32_New_TimerInterrupt), then select / install the latest version.
147 | You can also use this link [](https://www.ardu-badge.com/ESP32_New_TimerInterrupt) for more detailed instructions.
148 |
149 | ---
150 |
151 | ### Manual Install
152 |
153 | Another way to install is to:
154 |
155 | 1. Navigate to [**ESP32_New_TimerInterrupt**](https://github.com/khoih-prog/ESP32_New_TimerInterrupt) page.
156 | 2. Download the latest release `ESP32_New_TimerInterrupt-main.zip`.
157 | 3. Extract the zip file to `ESP32_New_TimerInterrupt-main` directory
158 | 4. Copy whole `ESP32_New_TimerInterrupt-main` folder to Arduino libraries' directory such as `~/Arduino/libraries/`.
159 |
160 | ---
161 |
162 | ### VS Code & PlatformIO
163 |
164 | 1. Install [VS Code](https://code.visualstudio.com/)
165 | 2. Install [PlatformIO](https://platformio.org/platformio-ide)
166 | 3. Install [**ESP32_New_TimerInterrupt** library](https://registry.platformio.org/libraries/khoih-prog/ESP32_New_TimerInterrupt) by using [Library Manager](https://registry.platformio.org/libraries/khoih-prog/ESP32_New_TimerInterrupt/installation). Search for **ESP32_New_TimerInterrupt** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22)
167 | 4. Use included [platformio.ini](platformio/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](https://docs.platformio.org/page/projectconf.html)
168 |
169 |
170 | ---
171 | ---
172 |
173 |
174 | ### HOWTO Fix `Multiple Definitions` Linker Error
175 |
176 | The current library implementation, using `xyz-Impl.h` instead of standard `xyz.cpp`, possibly creates certain `Multiple Definitions` Linker error in certain use cases.
177 |
178 | You can use
179 |
180 | ```cpp
181 | #include //https://github.com/khoih-prog/ESP32_New_TimerInterrupt
182 | ```
183 |
184 | in many files. But be sure to use the following `#include ` **in just 1 `.h`, `.cpp` or `.ino` file**, which must **not be included in any other file**, to avoid `Multiple Definitions` Linker Error
185 |
186 | ```cpp
187 | // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
188 | #include //https://github.com/khoih-prog/ESP32_New_TimerInterrupt
189 | ```
190 |
191 | ---
192 | ---
193 |
194 | ### HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE)
195 |
196 | Please have a look at [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to have more detailed description and solution of the issue.
197 |
198 | #### 1. ESP32 has 2 ADCs, named ADC1 and ADC2
199 |
200 | #### 2. ESP32 ADCs functions
201 |
202 | - `ADC1` controls ADC function for pins **GPIO32-GPIO39**
203 | - `ADC2` controls ADC function for pins **GPIO0, 2, 4, 12-15, 25-27**
204 |
205 | #### 3.. ESP32 WiFi uses ADC2 for WiFi functions
206 |
207 | Look in file [**adc_common.c**](https://github.com/espressif/esp-idf/blob/master/components/driver/adc_common.c)
208 |
209 | > In `ADC2`, there're two locks used for different cases:
210 | > 1. lock shared with app and Wi-Fi:
211 | > ESP32:
212 | > When Wi-Fi using the `ADC2`, we assume it will never stop, so app checks the lock and returns immediately if failed.
213 | > ESP32S2:
214 | > The controller's control over the ADC is determined by the arbiter. There is no need to control by lock.
215 | >
216 | > 2. lock shared between tasks:
217 | > when several tasks sharing the `ADC2`, we want to guarantee
218 | > all the requests will be handled.
219 | > Since conversions are short (about 31us), app returns the lock very soon,
220 | > we use a spinlock to stand there waiting to do conversions one by one.
221 | >
222 | > adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.
223 |
224 |
225 | - In order to use `ADC2` for other functions, we have to **acquire complicated firmware locks and very difficult to do**
226 | - So, it's not advisable to use `ADC2` with WiFi/BlueTooth (BT/BLE).
227 | - Use `ADC1`, and pins `GPIO32-GPIO39`
228 | - If somehow it's a must to use those pins serviced by `ADC2` (**GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27**), use the **fix mentioned at the end** of [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to work with ESP32 WiFi/BlueTooth (BT/BLE).
229 |
230 |
231 | ---
232 | ---
233 |
234 | ## More useful Information
235 |
236 | The ESP32 has two timer groups, each one with two general purpose hardware timers. All the timers are based on 64 bits counters and 16 bit prescalers.
237 |
238 | The timer counters can be configured to count up or down and support automatic reload and software reload.
239 |
240 | They can also generate alarms when they reach a specific value, defined by the software. The value of the counter can be read by
241 | the software program.
242 |
243 | ---
244 |
245 | 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.
246 | This important feature is absolutely necessary for mission-critical tasks.
247 |
248 | The `ISR_Timer_Complex` example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs of each type of timers.
249 | 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.
250 | This non-being-blocked important feature is absolutely necessary for mission-critical tasks.
251 | You'll see blynkTimer Software is blocked while system is connecting to WiFi / Internet / Blynk, as well as by blocking task
252 | in loop(), using delay() function as an example. The elapsed time then is very unaccurate
253 |
254 | ---
255 | ---
256 |
257 | ## How to use
258 |
259 | Before using any Timer, you have to make sure the Timer has not been used by any other purpose.
260 |
261 | `Timer0, Timer1, Timer2 and Timer3` are supported for ESP32-S2.
262 |
263 | ---
264 | ---
265 |
266 | ### Examples:
267 |
268 | 1. [Argument_None](examples/Argument_None)
269 | 2. [RPM_Measure](examples/RPM_Measure)
270 | 3. [SwitchDebounce](examples/SwitchDebounce)
271 | 4. [TimerInterruptTest](examples/TimerInterruptTest)
272 | 5. [**Change_Interval**](examples/Change_Interval).
273 | 6. [**ISR_16_Timers_Array**](examples/ISR_16_Timers_Array)
274 | 7. [**ISR_16_Timers_Array_Complex**](examples/ISR_16_Timers_Array_Complex).
275 |
276 | ---
277 | ---
278 |
279 | ### Example [ISR_16_Timers_Array_Complex](examples/ISR_16_Timers_Array_Complex)
280 |
281 | https://github.com/khoih-prog/ESP32_New_TimerInterrupt/blob/eb11f04967974c3b19e9c0f7b7ba078af49526c9/examples/ISR_16_Timers_Array_Complex/ISR_16_Timers_Array_Complex.ino#L43-L383
282 |
283 | ---
284 | ---
285 |
286 | ### Debug Terminal Output Samples
287 |
288 |
289 | ### 1. TimerInterruptTest on ESP32C3_DEV
290 |
291 | The following is the sample terminal output when running example [TimerInterruptTest](examples/TimerInterruptTest) to demonstrate how to start/stop Hardware Timers.
292 |
293 | ```
294 | Starting TimerInterruptTest on ESP32_DEV
295 | ESP32_New_TimerInterrupt v1.5.0
296 | CPU Frequency = 240 MHz
297 | [TISR] ESP32_TimerInterrupt: _timerNo = 0 , _fre = 1000000
298 | [TISR] TIMER_BASE_CLK = 80000000 , TIMER_DIVIDER = 80
299 | [TISR] _timerIndex = 0 , _timerGroup = 0
300 | [TISR] _count = 0 - 1000000
301 | [TISR] timer_set_alarm_value = 1000000.00
302 | Starting ITimer0 OK, millis() = 158
303 | [TISR] ESP32_TimerInterrupt: _timerNo = 1 , _fre = 1000000
304 | [TISR] TIMER_BASE_CLK = 80000000 , TIMER_DIVIDER = 80
305 | [TISR] _timerIndex = 1 , _timerGroup = 0
306 | [TISR] _count = 0 - 3000000
307 | [TISR] timer_set_alarm_value = 3000000.00
308 | Starting ITimer1 OK, millis() = 189
309 | Stop ITimer0, millis() = 5001
310 | Start ITimer0, millis() = 10002
311 | Stop ITimer1, millis() = 15001
312 | Stop ITimer0, millis() = 15003
313 | Start ITimer0, millis() = 20004
314 | Stop ITimer0, millis() = 25005
315 | Start ITimer1, millis() = 30002
316 | Start ITimer0, millis() = 30006
317 | ```
318 |
319 | ---
320 |
321 |
322 | ### 2. Change_Interval on ESP32_DEV
323 |
324 | The following is the sample terminal output when running example [Change_Interval](examples/Change_Interval) to demonstrate how to change Timer Interval on-the-fly
325 |
326 | ```
327 | Starting Change_Interval on ESP32_DEV
328 | ESP32_New_TimerInterrupt v1.5.0
329 | CPU Frequency = 240 MHz
330 | Starting ITimer0 OK, millis() = 136
331 | Starting ITimer1 OK, millis() = 147
332 | Time = 10001, Timer0Count = 5, Timer1Count = 2
333 | Time = 20002, Timer0Count = 10, Timer1Count = 4
334 | Changing Interval, Timer0 = 4000, Timer1 = 10000
335 | Time = 30003, Timer0Count = 12, Timer1Count = 5
336 | Time = 40004, Timer0Count = 15, Timer1Count = 6
337 | Changing Interval, Timer0 = 2000, Timer1 = 5000
338 | Time = 50005, Timer0Count = 20, Timer1Count = 8
339 | Time = 60006, Timer0Count = 25, Timer1Count = 10
340 | Changing Interval, Timer0 = 4000, Timer1 = 10000
341 | Time = 70007, Timer0Count = 27, Timer1Count = 11
342 | Time = 80008, Timer0Count = 30, Timer1Count = 12
343 | Changing Interval, Timer0 = 2000, Timer1 = 5000
344 | Time = 90009, Timer0Count = 35, Timer1Count = 14
345 | Time = 100010, Timer0Count = 40, Timer1Count = 16
346 | Changing Interval, Timer0 = 4000, Timer1 = 10000
347 | ```
348 |
349 | ---
350 |
351 | ### 3. Argument_None on ESP32S2_DEV
352 |
353 | The following is the sample terminal output when running example [Argument_None](examples/Argument_None)
354 |
355 | ```
356 | Starting Argument_None on ESP32S2_DEV
357 | ESP32_New_TimerInterrupt v1.5.0
358 | CPU Frequency = 240 MHz
359 | [TISR] ESP32_S2_TimerInterrupt: _timerNo = 0 , _fre = 1000000
360 | [TISR] TIMER_BASE_CLK = 80000000 , TIMER_DIVIDER = 80
361 | [TISR] _timerIndex = 0 , _timerGroup = 0
362 | [TISR] _count = 0 - 1000000
363 | [TISR] timer_set_alarm_value = 1000000.00
364 | ITimer0: millis() = 656
365 | Starting ITimer0 OK, millis() = 660
366 | [TISR] ESP32_S2_TimerInterrupt: _timerNo = 1 , _fre = 1000000
367 | [TISR] TIMER_BASE_CLK = 80000000 , TIMER_DIVIDER = 80
368 | [TISR] _timerIndex = 1 , _timerGroup = 0
369 | [TISR] _count = 0 - 5000000
370 | [TISR] timer_set_alarm_value = 5000000.00
371 | ITimer1: millis() = 682
372 | Starting ITimer1 OK, millis() = 685
373 | ITimer0: millis() = 1651
374 | ITimer0: millis() = 2651
375 | ITimer0: millis() = 3651
376 | ITimer0: millis() = 4651
377 | ITimer0: millis() = 5651
378 | ITimer1: millis() = 5676
379 | ITimer0: millis() = 6651
380 | ITimer0: millis() = 7651
381 | ITimer0: millis() = 8651
382 | ITimer0: millis() = 9651
383 | ITimer0: millis() = 10651
384 | ITimer1: millis() = 10676
385 | ITimer0: millis() = 11651
386 | ITimer0: millis() = 12651
387 | ITimer0: millis() = 13651
388 | ITimer0: millis() = 14651
389 | ITimer0: millis() = 15651
390 | ITimer1: millis() = 15676
391 | ITimer0: millis() = 16651
392 | ITimer0: millis() = 17651
393 | ITimer0: millis() = 18651
394 | ITimer0: millis() = 19651
395 | ITimer0: millis() = 20651
396 | ITimer1: millis() = 20676
397 | ITimer0: millis() = 21651
398 | ITimer0: millis() = 22651
399 | ```
400 |
401 | ---
402 |
403 | ### 4. ISR_16_Timers_Array_Complex on ESP32C3_DEV
404 |
405 | The following is the sample terminal output when running example [ISR_16_Timers_Array_Complex](examples/ISR_16_Timers_Array_Complex) on **ESP32C3_DEV** 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 !!!
406 |
407 | ```
408 | Starting ISR_16_Timers_Array_Complex on ESP32C3_DEV
409 | ESP32_New_TimerInterrupt v1.5.0
410 | CPU Frequency = 160 MHz
411 | Starting ITimer OK, millis() = 2187
412 | SimpleTimer : 2, ms : 12193, Dms : 10004
413 | Timer : 0, programmed : 5000, actual : 5008
414 | Timer : 1, programmed : 10000, actual : 0
415 | Timer : 2, programmed : 15000, actual : 0
416 | Timer : 3, programmed : 20000, actual : 0
417 | Timer : 4, programmed : 25000, actual : 0
418 | Timer : 5, programmed : 30000, actual : 0
419 | Timer : 6, programmed : 35000, actual : 0
420 | Timer : 7, programmed : 40000, actual : 0
421 | Timer : 8, programmed : 45000, actual : 0
422 | Timer : 9, programmed : 50000, actual : 0
423 | Timer : 10, programmed : 55000, actual : 0
424 | Timer : 11, programmed : 60000, actual : 0
425 | Timer : 12, programmed : 65000, actual : 0
426 | Timer : 13, programmed : 70000, actual : 0
427 | Timer : 14, programmed : 75000, actual : 0
428 | Timer : 15, programmed : 80000, actual : 0
429 | SimpleTimer : 2, ms : 22251, Dms : 10058
430 | Timer : 0, programmed : 5000, actual : 5000
431 | Timer : 1, programmed : 10000, actual : 10000
432 | Timer : 2, programmed : 15000, actual : 15008
433 | Timer : 3, programmed : 20000, actual : 20008
434 | Timer : 4, programmed : 25000, actual : 0
435 | Timer : 5, programmed : 30000, actual : 0
436 | Timer : 6, programmed : 35000, actual : 0
437 | Timer : 7, programmed : 40000, actual : 0
438 | Timer : 8, programmed : 45000, actual : 0
439 | Timer : 9, programmed : 50000, actual : 0
440 | Timer : 10, programmed : 55000, actual : 0
441 | Timer : 11, programmed : 60000, actual : 0
442 | Timer : 12, programmed : 65000, actual : 0
443 | Timer : 13, programmed : 70000, actual : 0
444 | Timer : 14, programmed : 75000, actual : 0
445 | Timer : 15, programmed : 80000, actual : 0
446 | SimpleTimer : 2, ms : 32310, Dms : 10059
447 | Timer : 0, programmed : 5000, actual : 5000
448 | Timer : 1, programmed : 10000, actual : 10000
449 | Timer : 2, programmed : 15000, actual : 15000
450 | Timer : 3, programmed : 20000, actual : 20008
451 | Timer : 4, programmed : 25000, actual : 25008
452 | Timer : 5, programmed : 30000, actual : 30008
453 | Timer : 6, programmed : 35000, actual : 0
454 | Timer : 7, programmed : 40000, actual : 0
455 | Timer : 8, programmed : 45000, actual : 0
456 | Timer : 9, programmed : 50000, actual : 0
457 | Timer : 10, programmed : 55000, actual : 0
458 | Timer : 11, programmed : 60000, actual : 0
459 | Timer : 12, programmed : 65000, actual : 0
460 | Timer : 13, programmed : 70000, actual : 0
461 | Timer : 14, programmed : 75000, actual : 0
462 | Timer : 15, programmed : 80000, actual : 0
463 | SimpleTimer : 2, ms : 42369, Dms : 10059
464 | Timer : 0, programmed : 5000, actual : 5000
465 | Timer : 1, programmed : 10000, actual : 10000
466 | Timer : 2, programmed : 15000, actual : 15000
467 | Timer : 3, programmed : 20000, actual : 20000
468 | Timer : 4, programmed : 25000, actual : 25008
469 | Timer : 5, programmed : 30000, actual : 30008
470 | Timer : 6, programmed : 35000, actual : 35008
471 | Timer : 7, programmed : 40000, actual : 40008
472 | Timer : 8, programmed : 45000, actual : 0
473 | Timer : 9, programmed : 50000, actual : 0
474 | Timer : 10, programmed : 55000, actual : 0
475 | Timer : 11, programmed : 60000, actual : 0
476 | Timer : 12, programmed : 65000, actual : 0
477 | Timer : 13, programmed : 70000, actual : 0
478 | Timer : 14, programmed : 75000, actual : 0
479 | Timer : 15, programmed : 80000, actual : 0
480 | SimpleTimer : 2, ms : 52429, Dms : 10060
481 | Timer : 0, programmed : 5000, actual : 5000
482 | Timer : 1, programmed : 10000, actual : 10000
483 | Timer : 2, programmed : 15000, actual : 15000
484 | Timer : 3, programmed : 20000, actual : 20000
485 | Timer : 4, programmed : 25000, actual : 25000
486 | Timer : 5, programmed : 30000, actual : 30008
487 | Timer : 6, programmed : 35000, actual : 35008
488 | Timer : 7, programmed : 40000, actual : 40008
489 | Timer : 8, programmed : 45000, actual : 45008
490 | Timer : 9, programmed : 50000, actual : 50008
491 | Timer : 10, programmed : 55000, actual : 0
492 | Timer : 11, programmed : 60000, actual : 0
493 | Timer : 12, programmed : 65000, actual : 0
494 | Timer : 13, programmed : 70000, actual : 0
495 | Timer : 14, programmed : 75000, actual : 0
496 | Timer : 15, programmed : 80000, actual : 0
497 | SimpleTimer : 2, ms : 62490, Dms : 10061
498 | Timer : 0, programmed : 5000, actual : 5000
499 | Timer : 1, programmed : 10000, actual : 10000
500 | Timer : 2, programmed : 15000, actual : 15000
501 | Timer : 3, programmed : 20000, actual : 20000
502 | Timer : 4, programmed : 25000, actual : 25000
503 | Timer : 5, programmed : 30000, actual : 30000
504 | Timer : 6, programmed : 35000, actual : 35008
505 | Timer : 7, programmed : 40000, actual : 40008
506 | Timer : 8, programmed : 45000, actual : 45008
507 | Timer : 9, programmed : 50000, actual : 50008
508 | Timer : 10, programmed : 55000, actual : 55008
509 | Timer : 11, programmed : 60000, actual : 60008
510 | Timer : 12, programmed : 65000, actual : 0
511 | Timer : 13, programmed : 70000, actual : 0
512 | Timer : 14, programmed : 75000, actual : 0
513 | Timer : 15, programmed : 80000, actual : 0
514 | SimpleTimer : 2, ms : 72551, Dms : 10061
515 | Timer : 0, programmed : 5000, actual : 5000
516 | Timer : 1, programmed : 10000, actual : 10000
517 | Timer : 2, programmed : 15000, actual : 15000
518 | Timer : 3, programmed : 20000, actual : 20000
519 | Timer : 4, programmed : 25000, actual : 25000
520 | Timer : 5, programmed : 30000, actual : 30000
521 | Timer : 6, programmed : 35000, actual : 35000
522 | Timer : 7, programmed : 40000, actual : 40008
523 | Timer : 8, programmed : 45000, actual : 45008
524 | Timer : 9, programmed : 50000, actual : 50008
525 | Timer : 10, programmed : 55000, actual : 55008
526 | Timer : 11, programmed : 60000, actual : 60008
527 | Timer : 12, programmed : 65000, actual : 65008
528 | Timer : 13, programmed : 70000, actual : 70008
529 | Timer : 14, programmed : 75000, actual : 0
530 | Timer : 15, programmed : 80000, actual : 0
531 | SimpleTimer : 2, ms : 82613, Dms : 10062
532 | Timer : 0, programmed : 5000, actual : 5000
533 | Timer : 1, programmed : 10000, actual : 10000
534 | Timer : 2, programmed : 15000, actual : 15000
535 | Timer : 3, programmed : 20000, actual : 20000
536 | Timer : 4, programmed : 25000, actual : 25000
537 | Timer : 5, programmed : 30000, actual : 30000
538 | Timer : 6, programmed : 35000, actual : 35000
539 | Timer : 7, programmed : 40000, actual : 40000
540 | Timer : 8, programmed : 45000, actual : 45008
541 | Timer : 9, programmed : 50000, actual : 50008
542 | Timer : 10, programmed : 55000, actual : 55008
543 | Timer : 11, programmed : 60000, actual : 60008
544 | Timer : 12, programmed : 65000, actual : 65008
545 | Timer : 13, programmed : 70000, actual : 70008
546 | Timer : 14, programmed : 75000, actual : 75008
547 | Timer : 15, programmed : 80000, actual : 80008
548 | ```
549 |
550 | ---
551 |
552 | ### 5. ISR_16_Timers_Array on ESP32S2_DEV
553 |
554 | The following is the sample terminal output when running example [ISR_16_Timers_Array](examples/ISR_16_Timers_Array) on **ESP32S2_DEV** 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 !!!
555 |
556 |
557 | ```
558 | Starting ISR_16_Timers_Array on ESP32S2_DEV
559 | ESP32_New_TimerInterrupt v1.5.0
560 | CPU Frequency = 240 MHz
561 | Starting ITimer OK, millis() = 2538
562 | simpleTimerDoingSomething2s: Delta programmed ms = 2000, actual = 10008
563 | simpleTimerDoingSomething2s: Delta programmed ms = 2000, actual = 10005
564 | ```
565 |
566 | ---
567 |
568 | ### 6. ISR_16_Timers_Array_Complex on ESP32S3_DEV
569 |
570 | The following is the sample terminal output when running example [ISR_16_Timers_Array_Complex](examples/ISR_16_Timers_Array_Complex) on **ESP32S3_DEV** 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 !!!
571 |
572 | ```
573 | Starting ISR_16_Timers_Array_Complex on ESP32S3_DEV
574 | ESP32_New_TimerInterrupt v1.5.0
575 | CPU Frequency = 240 MHz
576 | [TISR] ESP32_S3_TimerInterrupt: _timerNo = 1 , _fre = 1000000
577 | [TISR] TIMER_BASE_CLK = 80000000 , TIMER_DIVIDER = 80
578 | [TISR] _timerIndex = 1 , _timerGroup = 0
579 | [TISR] _count = 0 - 10000
580 | [TISR] timer_set_alarm_value = 10000.00
581 | Starting ITimer OK, millis() = 2118
582 | SimpleTimer : 2, ms : 12117, Dms : 9999
583 | Timer : 0, programmed : 5000, actual : 5009
584 | Timer : 1, programmed : 10000, actual : 0
585 | Timer : 2, programmed : 15000, actual : 0
586 | Timer : 3, programmed : 20000, actual : 0
587 | Timer : 4, programmed : 25000, actual : 0
588 | Timer : 5, programmed : 30000, actual : 0
589 | Timer : 6, programmed : 35000, actual : 0
590 | Timer : 7, programmed : 40000, actual : 0
591 | Timer : 8, programmed : 45000, actual : 0
592 | Timer : 9, programmed : 50000, actual : 0
593 | Timer : 10, programmed : 55000, actual : 0
594 | Timer : 11, programmed : 60000, actual : 0
595 | Timer : 12, programmed : 65000, actual : 0
596 | Timer : 13, programmed : 70000, actual : 0
597 | Timer : 14, programmed : 75000, actual : 0
598 | Timer : 15, programmed : 80000, actual : 0
599 | SimpleTimer : 2, ms : 22180, Dms : 10063
600 | Timer : 0, programmed : 5000, actual : 5000
601 | Timer : 1, programmed : 10000, actual : 10000
602 | Timer : 2, programmed : 15000, actual : 15009
603 | Timer : 3, programmed : 20000, actual : 20009
604 | Timer : 4, programmed : 25000, actual : 0
605 | Timer : 5, programmed : 30000, actual : 0
606 | Timer : 6, programmed : 35000, actual : 0
607 | Timer : 7, programmed : 40000, actual : 0
608 | Timer : 8, programmed : 45000, actual : 0
609 | Timer : 9, programmed : 50000, actual : 0
610 | Timer : 10, programmed : 55000, actual : 0
611 | Timer : 11, programmed : 60000, actual : 0
612 | Timer : 12, programmed : 65000, actual : 0
613 | Timer : 13, programmed : 70000, actual : 0
614 | Timer : 14, programmed : 75000, actual : 0
615 | Timer : 15, programmed : 80000, actual : 0
616 | SimpleTimer : 2, ms : 32243, Dms : 10063
617 | Timer : 0, programmed : 5000, actual : 5000
618 | Timer : 1, programmed : 10000, actual : 10000
619 | Timer : 2, programmed : 15000, actual : 15000
620 | Timer : 3, programmed : 20000, actual : 20009
621 | Timer : 4, programmed : 25000, actual : 25009
622 | Timer : 5, programmed : 30000, actual : 30009
623 | Timer : 6, programmed : 35000, actual : 0
624 | Timer : 7, programmed : 40000, actual : 0
625 | Timer : 8, programmed : 45000, actual : 0
626 | Timer : 9, programmed : 50000, actual : 0
627 | Timer : 10, programmed : 55000, actual : 0
628 | Timer : 11, programmed : 60000, actual : 0
629 | Timer : 12, programmed : 65000, actual : 0
630 | Timer : 13, programmed : 70000, actual : 0
631 | Timer : 14, programmed : 75000, actual : 0
632 | Timer : 15, programmed : 80000, actual : 0
633 | SimpleTimer : 2, ms : 42306, Dms : 10063
634 | Timer : 0, programmed : 5000, actual : 5000
635 | Timer : 1, programmed : 10000, actual : 10000
636 | Timer : 2, programmed : 15000, actual : 15000
637 | Timer : 3, programmed : 20000, actual : 20000
638 | Timer : 4, programmed : 25000, actual : 25009
639 | Timer : 5, programmed : 30000, actual : 30009
640 | Timer : 6, programmed : 35000, actual : 35009
641 | Timer : 7, programmed : 40000, actual : 40009
642 | Timer : 8, programmed : 45000, actual : 0
643 | Timer : 9, programmed : 50000, actual : 0
644 | Timer : 10, programmed : 55000, actual : 0
645 | Timer : 11, programmed : 60000, actual : 0
646 | Timer : 12, programmed : 65000, actual : 0
647 | Timer : 13, programmed : 70000, actual : 0
648 | Timer : 14, programmed : 75000, actual : 0
649 | Timer : 15, programmed : 80000, actual : 0
650 | SimpleTimer : 2, ms : 52369, Dms : 10063
651 | Timer : 0, programmed : 5000, actual : 5000
652 | Timer : 1, programmed : 10000, actual : 10000
653 | Timer : 2, programmed : 15000, actual : 15000
654 | Timer : 3, programmed : 20000, actual : 20000
655 | Timer : 4, programmed : 25000, actual : 25000
656 | Timer : 5, programmed : 30000, actual : 30009
657 | Timer : 6, programmed : 35000, actual : 35009
658 | Timer : 7, programmed : 40000, actual : 40009
659 | Timer : 8, programmed : 45000, actual : 45009
660 | Timer : 9, programmed : 50000, actual : 50009
661 | Timer : 10, programmed : 55000, actual : 0
662 | Timer : 11, programmed : 60000, actual : 0
663 | Timer : 12, programmed : 65000, actual : 0
664 | Timer : 13, programmed : 70000, actual : 0
665 | Timer : 14, programmed : 75000, actual : 0
666 | Timer : 15, programmed : 80000, actual : 0
667 | SimpleTimer : 2, ms : 62432, Dms : 10063
668 | Timer : 0, programmed : 5000, actual : 5000
669 | Timer : 1, programmed : 10000, actual : 10000
670 | Timer : 2, programmed : 15000, actual : 15000
671 | Timer : 3, programmed : 20000, actual : 20000
672 | Timer : 4, programmed : 25000, actual : 25000
673 | Timer : 5, programmed : 30000, actual : 30000
674 | Timer : 6, programmed : 35000, actual : 35009
675 | Timer : 7, programmed : 40000, actual : 40009
676 | Timer : 8, programmed : 45000, actual : 45009
677 | Timer : 9, programmed : 50000, actual : 50009
678 | Timer : 10, programmed : 55000, actual : 55009
679 | Timer : 11, programmed : 60000, actual : 60009
680 | Timer : 12, programmed : 65000, actual : 0
681 | Timer : 13, programmed : 70000, actual : 0
682 | Timer : 14, programmed : 75000, actual : 0
683 | Timer : 15, programmed : 80000, actual : 0
684 | SimpleTimer : 2, ms : 72495, Dms : 10063
685 | Timer : 0, programmed : 5000, actual : 5000
686 | Timer : 1, programmed : 10000, actual : 10000
687 | Timer : 2, programmed : 15000, actual : 15000
688 | Timer : 3, programmed : 20000, actual : 20000
689 | Timer : 4, programmed : 25000, actual : 25000
690 | Timer : 5, programmed : 30000, actual : 30000
691 | Timer : 6, programmed : 35000, actual : 35000
692 | Timer : 7, programmed : 40000, actual : 40009
693 | Timer : 8, programmed : 45000, actual : 45009
694 | Timer : 9, programmed : 50000, actual : 50009
695 | Timer : 10, programmed : 55000, actual : 55009
696 | Timer : 11, programmed : 60000, actual : 60009
697 | Timer : 12, programmed : 65000, actual : 65009
698 | Timer : 13, programmed : 70000, actual : 70009
699 | Timer : 14, programmed : 75000, actual : 0
700 | Timer : 15, programmed : 80000, actual : 0
701 | SimpleTimer : 2, ms : 82558, Dms : 10063
702 | Timer : 0, programmed : 5000, actual : 5000
703 | Timer : 1, programmed : 10000, actual : 10000
704 | Timer : 2, programmed : 15000, actual : 15000
705 | Timer : 3, programmed : 20000, actual : 20000
706 | Timer : 4, programmed : 25000, actual : 25000
707 | Timer : 5, programmed : 30000, actual : 30000
708 | Timer : 6, programmed : 35000, actual : 35000
709 | Timer : 7, programmed : 40000, actual : 40000
710 | Timer : 8, programmed : 45000, actual : 45009
711 | Timer : 9, programmed : 50000, actual : 50009
712 | Timer : 10, programmed : 55000, actual : 55009
713 | Timer : 11, programmed : 60000, actual : 60009
714 | Timer : 12, programmed : 65000, actual : 65009
715 | Timer : 13, programmed : 70000, actual : 70009
716 | Timer : 14, programmed : 75000, actual : 75009
717 | Timer : 15, programmed : 80000, actual : 80009
718 | ```
719 |
720 | ---
721 | ---
722 |
723 | ### Debug
724 |
725 | Debug is enabled by default on Serial.
726 |
727 | You can also change the debugging level (_TIMERINTERRUPT_LOGLEVEL_) from 0 to 4
728 |
729 | ```cpp
730 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
731 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
732 | // Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
733 | #define TIMER_INTERRUPT_DEBUG 0
734 | #define _TIMERINTERRUPT_LOGLEVEL_ 0
735 | ```
736 |
737 | ---
738 |
739 | ### Troubleshooting
740 |
741 | If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards.
742 |
743 | Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions.
744 |
745 |
746 | ---
747 | ---
748 |
749 |
750 | ### Issues
751 |
752 | Submit issues to: [ESP32_New_TimerInterrupt issues](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues)
753 |
754 | ---
755 | ---
756 |
757 | ## TO DO
758 |
759 | 1. Search for bug and improvement.
760 |
761 |
762 |
763 | ## DONE
764 |
765 | 1. Basic hardware timers for ESP32, ESP32-S2, ESP32-S3 and ESP32_C3 for [ESP32 core v2.0.0-rc1+](https://github.com/espressif/arduino-esp32/releases/tag/2.0.0-rc1)
766 | 2. More hardware-initiated software-enabled timers
767 | 3. Longer time interval
768 | 4. Similar features for remaining Arduino boards such as SAMD21, SAMD51, SAM-DUE, nRF52, ESP8266, STM32, etc.
769 | 5. Fix compiler errors due to conflict to some libraries.
770 | 6. Add complex examples.
771 | 7. Avoid using D1 in examples due to issue with core v2.0.0 and v2.0.1.
772 | 8. Avoid using float in ISR due to issue with core v2.0.0 and v2.0.1.
773 | 9. Fix `multiple-definitions` linker error. Drop `src_cpp` and `src_h` directories
774 | 10. Optimize library code by using `reference-passing` instead of `value-passing`
775 | 11. Add support to **ESP32-S3 (ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.)**
776 | 12. Add support to many more boards, such as
777 | - ESP32_S2 : ESP32S2 Native USB, UM FeatherS2 Neo, UM TinyS2, UM RMP, microS2, LOLIN_S2_MINI, LOLIN_S2_PICO, ADAFRUIT_FEATHER_ESP32S2, ADAFRUIT_FEATHER_ESP32S2_TFT, ATMegaZero ESP32-S2, Deneyap Mini, FRANZININHO_WIFI, FRANZININHO_WIFI_MSC
778 | - ESP32_S3 : UM TinyS3, UM PROS3, UM FeatherS3, ESP32_S3_USB_OTG, ESP32S3_CAM_LCD, DFROBOT_FIREBEETLE_2_ESP32S3, ADAFRUIT_FEATHER_ESP32S3_TFT
779 | - ESP32_C3 : LOLIN_C3_MINI, DFROBOT_BEETLE_ESP32_C3, ADAFRUIT_QTPY_ESP32C3, AirM2M_CORE_ESP32C3, XIAO_ESP32C3
780 | 13. Use `allman astyle` and add `utils`
781 |
782 |
783 |
784 | ---
785 | ---
786 |
787 | ### Contributions and Thanks
788 |
789 | Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library.
790 |
791 |
792 | ---
793 |
794 | ## Contributing
795 |
796 | If you want to contribute to this project:
797 | - Report bugs and errors
798 | - Ask for enhancements
799 | - Create issues and pull requests
800 | - Tell other people about this library
801 |
802 | ---
803 |
804 | ### License
805 |
806 | - The library is licensed under [MIT](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/blob/main/LICENSE)
807 |
808 | ---
809 |
810 | ## Copyright
811 |
812 | Copyright 2021- Khoi Hoang
813 |
814 |
815 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # ESP32_New_TimerInterrupt Library
2 |
3 | [](https://www.ardu-badge.com/ESP32_New_TimerInterrupt)
4 | [](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/releases)
5 | [](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/blob/main/LICENSE)
6 | [](#Contributing)
7 | [](http://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues)
8 |
9 |
10 |
11 |
12 |
13 | ---
14 | ---
15 |
16 | ## Table of Contents
17 |
18 | * [Changelog](#changelog)
19 | * [Releases v1.5.0](#releases-v150)
20 | * [Releases v1.4.0](#releases-v140)
21 | * [Releases v1.3.0](#releases-v130)
22 | * [Releases v1.2.1](#releases-v121)
23 | * [Releases v1.2.0](#releases-v120)
24 | * [Releases v1.1.0](#releases-v110)
25 | * [Releases v1.0.1](#releases-v101)
26 | * [Releases v1.0.0](#releases-v100)
27 |
28 |
29 | ---
30 | ---
31 |
32 | ## Changelog
33 |
34 | ### Releases v1.5.0
35 |
36 | 1. Fix doubled time for ESP32_C3, ESP32_S2 and ESP32_S3. Check [Error in the value defined by TIMER0_INTERVAL_MS #28](https://github.com/khoih-prog/ESP32_New_TimerInterrupt/issues/28)
37 | 2. Modify examples to avoid using `LED_BUILTIN` / `GPIO2` as it can cause crash in some boards, such as `ESP32_C3`
38 | 3. Use `allman astyle` and add `utils`
39 |
40 | ### Releases v1.4.0
41 |
42 | 1. Suppress warnings for ESP32_C3, ESP32_S2 and ESP32_S3
43 | 2. Add support to
44 | - ESP32_S2 : ESP32S2 Native USB, UM FeatherS2 Neo, UM TinyS2, UM RMP, microS2, LOLIN_S2_MINI, LOLIN_S2_PICO, ADAFRUIT_FEATHER_ESP32S2, ADAFRUIT_FEATHER_ESP32S2_TFT, ATMegaZero ESP32-S2, Deneyap Mini, FRANZININHO_WIFI, FRANZININHO_WIFI_MSC
45 | - ESP32_S3 : UM TinyS3, UM PROS3, UM FeatherS3, ESP32_S3_USB_OTG, ESP32S3_CAM_LCD, DFROBOT_FIREBEETLE_2_ESP32S3, ADAFRUIT_FEATHER_ESP32S3_TFT
46 | - ESP32_C3 : LOLIN_C3_MINI, DFROBOT_BEETLE_ESP32_C3, ADAFRUIT_QTPY_ESP32C3, AirM2M_CORE_ESP32C3, XIAO_ESP32C3
47 |
48 | ### Releases v1.3.0
49 |
50 | 1. Suppress errors and warnings for new ESP32 core v2.0.4+
51 |
52 | ### Releases v1.2.1
53 |
54 | 1. Add support to new Adafruit boards such as QTPY_ESP32S2, FEATHER_ESP32S3_NOPSRAM and QTPY_ESP32S3_NOPSRAM
55 |
56 | ### Releases v1.2.0
57 |
58 | 1. Add support to new `ESP32-S3`
59 | 2. Optimize library code by using `reference-passing` instead of `value-passing`
60 |
61 |
62 | ### Releases v1.1.0
63 |
64 | 1. Fix `multiple-definitions` linker error. Drop `src_cpp` and `src_h` directories
65 |
66 | ### Releases v1.0.1
67 |
68 | 1. Avoid using `PIN_D1 (GPIO1)` in your code due to issue with core v2.0.0 and v2.0.1. Check [ESP32 Core v2.0.1 / 2.0.1 RC1 crashes if using pinMode with GPIO1 #5868](https://github.com/espressif/arduino-esp32/issues/5868). Only OK with core v1.0.6-
69 | 2. Don't use `float` in `ISR` due to issue with core v2.0.0 and v2.0.1. Only OK with core v1.0.6-.
70 | 3. Delete Blynk-related examples
71 | 4. Add changelog.md
72 |
73 | ### Releases v1.0.0
74 |
75 | 1. Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with [ESP32 core v2.0.0-rc1+](https://github.com/espressif/arduino-esp32/releases/tag/2.0.0-rc1)
76 |
77 |
78 |
--------------------------------------------------------------------------------
/examples/Argument_None/Argument_None.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | Argument_None.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 | *****************************************************************************************************************************/
23 |
24 | /*
25 | Notes:
26 | Special design is necessary to share data between interrupt code and the rest of your program.
27 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
28 | variable can not spontaneously change. Because your function may change variables while your program is using them,
29 | the compiler needs this hint. But volatile alone is often not enough.
30 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
31 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
32 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
33 | or the entire sequence of your code which accesses the data.
34 | */
35 |
36 | #if !defined( ESP32 )
37 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
38 | #endif
39 |
40 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
41 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
42 | #define _TIMERINTERRUPT_LOGLEVEL_ 4
43 |
44 | #include "ESP32_New_TimerInterrupt.h"
45 |
46 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
47 | // Don't use PIN_D2 with ESP32_C3 (crash)
48 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
49 | #define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32
50 |
51 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
52 | // and you can't use float calculation inside ISR
53 | // Only OK in core v1.0.6-
54 | bool IRAM_ATTR TimerHandler0(void * timerNo)
55 | {
56 | static bool toggle0 = false;
57 |
58 | //timer interrupt toggles pin PIN_D19
59 | digitalWrite(19, toggle0);
60 | toggle0 = !toggle0;
61 |
62 | return true;
63 | }
64 |
65 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
66 | // and you can't use float calculation inside ISR
67 | // Only OK in core v1.0.6-
68 | bool IRAM_ATTR TimerHandler1(void * timerNo)
69 | {
70 | /////////////////////////////////////////////////////////
71 |
72 | static bool toggle1 = false;
73 |
74 | //timer interrupt toggles outputPin
75 | digitalWrite(PIN_D3, toggle1);
76 | toggle1 = !toggle1;
77 |
78 | return true;
79 | }
80 |
81 | #define TIMER0_INTERVAL_MS 100 //1000
82 |
83 | #define TIMER1_INTERVAL_MS 5000
84 |
85 | // Init ESP32 timer 0 and 1
86 | ESP32Timer ITimer0(0);
87 | ESP32Timer ITimer1(1);
88 |
89 | void setup()
90 | {
91 | pinMode(PIN_D19, OUTPUT);
92 | pinMode(PIN_D3, OUTPUT);
93 |
94 | Serial.begin(115200);
95 |
96 | while (!Serial && millis() < 5000);
97 |
98 | delay(500);
99 |
100 | Serial.print(F("\nStarting Argument_None on "));
101 | Serial.println(ARDUINO_BOARD);
102 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
103 | Serial.print(F("CPU Frequency = "));
104 | Serial.print(F_CPU / 1000000);
105 | Serial.println(F(" MHz"));
106 |
107 | // Using ESP32 => 80 / 160 / 240MHz CPU clock ,
108 | // For 64-bit timer counter
109 | // For 16-bit timer prescaler up to 1024
110 |
111 | // Interval in microsecs
112 | if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
113 | //if (ITimer0.attachInterrupt(1, TimerHandler0))
114 | {
115 | Serial.print(F("Starting ITimer0 OK, millis() = "));
116 | Serial.println(millis());
117 | }
118 | else
119 | Serial.println(F("Can't set ITimer0. Select another Timer, freq. or timer"));
120 |
121 |
122 | // Interval in microsecs
123 | if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
124 | //if (ITimer1.attachInterrupt(2, TimerHandler1))
125 | {
126 | Serial.print(F("Starting ITimer1 OK, millis() = "));
127 | Serial.println(millis());
128 | }
129 | else
130 | Serial.println(F("Can't set ITimer1. Select another Timer, freq. or timer"));
131 | }
132 |
133 | void loop()
134 | {
135 | delay(1);
136 | }
137 |
--------------------------------------------------------------------------------
/examples/Change_Interval/Change_Interval.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | Change_Interval.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 | *****************************************************************************************************************************/
23 |
24 | /*
25 | Notes:
26 | Special design is necessary to share data between interrupt code and the rest of your program.
27 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
28 | variable can not spontaneously change. Because your function may change variables while your program is using them,
29 | the compiler needs this hint. But volatile alone is often not enough.
30 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
31 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
32 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
33 | or the entire sequence of your code which accesses the data.
34 | */
35 |
36 | #if !defined( ESP32 )
37 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
38 | #endif
39 |
40 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
41 | #define _TIMERINTERRUPT_LOGLEVEL_ 1
42 |
43 | #include "ESP32_New_TimerInterrupt.h"
44 |
45 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
46 | // Don't use PIN_D2 with ESP32_C3 (crash)
47 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
48 | #define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32
49 |
50 | volatile uint32_t Timer0Count = 0;
51 | volatile uint32_t Timer1Count = 0;
52 |
53 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
54 | // and you can't use float calculation inside ISR
55 | // Only OK in core v1.0.6-
56 | bool IRAM_ATTR TimerHandler0(void * timerNo)
57 | {
58 | static bool toggle0 = false;
59 |
60 | // Flag for checking to be sure ISR is working as Serial.print is not OK here in ISR
61 | Timer0Count++;
62 |
63 | //timer interrupt toggles pin PIN_D19
64 | digitalWrite(PIN_D19, toggle0);
65 | toggle0 = !toggle0;
66 |
67 | return true;
68 | }
69 |
70 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
71 | // and you can't use float calculation inside ISR
72 | // Only OK in core v1.0.6-
73 | bool IRAM_ATTR TimerHandler1(void * timerNo)
74 | {
75 | static bool toggle1 = false;
76 |
77 | // Flag for checking to be sure ISR is working as Serial.print is not OK here in ISR
78 | Timer1Count++;
79 |
80 | //timer interrupt toggles PIN_D3
81 | digitalWrite(PIN_D3, toggle1);
82 | toggle1 = !toggle1;
83 |
84 | return true;
85 | }
86 |
87 | void printResult(uint32_t currTime)
88 | {
89 | Serial.print(F("Time = "));
90 | Serial.print(currTime);
91 | Serial.print(F(", Timer0Count = "));
92 | Serial.print(Timer0Count);
93 | Serial.print(F(", Timer1Count = "));
94 | Serial.println(Timer1Count);
95 | }
96 |
97 | #define TIMER0_INTERVAL_MS 2000
98 |
99 | #define TIMER1_INTERVAL_MS 5000
100 |
101 | // Init ESP32 timer 0
102 | ESP32Timer ITimer0(0);
103 | ESP32Timer ITimer1(1);
104 |
105 | void setup()
106 | {
107 | pinMode(PIN_D19, OUTPUT);
108 | pinMode(PIN_D3, OUTPUT);
109 |
110 | Serial.begin(115200);
111 |
112 | while (!Serial && millis() < 5000);
113 |
114 | delay(500);
115 |
116 | Serial.print(F("\nStarting Change_Interval on "));
117 | Serial.println(ARDUINO_BOARD);
118 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
119 | Serial.print(F("CPU Frequency = "));
120 | Serial.print(F_CPU / 1000000);
121 | Serial.println(F(" MHz"));
122 |
123 | // Interval in microsecs
124 | if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
125 | {
126 | Serial.print(F("Starting ITimer0 OK, millis() = "));
127 | Serial.println(millis());
128 | }
129 | else
130 | Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
131 |
132 | // Interval in microsecs
133 | if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
134 | {
135 | Serial.print(F("Starting ITimer1 OK, millis() = "));
136 | Serial.println(millis());
137 | }
138 | else
139 | Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
140 | }
141 |
142 | #define CHECK_INTERVAL_MS 10000L
143 | #define CHANGE_INTERVAL_MS 20000L
144 |
145 | void loop()
146 | {
147 | static uint32_t lastTime = 0;
148 | static uint32_t lastChangeTime = 0;
149 | static uint32_t currTime;
150 | static uint32_t multFactor = 0;
151 |
152 | currTime = millis();
153 |
154 | if (currTime - lastTime > CHECK_INTERVAL_MS)
155 | {
156 | printResult(currTime);
157 | lastTime = currTime;
158 |
159 | if (currTime - lastChangeTime > CHANGE_INTERVAL_MS)
160 | {
161 | //setInterval(unsigned long interval, timerCallback callback)
162 | multFactor = (multFactor + 1) % 2;
163 |
164 | ITimer0.setInterval(TIMER0_INTERVAL_MS * 1000 * (multFactor + 1), TimerHandler0);
165 | ITimer1.setInterval(TIMER1_INTERVAL_MS * 1000 * (multFactor + 1), TimerHandler1);
166 |
167 | Serial.print(F("Changing Interval, Timer0 = "));
168 | Serial.print(TIMER0_INTERVAL_MS * (multFactor + 1));
169 | Serial.print(F(", Timer1 = "));
170 | Serial.println(TIMER1_INTERVAL_MS * (multFactor + 1));
171 |
172 | lastChangeTime = currTime;
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/examples/ISR_16_Timers_Array/ISR_16_Timers_Array.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | ISR_16_Timers_Array.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 | *****************************************************************************************************************************/
23 | /*
24 | Notes:
25 | Special design is necessary to share data between interrupt code and the rest of your program.
26 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
27 | variable can not spontaneously change. Because your function may change variables while your program is using them,
28 | the compiler needs this hint. But volatile alone is often not enough.
29 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
30 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
31 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
32 | or the entire sequence of your code which accesses the data.
33 |
34 | RPM Measuring uses high frequency hardware timer 1Hz == 1ms) to measure the time from of one rotation, in ms
35 | then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor
36 | Asssuming LOW is active.
37 | For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing
38 | If the time between active state is less than 8ms => consider noise.
39 | RPM = 60000 / (rotation time in ms)
40 |
41 | We use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state
42 |
43 | This example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs.
44 | Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet
45 | and Blynk services. You can also have many (up to 16) timers to use.
46 | This non-being-blocked important feature is absolutely necessary for mission-critical tasks.
47 | You'll see blynkTimer is blocked while connecting to WiFi / Internet / Blynk, and elapsed time is very unaccurate
48 | In this super simple example, you don't see much different after Blynk is connected, because of no competing task is
49 | written
50 | */
51 |
52 | #if !defined( ESP32 )
53 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
54 | #endif
55 |
56 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
57 | #define _TIMERINTERRUPT_LOGLEVEL_ 0
58 |
59 | #include "ESP32_New_TimerInterrupt.h"
60 | #include "ESP32_New_ISR_Timer.h"
61 |
62 | #include // https://github.com/jfturcot/SimpleTimer
63 |
64 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
65 |
66 | #ifndef LED_BLUE
67 | #define LED_BLUE 25
68 | #endif
69 |
70 | #ifndef LED_RED
71 | #define LED_RED 27
72 | #endif
73 |
74 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
75 | // Don't use PIN_D2 with ESP32_C3 (crash)
76 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
77 |
78 | #define HW_TIMER_INTERVAL_MS 1L
79 |
80 | volatile uint32_t startMillis = 0;
81 |
82 | // Init ESP32 timer 1
83 | ESP32Timer ITimer(1);
84 |
85 | // Init ESP32_ISR_Timer
86 | ESP32_ISR_Timer ISR_Timer;
87 |
88 | #define LED_TOGGLE_INTERVAL_MS 2000L
89 |
90 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
91 | // and you can't use float calculation inside ISR
92 | // Only OK in core v1.0.6-
93 | bool IRAM_ATTR TimerHandler(void * timerNo)
94 | {
95 | static bool toggle = false;
96 | static bool started = false;
97 | static int timeRun = 0;
98 |
99 | ISR_Timer.run();
100 |
101 | // Toggle LED every LED_TOGGLE_INTERVAL_MS = 2000ms = 2s
102 | if (++timeRun == (LED_TOGGLE_INTERVAL_MS / HW_TIMER_INTERVAL_MS) )
103 | {
104 | timeRun = 0;
105 |
106 | if (!started)
107 | {
108 | started = true;
109 | pinMode(PIN_D19, OUTPUT);
110 | }
111 |
112 | //timer interrupt toggles pin PIN_D19
113 | digitalWrite(PIN_D19, toggle);
114 | toggle = !toggle;
115 | }
116 |
117 | return true;
118 | }
119 |
120 | #define NUMBER_ISR_TIMERS 16
121 |
122 | // You can assign any interval for any timer here, in milliseconds
123 | uint32_t TimerInterval[NUMBER_ISR_TIMERS] =
124 | {
125 | 1000L, 2000L, 3000L, 4000L, 5000L, 6000L, 7000L, 8000L,
126 | 9000L, 10000L, 11000L, 12000L, 13000L, 14000L, 15000L, 16000L
127 | };
128 |
129 | typedef void (*irqCallback) ();
130 |
131 |
132 | // In ESP32, avoid doing something fancy in ISR, for example complex Serial.print with String() argument
133 | // The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment
134 | // Or you can get this run-time error / crash
135 | void doingSomething0()
136 | {
137 | }
138 |
139 | void doingSomething1()
140 | {
141 | }
142 |
143 | void doingSomething2()
144 | {
145 | }
146 |
147 | void doingSomething3()
148 | {
149 | }
150 |
151 | void doingSomething4()
152 | {
153 | }
154 |
155 | void doingSomething5()
156 | {
157 | }
158 |
159 | void doingSomething6()
160 | {
161 | }
162 |
163 | void doingSomething7()
164 | {
165 | }
166 |
167 | void doingSomething8()
168 | {
169 | }
170 |
171 | void doingSomething9()
172 | {
173 | }
174 |
175 | void doingSomething10()
176 | {
177 | }
178 |
179 | void doingSomething11()
180 | {
181 | }
182 |
183 | void doingSomething12()
184 | {
185 | }
186 |
187 | void doingSomething13()
188 | {
189 | }
190 |
191 | void doingSomething14()
192 | {
193 | }
194 |
195 | void doingSomething15()
196 | {
197 | }
198 |
199 | irqCallback irqCallbackFunc[NUMBER_ISR_TIMERS] =
200 | {
201 | doingSomething0, doingSomething1, doingSomething2, doingSomething3,
202 | doingSomething4, doingSomething5, doingSomething6, doingSomething7,
203 | doingSomething8, doingSomething9, doingSomething10, doingSomething11,
204 | doingSomething12, doingSomething13, doingSomething14, doingSomething15
205 | };
206 |
207 | ////////////////////////////////////////////////
208 |
209 |
210 | #define SIMPLE_TIMER_MS 2000L
211 |
212 | // Init SimpleTimer
213 | SimpleTimer simpleTimer;
214 |
215 | // Here is software Timer, you can do somewhat fancy stuffs without many issues.
216 | // But always avoid
217 | // 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead
218 | // 2. Very long "do", "while", "for" loops without predetermined exit time.
219 | void simpleTimerDoingSomething2s()
220 | {
221 | static unsigned long previousMillis = startMillis;
222 |
223 | Serial.print(F("simpleTimerDoingSomething2s: Delta programmed ms = "));
224 | Serial.print(SIMPLE_TIMER_MS);
225 | Serial.print(F(", actual = "));
226 | Serial.println(millis() - previousMillis);
227 |
228 | previousMillis = millis();
229 | }
230 |
231 | void setup()
232 | {
233 | Serial.begin(115200);
234 |
235 | while (!Serial && millis() < 5000);
236 |
237 | delay(500);
238 |
239 | Serial.print(F("\nStarting ISR_16_Timers_Array on "));
240 | Serial.println(ARDUINO_BOARD);
241 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
242 | Serial.print(F("CPU Frequency = "));
243 | Serial.print(F_CPU / 1000000);
244 | Serial.println(F(" MHz"));
245 |
246 | // Interval in microsecs
247 | if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler))
248 | {
249 | startMillis = millis();
250 | Serial.print(F("Starting ITimer OK, millis() = "));
251 | Serial.println(startMillis);
252 | }
253 | else
254 | Serial.println(F("Can't set ITimer. Select another freq. or timer"));
255 |
256 | // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary
257 | // You can use up to 16 timer for each ISR_Timer
258 | for (uint16_t i = 0; i < NUMBER_ISR_TIMERS; i++)
259 | {
260 | ISR_Timer.setInterval(TimerInterval[i], irqCallbackFunc[i]);
261 | }
262 |
263 | // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary.
264 | simpleTimer.setInterval(SIMPLE_TIMER_MS, simpleTimerDoingSomething2s);
265 | }
266 |
267 | #define BLOCKING_TIME_MS 10000L
268 |
269 | void loop()
270 | {
271 | // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer
272 | // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer
273 | // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS)
274 | // While that of ISR_Timer is still prefect.
275 | delay(BLOCKING_TIME_MS);
276 |
277 | // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary
278 | // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer.
279 | simpleTimer.run();
280 | }
281 |
--------------------------------------------------------------------------------
/examples/ISR_16_Timers_Array_Complex/ISR_16_Timers_Array_Complex.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | ISR_16_Timers_Array_Complex.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 | *****************************************************************************************************************************/
23 | /*
24 | Notes:
25 | Special design is necessary to share data between interrupt code and the rest of your program.
26 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
27 | variable can not spontaneously change. Because your function may change variables while your program is using them,
28 | the compiler needs this hint. But volatile alone is often not enough.
29 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
30 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
31 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
32 | or the entire sequence of your code which accesses the data.
33 |
34 | This example will demonstrate the nearly perfect accuracy compared to software timers by printing the actual elapsed millisecs.
35 | Being ISR-based timers, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet
36 | and Blynk services. You can also have many (up to 16) timers to use.
37 | This non-being-blocked important feature is absolutely necessary for mission-critical tasks.
38 | You'll see blynkTimer is blocked while connecting to WiFi / Internet / Blynk, and elapsed time is very unaccurate
39 | In this super simple example, you don't see much different after Blynk is connected, because of no competing task is
40 | written
41 | */
42 |
43 | #if !defined( ESP32 )
44 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
45 | #endif
46 |
47 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
48 | #define _TIMERINTERRUPT_LOGLEVEL_ 4
49 |
50 | #include "ESP32_New_TimerInterrupt.h"
51 | #include "ESP32_New_ISR_Timer.h"
52 |
53 | #include // https://github.com/jfturcot/SimpleTimer
54 |
55 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
56 |
57 | #ifndef LED_BLUE
58 | #define LED_BLUE 25
59 | #endif
60 |
61 | #ifndef LED_RED
62 | #define LED_RED 27
63 | #endif
64 |
65 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
66 | // Don't use PIN_D2 with ESP32_C3 (crash)
67 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
68 |
69 | #define HW_TIMER_INTERVAL_US 10000L
70 |
71 | volatile uint32_t startMillis = 0;
72 |
73 | // Init ESP32 timer 1
74 | ESP32Timer ITimer(1);
75 |
76 | // Init ESP32_ISR_Timer
77 | ESP32_ISR_Timer ISR_Timer;
78 |
79 | #define LED_TOGGLE_INTERVAL_MS 2000L
80 |
81 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
82 | // and you can't use float calculation inside ISR
83 | // Only OK in core v1.0.6-
84 | bool IRAM_ATTR TimerHandler(void * timerNo)
85 | {
86 | static bool toggle = false;
87 | static int timeRun = 0;
88 |
89 | ISR_Timer.run();
90 |
91 | // Toggle LED every LED_TOGGLE_INTERVAL_MS = 2000ms = 2s
92 | if (++timeRun == ((LED_TOGGLE_INTERVAL_MS * 1000) / HW_TIMER_INTERVAL_US) )
93 | {
94 | timeRun = 0;
95 |
96 | //timer interrupt toggles pin PIN_D19
97 | digitalWrite(PIN_D19, toggle);
98 | toggle = !toggle;
99 | }
100 |
101 | return true;
102 | }
103 |
104 | /////////////////////////////////////////////////
105 |
106 | #define NUMBER_ISR_TIMERS 16
107 |
108 | typedef void (*irqCallback) ();
109 |
110 | /////////////////////////////////////////////////
111 |
112 | #define USE_COMPLEX_STRUCT true
113 |
114 | #if USE_COMPLEX_STRUCT
115 |
116 | typedef struct
117 | {
118 | irqCallback irqCallbackFunc;
119 | uint32_t TimerInterval;
120 | unsigned long deltaMillis;
121 | unsigned long previousMillis;
122 | } ISRTimerData;
123 |
124 | // In NRF52, avoid doing something fancy in ISR, for example Serial.print()
125 | // The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment
126 | // Or you can get this run-time error / crash
127 |
128 | void doingSomething(int index);
129 |
130 | #else
131 |
132 | volatile unsigned long deltaMillis [NUMBER_ISR_TIMERS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
133 | volatile unsigned long previousMillis [NUMBER_ISR_TIMERS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
134 |
135 | // You can assign any interval for any timer here, in milliseconds
136 | uint32_t TimerInterval[NUMBER_ISR_TIMERS] =
137 | {
138 | 5000L, 10000L, 15000L, 20000L, 25000L, 30000L, 35000L, 40000L,
139 | 45000L, 50000L, 55000L, 60000L, 65000L, 70000L, 75000L, 80000L
140 | };
141 |
142 | void doingSomething(int index)
143 | {
144 | unsigned long currentMillis = millis();
145 |
146 | deltaMillis[index] = currentMillis - previousMillis[index];
147 | previousMillis[index] = currentMillis;
148 | }
149 |
150 | #endif
151 |
152 | ////////////////////////////////////
153 | // Shared
154 | ////////////////////////////////////
155 |
156 | void doingSomething0()
157 | {
158 | doingSomething(0);
159 | }
160 |
161 | void doingSomething1()
162 | {
163 | doingSomething(1);
164 | }
165 |
166 | void doingSomething2()
167 | {
168 | doingSomething(2);
169 | }
170 |
171 | void doingSomething3()
172 | {
173 | doingSomething(3);
174 | }
175 |
176 | void doingSomething4()
177 | {
178 | doingSomething(4);
179 | }
180 |
181 | void doingSomething5()
182 | {
183 | doingSomething(5);
184 | }
185 |
186 | void doingSomething6()
187 | {
188 | doingSomething(6);
189 | }
190 |
191 | void doingSomething7()
192 | {
193 | doingSomething(7);
194 | }
195 |
196 | void doingSomething8()
197 | {
198 | doingSomething(8);
199 | }
200 |
201 | void doingSomething9()
202 | {
203 | doingSomething(9);
204 | }
205 |
206 | void doingSomething10()
207 | {
208 | doingSomething(10);
209 | }
210 |
211 | void doingSomething11()
212 | {
213 | doingSomething(11);
214 | }
215 |
216 | void doingSomething12()
217 | {
218 | doingSomething(12);
219 | }
220 |
221 | void doingSomething13()
222 | {
223 | doingSomething(13);
224 | }
225 |
226 | void doingSomething14()
227 | {
228 | doingSomething(14);
229 | }
230 |
231 | void doingSomething15()
232 | {
233 | doingSomething(15);
234 | }
235 |
236 | #if USE_COMPLEX_STRUCT
237 |
238 | ISRTimerData curISRTimerData[NUMBER_ISR_TIMERS] =
239 | {
240 | //irqCallbackFunc, TimerInterval, deltaMillis, previousMillis
241 | { doingSomething0, 5000L, 0, 0 },
242 | { doingSomething1, 10000L, 0, 0 },
243 | { doingSomething2, 15000L, 0, 0 },
244 | { doingSomething3, 20000L, 0, 0 },
245 | { doingSomething4, 25000L, 0, 0 },
246 | { doingSomething5, 30000L, 0, 0 },
247 | { doingSomething6, 35000L, 0, 0 },
248 | { doingSomething7, 40000L, 0, 0 },
249 | { doingSomething8, 45000L, 0, 0 },
250 | { doingSomething9, 50000L, 0, 0 },
251 | { doingSomething10, 55000L, 0, 0 },
252 | { doingSomething11, 60000L, 0, 0 },
253 | { doingSomething12, 65000L, 0, 0 },
254 | { doingSomething13, 70000L, 0, 0 },
255 | { doingSomething14, 75000L, 0, 0 },
256 | { doingSomething15, 80000L, 0, 0 }
257 | };
258 |
259 | void doingSomething(int index)
260 | {
261 | unsigned long currentMillis = millis();
262 |
263 | curISRTimerData[index].deltaMillis = currentMillis - curISRTimerData[index].previousMillis;
264 | curISRTimerData[index].previousMillis = currentMillis;
265 | }
266 |
267 | #else
268 |
269 | irqCallback irqCallbackFunc[NUMBER_ISR_TIMERS] =
270 | {
271 | doingSomething0, doingSomething1, doingSomething2, doingSomething3,
272 | doingSomething4, doingSomething5, doingSomething6, doingSomething7,
273 | doingSomething8, doingSomething9, doingSomething10, doingSomething11,
274 | doingSomething12, doingSomething13, doingSomething14, doingSomething15
275 | };
276 |
277 | #endif
278 | ///////////////////////////////////////////
279 |
280 | #define SIMPLE_TIMER_MS 2000L
281 |
282 | // Init SimpleTimer
283 | SimpleTimer simpleTimer;
284 |
285 | // Here is software Timer, you can do somewhat fancy stuffs without many issues.
286 | // But always avoid
287 | // 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead
288 | // 2. Very long "do", "while", "for" loops without predetermined exit time.
289 | void simpleTimerDoingSomething2s()
290 | {
291 | static unsigned long previousMillis = startMillis;
292 |
293 | unsigned long currMillis = millis();
294 |
295 | Serial.print(F("SimpleTimer : "));
296 | Serial.print(SIMPLE_TIMER_MS / 1000);
297 | Serial.print(F(", ms : "));
298 | Serial.print(currMillis);
299 | Serial.print(F(", Dms : "));
300 | Serial.println(currMillis - previousMillis);
301 |
302 | for (uint16_t i = 0; i < NUMBER_ISR_TIMERS; i++)
303 | {
304 | #if USE_COMPLEX_STRUCT
305 | Serial.print(F("Timer : "));
306 | Serial.print(i);
307 | Serial.print(F(", programmed : "));
308 | Serial.print(curISRTimerData[i].TimerInterval);
309 | Serial.print(F(", actual : "));
310 | Serial.println(curISRTimerData[i].deltaMillis);
311 | #else
312 | Serial.print(F("Timer : "));
313 | Serial.print(i);
314 | Serial.print(F(", programmed : "));
315 | Serial.print(TimerInterval[i]);
316 | Serial.print(F(", actual : "));
317 | Serial.println(deltaMillis[i]);
318 | #endif
319 | }
320 |
321 | previousMillis = currMillis;
322 | }
323 |
324 | void setup()
325 | {
326 | pinMode(PIN_D19, OUTPUT);
327 |
328 | Serial.begin(115200);
329 |
330 | while (!Serial && millis() < 5000);
331 |
332 | delay(500);
333 |
334 | Serial.print(F("\nStarting ISR_16_Timers_Array_Complex on "));
335 | Serial.println(ARDUINO_BOARD);
336 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
337 | Serial.print(F("CPU Frequency = "));
338 | Serial.print(F_CPU / 1000000);
339 | Serial.println(F(" MHz"));
340 |
341 | // Interval in microsecs
342 | if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_US, TimerHandler))
343 | {
344 | startMillis = millis();
345 | Serial.print(F("Starting ITimer OK, millis() = "));
346 | Serial.println(startMillis);
347 | }
348 | else
349 | Serial.println(F("Can't set ITimer. Select another freq. or timer"));
350 |
351 | startMillis = millis();
352 |
353 | // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary
354 | // You can use up to 16 timer for each ISR_Timer
355 | for (uint16_t i = 0; i < NUMBER_ISR_TIMERS; i++)
356 | {
357 | #if USE_COMPLEX_STRUCT
358 | curISRTimerData[i].previousMillis = startMillis;
359 | ISR_Timer.setInterval(curISRTimerData[i].TimerInterval, curISRTimerData[i].irqCallbackFunc);
360 | #else
361 | previousMillis[i] = millis();
362 | ISR_Timer.setInterval(TimerInterval[i], irqCallbackFunc[i]);
363 | #endif
364 | }
365 |
366 | // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary.
367 | simpleTimer.setInterval(SIMPLE_TIMER_MS, simpleTimerDoingSomething2s);
368 | }
369 |
370 | #define BLOCKING_TIME_MS 10000L
371 |
372 | void loop()
373 | {
374 | // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer
375 | // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer
376 | // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS)
377 | // While that of ISR_Timer is still prefect.
378 | delay(BLOCKING_TIME_MS);
379 |
380 | // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary
381 | // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer.
382 | simpleTimer.run();
383 | }
384 |
--------------------------------------------------------------------------------
/examples/RPM_Measure/RPM_Measure.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | RPM_Measure.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 |
23 | Based on SimpleTimer - A timer library for Arduino.
24 | Author: mromani@ottotecnica.com
25 | Copyright (c) 2010 OTTOTECNICA Italy
26 | *****************************************************************************************************************************/
27 | /*
28 | Notes:
29 | Special design is necessary to share data between interrupt code and the rest of your program.
30 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
31 | variable can not spontaneously change. Because your function may change variables while your program is using them,
32 | the compiler needs this hint. But volatile alone is often not enough.
33 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
34 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
35 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
36 | or the entire sequence of your code which accesses the data.
37 |
38 | RPM Measuring uses high frequency hardware timer 1000Hz == 1ms) to measure the time from of one rotation, in ms
39 | then convert to RPM. One rotation is detected by reading the state of a magnetic REED SW or IR LED Sensor
40 | Asssuming LOW is active.
41 | For example: Max speed is 600RPM => 10 RPS => minimum 100ms a rotation. We'll use 80ms for debouncing
42 | If the time between active state is less than 8ms => consider noise.
43 | RPM = 60000 / (rotation time in ms)
44 |
45 | You can also use interrupt to detect whenever the SW is active, set a flag then use timer to count the time between active state
46 | */
47 |
48 | #if !defined(ESP32)
49 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
50 | #elif ( defined(ARDUINO_ESP32S3_DEV) || defined(ARDUINO_ESP32_S3_BOX) || defined(ARDUINO_TINYS3) || \
51 | defined(ARDUINO_PROS3) || defined(ARDUINO_FEATHERS3) )
52 | //#error ESP32_S3 is not supported yet
53 | #endif
54 |
55 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
56 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
57 | #define _TIMERINTERRUPT_LOGLEVEL_ 0
58 |
59 | #include "ESP32_New_TimerInterrupt.h"
60 |
61 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
62 | // Don't use PIN_D2 with ESP32_C3 (crash)
63 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
64 | #define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32
65 | #define PIN_D4 4 // Pin D4 mapped to pin GPIO4/ADC10/TOUCH0 of ESP32
66 |
67 | unsigned int SWPin = PIN_D4;
68 |
69 | #define TIMER0_INTERVAL_MS 1
70 | #define DEBOUNCING_INTERVAL_MS 80
71 |
72 | #define LOCAL_DEBUG 1
73 |
74 | // Init ESP32 timer 0
75 | ESP32Timer ITimer0(0);
76 |
77 | volatile unsigned long rotationTime = 0;
78 |
79 | // Not using float => using RPM = 100 * real RPM
80 | float RPM = 0;
81 | float avgRPM = 0;
82 | //uint32_t RPM = 0;
83 | //uint32_t avgRPM = 0;
84 |
85 | volatile int debounceCounter;
86 |
87 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
88 | // and you can't use float calculation inside ISR
89 | // Only OK in core v1.0.6-
90 | bool IRAM_ATTR TimerHandler0(void * timerNo)
91 | {
92 | if ( !digitalRead(SWPin) && (debounceCounter >= DEBOUNCING_INTERVAL_MS / TIMER0_INTERVAL_MS ) )
93 | {
94 | //min time between pulses has passed
95 | // Using float calculation / vars in core v2.0.0 and core v2.0.1 will cause crash
96 | // Not using float => using RPM = 100 * real RPM
97 | RPM = ( 6000000 / ( rotationTime * TIMER0_INTERVAL_MS ) );
98 |
99 | avgRPM = ( 2 * avgRPM + RPM) / 3;
100 |
101 | rotationTime = 0;
102 | debounceCounter = 0;
103 | }
104 | else
105 | {
106 | debounceCounter++;
107 | }
108 |
109 | //if (rotationTime >= 5000)
110 | if (rotationTime >= 1000)
111 | {
112 | // If idle, set RPM to 0, don't increase rotationTime
113 | RPM = 0;
114 |
115 | avgRPM = ( avgRPM + 3 * RPM) / 4;
116 |
117 | rotationTime = 0;
118 | }
119 | else
120 | {
121 | rotationTime++;
122 | }
123 |
124 | return true;
125 | }
126 |
127 | void setup()
128 | {
129 | pinMode(SWPin, INPUT_PULLUP);
130 |
131 | Serial.begin(115200);
132 |
133 | while (!Serial && millis() < 5000);
134 |
135 | delay(500);
136 |
137 | Serial.print(F("\nStarting RPM_Measure on "));
138 | Serial.println(ARDUINO_BOARD);
139 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
140 | Serial.print(F("CPU Frequency = "));
141 | Serial.print(F_CPU / 1000000);
142 | Serial.println(F(" MHz"));
143 |
144 | // Using ESP32 => 80 / 160 / 240MHz CPU clock ,
145 | // For 64-bit timer counter
146 | // For 16-bit timer prescaler up to 1024
147 |
148 | // Interval in microsecs
149 | if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
150 | {
151 | Serial.print(F("Starting ITimer0 OK, millis() = "));
152 | Serial.println(millis());
153 | }
154 | else
155 | Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
156 |
157 | Serial.flush();
158 | }
159 |
160 | void loop()
161 | {
162 | if (avgRPM > 0)
163 | {
164 | Serial.print(F("RPM = "));
165 | Serial.print((float) RPM / 100.f);
166 | Serial.print(F(", avgRPM = "));
167 | Serial.println((float) avgRPM / 100.f);
168 | }
169 |
170 | delay(1000);
171 | }
172 |
--------------------------------------------------------------------------------
/examples/SwitchDebounce/SwitchDebounce.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | SwitchDebounce.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 | *****************************************************************************************************************************/
23 | /*
24 | Notes:
25 | Special design is necessary to share data between interrupt code and the rest of your program.
26 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
27 | variable can not spontaneously change. Because your function may change variables while your program is using them,
28 | the compiler needs this hint. But volatile alone is often not enough.
29 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
30 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
31 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
32 | or the entire sequence of your code which accesses the data.
33 |
34 | Switch Debouncing uses high frequency hardware timer 50Hz == 20ms) to measure the time from the SW is pressed,
35 | debouncing time is 100ms => SW is considered pressed if timer count is > 5, then call / flag SW is pressed
36 | When the SW is released, timer will count (debounce) until more than 50ms until consider SW is released.
37 | We can set to flag or call a function whenever SW is pressed more than certain predetermined time, even before
38 | SW is released.
39 | */
40 |
41 | #if !defined( ESP32 )
42 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
43 | #endif
44 |
45 | //These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
46 | // Don't define TIMER_INTERRUPT_DEBUG > 2. Only for special ISR debugging only. Can hang the system.
47 | #define TIMER_INTERRUPT_DEBUG 1
48 |
49 | #include "ESP32_New_TimerInterrupt.h"
50 |
51 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
52 | // Don't use PIN_D2 with ESP32_C3 (crash)
53 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
54 | #define PIN_D4 4 // Pin D4 mapped to pin GPIO4/ADC10/TOUCH0 of ESP32
55 |
56 | unsigned int SWPin = PIN_D4;
57 |
58 | #define TIMER1_INTERVAL_MS 20
59 | #define DEBOUNCING_INTERVAL_MS 100
60 | #define LONG_PRESS_INTERVAL_MS 5000
61 |
62 | // Init ESP32 timer 1
63 | ESP32Timer ITimer1(1);
64 |
65 | volatile bool SWPressed = false;
66 | volatile bool SWLongPressed = false;
67 |
68 | volatile uint64_t lastSWPressedTime = 0;
69 | volatile uint64_t lastSWLongPressedTime = 0;
70 |
71 | volatile bool lastSWPressedNoted = true;
72 | volatile bool lastSWLongPressedNoted = true;
73 |
74 | void IRAM_ATTR lastSWPressedMS()
75 | {
76 | lastSWPressedTime = millis();
77 | lastSWPressedNoted = false;
78 | }
79 |
80 | void IRAM_ATTR lastSWLongPressedMS()
81 | {
82 | lastSWLongPressedTime = millis();
83 | lastSWLongPressedNoted = false;
84 | }
85 |
86 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
87 | // and you can't use float calculation inside ISR
88 | // Only OK in core v1.0.6-
89 | bool IRAM_ATTR TimerHandler1(void * timerNo)
90 | {
91 | static unsigned int debounceCountSWPressed = 0;
92 | static unsigned int debounceCountSWReleased = 0;
93 |
94 | if ( (!digitalRead(SWPin)) )
95 | {
96 | // Start debouncing counting debounceCountSWPressed and clear debounceCountSWReleased
97 | debounceCountSWReleased = 0;
98 |
99 | if (++debounceCountSWPressed >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS)
100 | {
101 | // Call and flag SWPressed
102 | if (!SWPressed)
103 | {
104 | SWPressed = true;
105 | // Do something for SWPressed here in ISR
106 | // But it's better to use outside software timer to do your job instead of inside ISR
107 | //Your_Response_To_Press();
108 | lastSWPressedMS();
109 | }
110 |
111 | if (debounceCountSWPressed >= LONG_PRESS_INTERVAL_MS / TIMER1_INTERVAL_MS)
112 | {
113 | // Call and flag SWLongPressed
114 | if (!SWLongPressed)
115 | {
116 | SWLongPressed = true;
117 | // Do something for SWLongPressed here in ISR
118 | // But it's better to use outside software timer to do your job instead of inside ISR
119 | //Your_Response_To_Long_Press();
120 | lastSWLongPressedMS();
121 | }
122 | }
123 | }
124 | }
125 | else
126 | {
127 | // Start debouncing counting debounceCountSWReleased and clear debounceCountSWPressed
128 | if ( SWPressed && (++debounceCountSWReleased >= DEBOUNCING_INTERVAL_MS / TIMER1_INTERVAL_MS))
129 | {
130 | SWPressed = false;
131 | SWLongPressed = false;
132 |
133 | // Do something for !SWPressed here in ISR
134 | // But it's better to use outside software timer to do your job instead of inside ISR
135 | //Your_Response_To_Release();
136 |
137 | // Call and flag SWPressed
138 | debounceCountSWPressed = 0;
139 | }
140 | }
141 |
142 | return true;
143 | }
144 |
145 | void setup()
146 | {
147 | pinMode(SWPin, INPUT_PULLUP);
148 |
149 | Serial.begin(115200);
150 |
151 | while (!Serial && millis() < 5000);
152 |
153 | delay(500);
154 |
155 | Serial.print(F("\nStarting SwitchDebounce on "));
156 | Serial.println(ARDUINO_BOARD);
157 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
158 | Serial.print(F("CPU Frequency = "));
159 | Serial.print(F_CPU / 1000000);
160 | Serial.println(F(" MHz"));
161 |
162 | // Using ESP32 => 80 / 160 / 240MHz CPU clock ,
163 | // For 64-bit timer counter
164 | // For 16-bit timer prescaler up to 1024
165 |
166 | // Interval in microsecs
167 | if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
168 | {
169 | Serial.print(F("Starting ITimer1 OK, millis() = "));
170 | Serial.println(millis());
171 | }
172 | else
173 | Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
174 | }
175 |
176 | void loop()
177 | {
178 | if (!lastSWPressedNoted)
179 | {
180 | lastSWPressedNoted = true;
181 | Serial.print(F("lastSWPressed @ millis() = "));
182 | Serial.println(lastSWPressedTime);
183 | }
184 |
185 | if (!lastSWLongPressedNoted)
186 | {
187 | lastSWLongPressedNoted = true;
188 | Serial.print(F("lastSWLongPressed @ millis() = "));
189 | Serial.println(lastSWLongPressedTime);
190 | }
191 |
192 | delay(500);
193 | }
194 |
--------------------------------------------------------------------------------
/examples/TimerInterruptTest/TimerInterruptTest.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | TimerInterruptTest.ino
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 | *****************************************************************************************************************************/
23 | /*
24 | Notes:
25 | Special design is necessary to share data between interrupt code and the rest of your program.
26 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
27 | variable can not spontaneously change. Because your function may change variables while your program is using them,
28 | the compiler needs this hint. But volatile alone is often not enough.
29 | When accessing shared variables, usually interrupts must be disabled. Even with volatile,
30 | if the interrupt changes a multi-byte variable between a sequence of instructions, it can be read incorrectly.
31 | If your data is multiple variables, such as an array and a count, usually interrupts need to be disabled
32 | or the entire sequence of your code which accesses the data.
33 | */
34 |
35 | #if !defined( ESP32 )
36 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
37 | #endif
38 |
39 | // These define's must be placed at the beginning before #include "ESP32_New_TimerInterrupt.h"
40 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
41 | #define _TIMERINTERRUPT_LOGLEVEL_ 4
42 |
43 | #include "ESP32_New_TimerInterrupt.h"
44 |
45 | // Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
46 | // Don't use PIN_D2 with ESP32_C3 (crash)
47 | #define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
48 | #define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32
49 |
50 | // With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
51 | // and you can't use float calculation inside ISR
52 | // Only OK in core v1.0.6-
53 | bool IRAM_ATTR TimerHandler0(void * timerNo)
54 | {
55 | static bool toggle0 = false;
56 |
57 | //timer interrupt toggles pin PIN_D19
58 | digitalWrite(PIN_D19, toggle0);
59 | toggle0 = !toggle0;
60 |
61 | return true;
62 | }
63 |
64 | bool IRAM_ATTR TimerHandler1(void * timerNo)
65 | {
66 | static bool toggle1 = false;
67 |
68 | //timer interrupt toggles outputPin
69 | digitalWrite(PIN_D3, toggle1);
70 | toggle1 = !toggle1;
71 |
72 | return true;
73 | }
74 |
75 | #define TIMER0_INTERVAL_MS 1000
76 | #define TIMER0_DURATION_MS 5000
77 |
78 | #define TIMER1_INTERVAL_MS 3000
79 | #define TIMER1_DURATION_MS 15000
80 |
81 | // Init ESP32 timer 0 and 1
82 | ESP32Timer ITimer0(0);
83 | ESP32Timer ITimer1(1);
84 |
85 | void setup()
86 | {
87 | pinMode(PIN_D19, OUTPUT);
88 | pinMode(PIN_D3, OUTPUT);
89 |
90 | Serial.begin(115200);
91 |
92 | while (!Serial && millis() < 5000);
93 |
94 | delay(500);
95 |
96 | Serial.print(F("\nStarting TimerInterruptTest on "));
97 | Serial.println(ARDUINO_BOARD);
98 | Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
99 | Serial.print(F("CPU Frequency = "));
100 | Serial.print(F_CPU / 1000000);
101 | Serial.println(F(" MHz"));
102 |
103 | // Using ESP32 => 80 / 160 / 240MHz CPU clock ,
104 | // For 64-bit timer counter
105 | // For 16-bit timer prescaler up to 1024
106 |
107 | // Interval in microsecs
108 | if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0))
109 | {
110 | Serial.print(F("Starting ITimer0 OK, millis() = "));
111 | Serial.println(millis());
112 | }
113 | else
114 | Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
115 |
116 | // Interval in microsecs
117 | if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
118 | {
119 | Serial.print(F("Starting ITimer1 OK, millis() = "));
120 | Serial.println(millis());
121 | }
122 | else
123 | Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
124 |
125 | Serial.flush();
126 | }
127 |
128 | void loop()
129 | {
130 | static unsigned long lastTimer0 = 0;
131 | static unsigned long lastTimer1 = 0;
132 |
133 | static bool timer0Stopped = false;
134 | static bool timer1Stopped = false;
135 |
136 | if (millis() - lastTimer0 > TIMER0_DURATION_MS)
137 | {
138 | lastTimer0 = millis();
139 |
140 | if (timer0Stopped)
141 | {
142 | Serial.print(F("Start ITimer0, millis() = "));
143 | Serial.println(millis());
144 | ITimer0.restartTimer();
145 | }
146 | else
147 | {
148 | Serial.print(F("Stop ITimer0, millis() = "));
149 | Serial.println(millis());
150 | ITimer0.stopTimer();
151 | }
152 |
153 | timer0Stopped = !timer0Stopped;
154 | }
155 |
156 | if (millis() - lastTimer1 > TIMER1_DURATION_MS)
157 | {
158 | lastTimer1 = millis();
159 |
160 | if (timer1Stopped)
161 | {
162 | Serial.print(F("Start ITimer1, millis() = "));
163 | Serial.println(millis());
164 | ITimer1.restartTimer();
165 | }
166 | else
167 | {
168 | Serial.print(F("Stop ITimer1, millis() = "));
169 | Serial.println(millis());
170 | ITimer1.stopTimer();
171 | }
172 |
173 | timer1Stopped = !timer1Stopped;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | #######################################
2 | # Datatypes (KEYWORD1)
3 | #######################################
4 |
5 | ESP32TimerInterrupt KEYWORD1
6 | ESP32Timer KEYWORD1
7 | ESP32_ISRTimer KEYWORD1
8 |
9 | #######################################
10 | # Methods and Functions (KEYWORD2)
11 | #######################################
12 |
13 | setFrequency KEYWORD2
14 | setInterval KEYWORD2
15 | attachInterrupt KEYWORD2
16 | attachInterruptInterval KEYWORD2
17 | detachInterrupt KEYWORD2
18 | disableTimer KEYWORD2
19 | reattachInterrupt KEYWORD2
20 | enableTimer KEYWORD2
21 | stopTimer KEYWORD2
22 | restartTimer KEYWORD2
23 | init KEYWORD2
24 | run KEYWORD2
25 | setTimeout KEYWORD2
26 | setTimer KEYWORD2
27 | changeInterval KEYWORD2
28 | deleteTimer KEYWORD2
29 | restartTimer KEYWORD2
30 | isEnabled KEYWORD2
31 | enable KEYWORD2
32 | disable KEYWORD2
33 | enableAll KEYWORD2
34 | disableAll KEYWORD2
35 | toggle KEYWORD2
36 | getNumTimers KEYWORD2
37 | getNumAvailableTimers KEYWORD2
38 |
39 | #######################################
40 | # Constants (LITERAL1)
41 | #######################################
42 |
43 | ESP32_NEW_TIMERINTERRUPT_VERSION LITERAL1
44 | ESP32_NEW_TIMERINTERRUPT_VERSION_MAJOR LITERAL1
45 | ESP32_NEW_TIMERINTERRUPT_VERSION_MINOR LITERAL1
46 | ESP32_NEW_TIMERINTERRUPT_VERSION_PATCH LITERAL1
47 | ESP32_NEW_TIMERINTERRUPT_VERSION_INT LITERAL1
48 |
49 |
--------------------------------------------------------------------------------
/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ESP32_New_TimerInterrupt",
3 | "version": "1.5.0",
4 | "keywords": "timing, device, control, timer, interrupt, timer-interrupt, hardware, isr, isr-based, hardware-timer, isr-timer, isr-based-timer, mission-critical, accuracy, precise, non-blocking, esp32, esp32-s2, esp32-c3, esp32-s3",
5 | "description": "This library enables you to use Interrupt from Hardware Timers on an ESP32, ESP32_S2, ESP32_S3 or ESP32_C3-based board. 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. 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.",
6 | "authors":
7 | {
8 | "name": "Khoi Hoang",
9 | "url": "https://github.com/khoih-prog",
10 | "maintainer": true
11 | },
12 | "repository":
13 | {
14 | "type": "git",
15 | "url": "https://github.com/khoih-prog/ESP32_New_TimerInterrupt"
16 | },
17 | "homepage": "https://github.com/khoih-prog/ESP32_New_TimerInterrupt",
18 | "export": {
19 | "exclude": [
20 | "linux",
21 | "extras",
22 | "tests"
23 | ]
24 | },
25 | "license": "MIT",
26 | "frameworks": "*",
27 | "platforms": "espressif32",
28 | "examples": "examples/*/*/*.ino",
29 | "headers": ["ESP32_New_TimerInterrupt.h", "ESP32_New_ISR_Timer.hpp", "ESP32_New_ISR_Timer.h"]
30 | }
31 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=ESP32_New_TimerInterrupt
2 | version=1.5.0
3 | author=Khoi Hoang
4 | maintainer=Khoi Hoang
5 | sentence=This library enables you to use Interrupt from Hardware Timers on an ESP32, ESP32_S2, ESP32_S3 or ESP32_C3-based board
6 | paragraph=These ESP32, ESP32_S2, ESP32_S3 or ESP32_C3 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 is 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 are 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.
7 | category=Device Control
8 | url=https://github.com/khoih-prog/ESP32_New_TimerInterrupt
9 | architectures=esp32
10 | repository=https://github.com/khoih-prog/ESP32_New_TimerInterrupt
11 | license=MIT
12 | includes=ESP32_New_TimerInterrupt.h,ESP32_New_ISR_Timer.hpp,ESP32_New_ISR_Timer.h
13 |
--------------------------------------------------------------------------------
/platformio/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [platformio]
12 | ; ============================================================
13 | ; chose environment:
14 | ; ESP32
15 | ; esp32s2
16 | ; esp32s3
17 | ; esp32c3
18 |
19 | ; ============================================================
20 | default_envs = ESP32
21 |
22 | [env]
23 | ; ============================================================
24 | ; Serial configuration
25 | ; choose upload speed, serial-monitor speed
26 | ; ============================================================
27 | upload_speed = 921600
28 | ;upload_port = COM11
29 | ;monitor_speed = 9600
30 | ;monitor_port = COM11
31 |
32 | ; Checks for the compatibility with frameworks and dev/platforms
33 | lib_compat_mode = strict
34 | lib_ldf_mode = chain+
35 | ;lib_ldf_mode = deep+
36 |
37 | lib_deps =
38 |
39 | build_flags =
40 | ; set your debug output (default=Serial)
41 | -D DEBUG_ESP_PORT=Serial
42 | ; comment the following line to enable WiFi debugging
43 | -D NDEBUG
44 |
45 |
46 | ; ============================================================
47 | ; ============================================================
48 |
49 | [env:ESP32]
50 | platform = espressif32
51 | framework = arduino
52 |
53 | ; ============================================================
54 | ; Board configuration
55 | ; choose your board by uncommenting one of the following lines
56 | ; ============================================================
57 | ;board = esp32cam
58 | ;board = alksesp32
59 | ;board = featheresp32
60 | ;board = espea32
61 | ;board = bpi-bit
62 | ;board = d-duino-32
63 | board = esp32doit-devkit-v1
64 | ;board = pocket_32
65 | ;board = fm-devkit
66 | ;board = pico32
67 | ;board = esp32-evb
68 | ;board = esp32-gateway
69 | ;board = esp32-pro
70 | ;board = esp32-poe
71 | ;board = oroca_edubot
72 | ;board = onehorse32dev
73 | ;board = lopy
74 | ;board = lopy4
75 | ;board = wesp32
76 | ;board = esp32thing
77 | ;board = sparkfun_lora_gateway_1-channel
78 | ;board = ttgo-lora32-v1
79 | ;board = ttgo-t-beam
80 | ;board = turta_iot_node
81 | ;board = lolin_d32
82 | ;board = lolin_d32_pro
83 | ;board = lolin32
84 | ;board = wemosbat
85 | ;board = widora-air
86 | ;board = xinabox_cw02
87 | ;board = iotbusio
88 | ;board = iotbusproteus
89 | ;board = nina_w10
90 |
91 | ; ============================================================
92 |
93 | [env:esp32s2]
94 | platform = espressif32
95 | framework = arduino
96 |
97 | ; toolchain download links see
98 | ; refer "name": "xtensa-esp32s2-elf-gcc","version": "gcc8_4_0-esp-2021r1" section of
99 | ; https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
100 | ; e.g. Windows: https://github.com/espressif/crosstool-NG/releases/download/esp-2021r1/xtensa-esp32s2-elf-gcc8_4_0-esp-2021r1-win32.zip
101 | platform_packages =
102 | toolchain-xtensa32s2@file://C:\Users\Max\Downloads\xtensa-esp32s2-elf
103 | framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git#a4118ea88987c28aac3a49bcb9cc5d6c0acc6f3f
104 | platformio/tool-esptoolpy @ ~1.30100
105 | framework = arduino
106 | board = esp32dev
107 | board_build.mcu = esp32s2
108 | board_build.partitions = huge_app.csv
109 | board_build.variant = esp32s2
110 | board_build.f_cpu = 240000000L
111 | board_build.f_flash = 80000000L
112 | board_build.flash_mode = qio
113 | board_build.arduino.ldscript = esp32s2_out.ld
114 | build_unflags =
115 | -DARDUINO_ESP32_DEV
116 | -DARDUINO_VARIANT="esp32"
117 | build_flags =
118 | -DARDUINO_ESP32S2_DEV
119 | -DARDUINO_VARIANT="esp32s2"
120 |
121 | ; ============================================================
122 |
123 | [env:esp32s3]
124 | platform = espressif32
125 | framework = arduino
126 |
127 | board_build.mcu = esp32s3
128 | board_build.partitions = huge_app.csv
129 | board_build.variant = esp32s3
130 | board_build.f_cpu = 240000000L
131 | board_build.f_flash = 80000000L
132 | board_build.flash_mode = qio
133 | board_build.arduino.ldscript = esp32s3_out.ld
134 | build_unflags =
135 | -DARDUINO_ESP32_DEV
136 | -DARDUINO_VARIANT="esp32"
137 | build_flags =
138 | -DARDUINO_ESP32S3_DEV
139 | -DARDUINO_VARIANT="esp32s3"
140 |
141 | ; ============================================================
142 |
143 | [env:esp32c3]
144 | platform = espressif32
145 | framework = arduino
146 |
147 | board_build.mcu = esp32c3
148 | board_build.partitions = huge_app.csv
149 | board_build.variant = esp32c3
150 | board_build.f_cpu = 160000000L
151 | board_build.f_flash = 80000000L
152 | board_build.flash_mode = qio
153 | board_build.arduino.ldscript = esp32c3_out.ld
154 | build_unflags =
155 | -DARDUINO_ESP32_DEV
156 | -DARDUINO_VARIANT="esp32"
157 | build_flags =
158 | -DARDUINO_ESP32S3_DEV
159 | -DARDUINO_VARIANT="esp32c3"
160 |
161 | ; ============================================================
162 |
--------------------------------------------------------------------------------
/src/ESP32_New_ISR_Timer-Impl.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | ESP32_New_ISR_Timer-Impl.h
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 |
23 | Based on SimpleTimer - A timer library for Arduino.
24 | Author: mromani@ottotecnica.com
25 | Copyright (c) 2010 OTTOTECNICA Italy
26 |
27 | Based on BlynkTimer.h
28 | Author: Volodymyr Shymanskyy
29 |
30 | Version: 1.5.0
31 |
32 | Version Modified By Date Comments
33 | ------- ----------- ---------- -----------
34 | 1.0.0 K Hoang 15/08/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
35 | 1.0.1 K.Hoang 14/11/2021 Avoid using float and D1 in examples due to issue with core v2.0.0 and v2.0.1
36 | 1.1.0 K.Hoang 18/01/2022 Fix `multiple-definitions` linker error.
37 | 1.2.0 K Hoang 12/02/2022 Add support to new ESP32-S3
38 | 1.2.1 K Hoang 16/06/2022 Add support to new Adafruit boards
39 | 1.3.0 K Hoang 03/08/2022 Suppress errors and warnings for new ESP32 core
40 | 1.4.0 K Hoang 11/08/2022 Add support and suppress warnings for ESP32_C3, ESP32_S2 and ESP32_S3 boards
41 | 1.5.0 K Hoang 16/11/2022 Fix doubled time for ESP32_C3, ESP32_S2 and ESP32_S3
42 | *****************************************************************************************************************************/
43 |
44 | #pragma once
45 |
46 | #ifndef ISR_TIMER_GENERIC_IMPL_H
47 | #define ISR_TIMER_GENERIC_IMPL_H
48 |
49 | #include
50 |
51 | ESP32_ISR_Timer::ESP32_ISR_Timer()
52 | : numTimers (-1)
53 | {
54 | }
55 |
56 | void ESP32_ISR_Timer::init()
57 | {
58 | unsigned long current_millis = millis(); //elapsed();
59 |
60 | for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
61 | {
62 | memset((void*) &timer[i], 0, sizeof (timer_t));
63 | timer[i].prev_millis = current_millis;
64 | }
65 |
66 | numTimers = 0;
67 |
68 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
69 | timerMux = portMUX_INITIALIZER_UNLOCKED;
70 | }
71 |
72 | void IRAM_ATTR ESP32_ISR_Timer::run()
73 | {
74 | uint8_t i;
75 | unsigned long current_millis;
76 |
77 | // get current time
78 | current_millis = millis(); //elapsed();
79 |
80 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
81 | portENTER_CRITICAL_ISR(&timerMux);
82 |
83 | for (i = 0; i < MAX_NUMBER_TIMERS; i++)
84 | {
85 |
86 | timer[i].toBeCalled = TIMER_DEFCALL_DONTRUN;
87 |
88 | // no callback == no timer, i.e. jump over empty slots
89 | if (timer[i].callback != NULL)
90 | {
91 |
92 | // is it time to process this timer ?
93 | // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592
94 |
95 | if ((current_millis - timer[i].prev_millis) >= timer[i].delay)
96 | {
97 | unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay;
98 |
99 | // update time
100 | timer[i].prev_millis += timer[i].delay * skipTimes;
101 |
102 | // check if the timer callback has to be executed
103 | if (timer[i].enabled)
104 | {
105 |
106 | // "run forever" timers must always be executed
107 | if (timer[i].maxNumRuns == TIMER_RUN_FOREVER)
108 | {
109 | timer[i].toBeCalled = TIMER_DEFCALL_RUNONLY;
110 | }
111 | // other timers get executed the specified number of times
112 | else if (timer[i].numRuns < timer[i].maxNumRuns)
113 | {
114 | timer[i].toBeCalled = TIMER_DEFCALL_RUNONLY;
115 | timer[i].numRuns++;
116 |
117 | // after the last run, delete the timer
118 | if (timer[i].numRuns >= timer[i].maxNumRuns)
119 | {
120 | timer[i].toBeCalled = TIMER_DEFCALL_RUNANDDEL;
121 | }
122 | }
123 | }
124 | }
125 | }
126 | }
127 |
128 | for (i = 0; i < MAX_NUMBER_TIMERS; i++)
129 | {
130 | if (timer[i].toBeCalled == TIMER_DEFCALL_DONTRUN)
131 | continue;
132 |
133 | if (timer[i].hasParam)
134 | (*(timer_callback_p)timer[i].callback)(timer[i].param);
135 | else
136 | (*(timer_callback)timer[i].callback)();
137 |
138 | if (timer[i].toBeCalled == TIMER_DEFCALL_RUNANDDEL)
139 | deleteTimer(i);
140 | }
141 |
142 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
143 | portEXIT_CRITICAL_ISR(&timerMux);
144 |
145 | }
146 |
147 |
148 | // find the first available slot
149 | // return -1 if none found
150 | int ESP32_ISR_Timer::findFirstFreeSlot()
151 | {
152 | // all slots are used
153 | if (numTimers >= MAX_NUMBER_TIMERS)
154 | {
155 | return -1;
156 | }
157 |
158 | // return the first slot with no callback (i.e. free)
159 | for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
160 | {
161 | if (timer[i].callback == NULL)
162 | {
163 | return i;
164 | }
165 | }
166 |
167 | // no free slots found
168 | return -1;
169 | }
170 |
171 |
172 | int ESP32_ISR_Timer::setupTimer(const unsigned long& delay, void* callback, void* param, bool hasParam,
173 | const uint32_t& numRuns)
174 | {
175 | int freeTimer;
176 |
177 | if (numTimers < 0)
178 | {
179 | init();
180 | }
181 |
182 | freeTimer = findFirstFreeSlot();
183 |
184 | if (freeTimer < 0)
185 | {
186 | return -1;
187 | }
188 |
189 | if (callback == NULL)
190 | {
191 | return -1;
192 | }
193 |
194 | timer[freeTimer].delay = delay;
195 | timer[freeTimer].callback = callback;
196 | timer[freeTimer].param = param;
197 | timer[freeTimer].hasParam = hasParam;
198 | timer[freeTimer].maxNumRuns = numRuns;
199 | timer[freeTimer].enabled = true;
200 | timer[freeTimer].prev_millis = millis();
201 |
202 | numTimers++;
203 |
204 | return freeTimer;
205 | }
206 |
207 |
208 | int ESP32_ISR_Timer::setTimer(const unsigned long& delay, timer_callback callback, const uint32_t& numRuns)
209 | {
210 | return setupTimer(delay, (void *)callback, NULL, false, numRuns);
211 | }
212 |
213 | int ESP32_ISR_Timer::setTimer(const unsigned long& delay, timer_callback_p callback, void* param,
214 | const uint32_t& numRuns)
215 | {
216 | return setupTimer(delay, (void *)callback, param, true, numRuns);
217 | }
218 |
219 | int ESP32_ISR_Timer::setInterval(const unsigned long& delay, timer_callback callback)
220 | {
221 | return setupTimer(delay, (void *)callback, NULL, false, TIMER_RUN_FOREVER);
222 | }
223 |
224 | int ESP32_ISR_Timer::setInterval(const unsigned long& delay, timer_callback_p callback, void* param)
225 | {
226 | return setupTimer(delay, (void *)callback, param, true, TIMER_RUN_FOREVER);
227 | }
228 |
229 | int ESP32_ISR_Timer::setTimeout(const unsigned long& delay, timer_callback callback)
230 | {
231 | return setupTimer(delay, (void *)callback, NULL, false, TIMER_RUN_ONCE);
232 | }
233 |
234 | int ESP32_ISR_Timer::setTimeout(const unsigned long& delay, timer_callback_p callback, void* param)
235 | {
236 | return setupTimer(delay, (void *)callback, param, true, TIMER_RUN_ONCE);
237 | }
238 |
239 | bool IRAM_ATTR ESP32_ISR_Timer::changeInterval(const uint8_t& numTimer, const unsigned long& delay)
240 | {
241 | if (numTimer >= MAX_NUMBER_TIMERS)
242 | {
243 | return false;
244 | }
245 |
246 | // Updates interval of existing specified timer
247 | if (timer[numTimer].callback != NULL)
248 | {
249 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
250 | portENTER_CRITICAL(&timerMux);
251 |
252 | timer[numTimer].delay = delay;
253 | timer[numTimer].prev_millis = millis();
254 |
255 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
256 | portEXIT_CRITICAL(&timerMux);
257 |
258 | return true;
259 | }
260 |
261 | // false return for non-used numTimer, no callback
262 | return false;
263 | }
264 |
265 | void ESP32_ISR_Timer::deleteTimer(const uint8_t& timerId)
266 | {
267 | // nothing to delete if no timers are in use
268 | if ( (timerId >= MAX_NUMBER_TIMERS) || (numTimers == 0) )
269 | {
270 | return;
271 | }
272 |
273 | // don't decrease the number of timers if the specified slot is already empty
274 | if (timer[timerId].callback != NULL)
275 | {
276 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
277 | portENTER_CRITICAL(&timerMux);
278 |
279 | memset((void*) &timer[timerId], 0, sizeof (timer_t));
280 | timer[timerId].prev_millis = millis();
281 |
282 | // update number of timers
283 | numTimers--;
284 |
285 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
286 | portEXIT_CRITICAL(&timerMux);
287 |
288 | }
289 | }
290 |
291 | // function contributed by code@rowansimms.com
292 | void ESP32_ISR_Timer::restartTimer(const uint8_t& numTimer)
293 | {
294 | if (numTimer >= MAX_NUMBER_TIMERS)
295 | {
296 | return;
297 | }
298 |
299 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
300 | portENTER_CRITICAL(&timerMux);
301 |
302 | timer[numTimer].prev_millis = millis();
303 |
304 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
305 | portEXIT_CRITICAL(&timerMux);
306 | }
307 |
308 |
309 | bool ESP32_ISR_Timer::isEnabled(const uint8_t& numTimer)
310 | {
311 | if (numTimer >= MAX_NUMBER_TIMERS)
312 | {
313 | return false;
314 | }
315 |
316 | return timer[numTimer].enabled;
317 | }
318 |
319 |
320 | void ESP32_ISR_Timer::enable(const uint8_t& numTimer)
321 | {
322 | if (numTimer >= MAX_NUMBER_TIMERS)
323 | {
324 | return;
325 | }
326 |
327 | timer[numTimer].enabled = true;
328 | }
329 |
330 |
331 | void ESP32_ISR_Timer::disable(const uint8_t& numTimer)
332 | {
333 | if (numTimer >= MAX_NUMBER_TIMERS)
334 | {
335 | return;
336 | }
337 |
338 | timer[numTimer].enabled = false;
339 | }
340 |
341 | void ESP32_ISR_Timer::enableAll()
342 | {
343 | // Enable all timers with a callback assigned (used)
344 |
345 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
346 | portENTER_CRITICAL(&timerMux);
347 |
348 | for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
349 | {
350 | if (timer[i].callback != NULL && timer[i].numRuns == TIMER_RUN_FOREVER)
351 | {
352 | timer[i].enabled = true;
353 | }
354 | }
355 |
356 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
357 | portEXIT_CRITICAL(&timerMux);
358 | }
359 |
360 | void ESP32_ISR_Timer::disableAll()
361 | {
362 | // Disable all timers with a callback assigned (used)
363 |
364 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
365 | portENTER_CRITICAL(&timerMux);
366 |
367 | for (uint8_t i = 0; i < MAX_NUMBER_TIMERS; i++)
368 | {
369 | if (timer[i].callback != NULL && timer[i].numRuns == TIMER_RUN_FOREVER)
370 | {
371 | timer[i].enabled = false;
372 | }
373 | }
374 |
375 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
376 | portEXIT_CRITICAL(&timerMux);
377 |
378 | }
379 |
380 | void ESP32_ISR_Timer::toggle(const uint8_t& numTimer)
381 | {
382 | if (numTimer >= MAX_NUMBER_TIMERS)
383 | {
384 | return;
385 | }
386 |
387 | timer[numTimer].enabled = !timer[numTimer].enabled;
388 | }
389 |
390 |
391 | int8_t ESP32_ISR_Timer::getNumTimers()
392 | {
393 | return numTimers;
394 | }
395 |
396 | #endif // ISR_TIMER_GENERIC_IMPL_H
397 |
398 |
--------------------------------------------------------------------------------
/src/ESP32_New_ISR_Timer.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | ESP32_New_ISR_Timer.h
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 |
23 | Based on SimpleTimer - A timer library for Arduino.
24 | Author: mromani@ottotecnica.com
25 | Copyright (c) 2010 OTTOTECNICA Italy
26 |
27 | Based on BlynkTimer.h
28 | Author: Volodymyr Shymanskyy
29 |
30 | Version: 1.5.0
31 |
32 | Version Modified By Date Comments
33 | ------- ----------- ---------- -----------
34 | 1.0.0 K Hoang 15/08/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
35 | 1.0.1 K.Hoang 14/11/2021 Avoid using float and D1 in examples due to issue with core v2.0.0 and v2.0.1
36 | 1.1.0 K.Hoang 18/01/2022 Fix `multiple-definitions` linker error.
37 | 1.2.0 K Hoang 12/02/2022 Add support to new ESP32-S3
38 | 1.2.1 K Hoang 16/06/2022 Add support to new Adafruit boards
39 | 1.3.0 K Hoang 03/08/2022 Suppress errors and warnings for new ESP32 core
40 | 1.4.0 K Hoang 11/08/2022 Add support and suppress warnings for ESP32_C3, ESP32_S2 and ESP32_S3 boards
41 | 1.5.0 K Hoang 16/11/2022 Fix doubled time for ESP32_C3, ESP32_S2 and ESP32_S3
42 | *****************************************************************************************************************************/
43 |
44 | #pragma once
45 |
46 | #ifndef ISR_TIMER_GENERIC_H
47 | #define ISR_TIMER_GENERIC_H
48 |
49 | #include "ESP32_New_ISR_Timer.hpp"
50 | #include "ESP32_New_ISR_Timer-Impl.h"
51 |
52 |
53 | #endif // ISR_TIMER_GENERIC_H
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/ESP32_New_ISR_Timer.hpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | ESP32_New_ISR_Timer.hpp
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 |
23 | Based on SimpleTimer - A timer library for Arduino.
24 | Author: mromani@ottotecnica.com
25 | Copyright (c) 2010 OTTOTECNICA Italy
26 |
27 | Based on BlynkTimer.h
28 | Author: Volodymyr Shymanskyy
29 |
30 | Version: 1.5.0
31 |
32 | Version Modified By Date Comments
33 | ------- ----------- ---------- -----------
34 | 1.0.0 K Hoang 15/08/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
35 | 1.0.1 K.Hoang 14/11/2021 Avoid using float and D1 in examples due to issue with core v2.0.0 and v2.0.1
36 | 1.1.0 K.Hoang 18/01/2022 Fix `multiple-definitions` linker error.
37 | 1.2.0 K Hoang 12/02/2022 Add support to new ESP32-S3
38 | 1.2.1 K Hoang 16/06/2022 Add support to new Adafruit boards
39 | 1.3.0 K Hoang 03/08/2022 Suppress errors and warnings for new ESP32 core
40 | 1.4.0 K Hoang 11/08/2022 Add support and suppress warnings for ESP32_C3, ESP32_S2 and ESP32_S3 boards
41 | 1.5.0 K Hoang 16/11/2022 Fix doubled time for ESP32_C3, ESP32_S2 and ESP32_S3
42 | *****************************************************************************************************************************/
43 |
44 | #pragma once
45 |
46 | #ifndef ISR_TIMER_GENERIC_HPP
47 | #define ISR_TIMER_GENERIC_HPP
48 |
49 | #if !defined( ESP32 )
50 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
51 | #endif
52 |
53 | #ifndef ESP32_NEW_TIMERINTERRUPT_VERSION
54 | #define ESP32_NEW_TIMERINTERRUPT_VERSION "ESP32_New_TimerInterrupt v1.5.0"
55 |
56 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_MAJOR 1
57 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_MINOR 5
58 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_PATCH 0
59 |
60 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_INT 1005000
61 | #endif
62 |
63 | #include "TimerInterrupt_Generic_Debug.h"
64 |
65 | #define CONFIG_ESP32_APPTRACE_ENABLE
66 |
67 | #if 0
68 | #ifndef configMINIMAL_STACK_SIZE
69 | #define configMINIMAL_STACK_SIZE 2048
70 | #else
71 | #undef configMINIMAL_STACK_SIZE
72 | #define configMINIMAL_STACK_SIZE 2048
73 | #endif
74 | #endif
75 |
76 | #include
77 |
78 | #include
79 |
80 | #if defined(ARDUINO)
81 | #if ARDUINO >= 100
82 | #include
83 | #else
84 | #include
85 | #endif
86 | #endif
87 |
88 | #define ESP32_ISR_Timer ESP32_ISRTimer
89 |
90 | typedef void (*timer_callback)();
91 | typedef void (*timer_callback_p)(void *);
92 |
93 | class ESP32_ISR_Timer
94 | {
95 |
96 | public:
97 | // maximum number of timers
98 | #define MAX_NUMBER_TIMERS 16
99 | #define TIMER_RUN_FOREVER 0
100 | #define TIMER_RUN_ONCE 1
101 |
102 | // constructor
103 | ESP32_ISR_Timer();
104 |
105 | void init();
106 |
107 | // this function must be called inside loop()
108 | void IRAM_ATTR run();
109 |
110 | // Timer will call function 'callback' every 'delay' milliseconds forever
111 | // returns the timer number (numTimer) on success or
112 | // -1 on failure (callback == NULL) or no free timers
113 | int setInterval(const unsigned long& delay, timer_callback callback);
114 |
115 | // Timer will call function 'callback' with parameter 'param' every 'delay' milliseconds forever
116 | // returns the timer number (numTimer) on success or
117 | // -1 on failure (callback == NULL) or no free timers
118 | int setInterval(const unsigned long& delay, timer_callback_p callback, void* param);
119 |
120 | // Timer will call function 'callback' after 'delay' milliseconds one time
121 | // returns the timer number (numTimer) on success or
122 | // -1 on failure (callback == NULL) or no free timers
123 | int setTimeout(const unsigned long& delay, timer_callback callback);
124 |
125 | // Timer will call function 'callback' with parameter 'param' after 'delay' milliseconds one time
126 | // returns the timer number (numTimer) on success or
127 | // -1 on failure (callback == NULL) or no free timers
128 | int setTimeout(const unsigned long& delay, timer_callback_p callback, void* param);
129 |
130 | // Timer will call function 'callback' every 'delay' milliseconds 'numRuns' times
131 | // returns the timer number (numTimer) on success or
132 | // -1 on failure (callback == NULL) or no free timers
133 | int setTimer(const unsigned long& delay, timer_callback callback, const uint32_t& numRuns);
134 |
135 | // Timer will call function 'callback' with parameter 'param' every 'delay' milliseconds 'numRuns' times
136 | // returns the timer number (numTimer) on success or
137 | // -1 on failure (callback == NULL) or no free timers
138 | int setTimer(const unsigned long& delay, timer_callback_p callback, void* param, const uint32_t& numRuns);
139 |
140 | // updates interval of the specified timer
141 | bool changeInterval(const uint8_t& numTimer, const unsigned long& delay);
142 |
143 | // destroy the specified timer
144 | void deleteTimer(const uint8_t& numTimer);
145 |
146 | // restart the specified timer
147 | void restartTimer(const uint8_t& numTimer);
148 |
149 | // returns true if the specified timer is enabled
150 | bool isEnabled(const uint8_t& numTimer);
151 |
152 | // enables the specified timer
153 | void enable(const uint8_t& numTimer);
154 |
155 | // disables the specified timer
156 | void disable(const uint8_t& numTimer);
157 |
158 | // enables all timers
159 | void enableAll();
160 |
161 | // disables all timers
162 | void disableAll();
163 |
164 | // enables the specified timer if it's currently disabled, and vice-versa
165 | void toggle(const uint8_t& numTimer);
166 |
167 | // returns the number of used timers
168 | int8_t getNumTimers();
169 |
170 | // returns the number of available timers
171 | uint8_t getNumAvailableTimers() __attribute__((always_inline))
172 | {
173 | if (numTimers <= 0)
174 | return MAX_NUMBER_TIMERS;
175 | else
176 | return MAX_NUMBER_TIMERS - numTimers;
177 | };
178 |
179 | private:
180 | // deferred call constants
181 | #define TIMER_DEFCALL_DONTRUN 0 // don't call the callback function
182 | #define TIMER_DEFCALL_RUNONLY 1 // call the callback function but don't delete the timer
183 | #define TIMER_DEFCALL_RUNANDDEL 2 // call the callback function and delete the timer
184 |
185 | // low level function to initialize and enable a new timer
186 | // returns the timer number (numTimer) on success or
187 | // -1 on failure (f == NULL) or no free timers
188 | int setupTimer(const unsigned long& delay, void* callback, void* param, bool hasParam, const uint32_t& numRuns) ;
189 |
190 | // find the first available slot
191 | int findFirstFreeSlot();
192 |
193 | typedef struct
194 | {
195 | unsigned long prev_millis; // value returned by the millis() function in the previous run() call
196 | void* callback; // pointer to the callback function
197 | void* param; // function parameter
198 | bool hasParam; // true if callback takes a parameter
199 | unsigned long delay; // delay value
200 | uint32_t maxNumRuns; // number of runs to be executed
201 | uint32_t numRuns; // number of executed runs
202 | bool enabled; // true if enabled
203 | unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run()
204 | } timer_t;
205 |
206 | volatile timer_t timer[MAX_NUMBER_TIMERS];
207 |
208 | // actual number of timers in use (-1 means uninitialized)
209 | volatile int8_t numTimers;
210 |
211 | // ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during ISR
212 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
213 | };
214 |
215 | #endif // ISR_TIMER_GENERIC_HPP
216 |
217 |
218 |
--------------------------------------------------------------------------------
/src/ESP32_New_TimerInterrupt.h:
--------------------------------------------------------------------------------
1 |
2 | /****************************************************************************************************************************
3 | ESP32_New_TimerInterrupt.h
4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
5 | Written by Khoi Hoang
6 |
7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
8 | Licensed under MIT license
9 |
10 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
11 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
12 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
13 |
14 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
15 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
16 | the software. The value of the counter can be read by the software program.
17 |
18 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
19 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
20 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
21 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
22 | This important feature is absolutely necessary for mission-critical tasks.
23 |
24 | Based on SimpleTimer - A timer library for Arduino.
25 | Author: mromani@ottotecnica.com
26 | Copyright (c) 2010 OTTOTECNICA Italy
27 |
28 | Based on BlynkTimer.h
29 | Author: Volodymyr Shymanskyy
30 |
31 | Version: 1.5.0
32 |
33 | Version Modified By Date Comments
34 | ------- ----------- ---------- -----------
35 | 1.0.0 K Hoang 15/08/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
36 | 1.0.1 K.Hoang 14/11/2021 Avoid using float and D1 in examples due to issue with core v2.0.0 and v2.0.1
37 | 1.1.0 K.Hoang 18/01/2022 Fix `multiple-definitions` linker error.
38 | 1.2.0 K Hoang 12/02/2022 Add support to new ESP32-S3
39 | 1.2.1 K Hoang 16/06/2022 Add support to new Adafruit boards
40 | 1.3.0 K Hoang 03/08/2022 Suppress errors and warnings for new ESP32 core
41 | 1.4.0 K Hoang 11/08/2022 Add support and suppress warnings for ESP32_C3, ESP32_S2 and ESP32_S3 boards
42 | 1.5.0 K Hoang 16/11/2022 Fix doubled time for ESP32_C3, ESP32_S2 and ESP32_S3
43 | *****************************************************************************************************************************/
44 |
45 | #pragma once
46 |
47 | #ifndef ESP32_NEW_TIMERINTERRUPT_H
48 | #define ESP32_NEW_TIMERINTERRUPT_H
49 |
50 | ////////////////////////////////////////
51 |
52 | #if ( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \
53 | ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \
54 | ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM || ARDUINO_ADAFRUIT_QTPY_ESP32S2 || ARDUINO_ESP32S2_USB || \
55 | ARDUINO_FEATHERS2NEO || ARDUINO_TINYS2 || ARDUINO_RMP || ARDUINO_LOLIN_S2_MINI || ARDUINO_LOLIN_S2_PICO || \
56 | ARDUINO_ADAFRUIT_FEATHER_ESP32S2 || ARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT || ARDUINO_atmegazero_esp32s2 || \
57 | ARDUINO_DYM || ARDUINO_FRANZININHO_WIFI || ARDUINO_FRANZININHO_WIFI_MSC )
58 | #define USING_ESP32_S2_NEW_TIMERINTERRUPT true
59 |
60 | #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
61 | #warning USING_ESP32_S2_NEW_TIMERINTERRUPT
62 | #endif
63 |
64 | ////////////////////////////////////////
65 |
66 | #elif ( defined(ARDUINO_ESP32S3_DEV) || defined(ARDUINO_ESP32_S3_BOX) || defined(ARDUINO_TINYS3) || \
67 | defined(ARDUINO_PROS3) || defined(ARDUINO_FEATHERS3) || defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_NOPSRAM) || \
68 | defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM) || defined(ARDUINO_ESP32S3_CAM_LCD) || \
69 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3) || defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_TFT) || \
70 | defined(ARDUINO_ESP32_S3_USB_OTG) )
71 | #define USING_ESP32_S3_NEW_TIMERINTERRUPT true
72 |
73 | #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
74 | #warning USING_ESP32_S3_NEW_TIMERINTERRUPT
75 | #endif
76 |
77 | ////////////////////////////////////////
78 |
79 | #elif ( defined(ARDUINO_ESP32C3_DEV) || defined(ARDUINO_LOLIN_C3_MINI) || defined(ARDUINO_ADAFRUIT_QTPY_ESP32C3) || \
80 | defined(ARDUINO_AirM2M_CORE_ESP32C3) || defined(ARDUINO_XIAO_ESP32C3) )
81 | #define USING_ESP32_C3_NEW_TIMERINTERRUPT true
82 |
83 | #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
84 | #warning USING_ESP32_C3_NEW_TIMERINTERRUPT
85 | #endif
86 | #elif defined(ESP32)
87 | #define USING_ESP32_NEW_TIMERINTERRUPT true
88 |
89 | #if (_TIMERINTERRUPT_LOGLEVEL_ > 3)
90 | #warning USING_ESP32_NEW_TIMERINTERRUPT
91 | #endif
92 | #else
93 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
94 | #endif
95 |
96 | #ifndef ESP32_NEW_TIMERINTERRUPT_VERSION
97 | #define ESP32_NEW_TIMERINTERRUPT_VERSION "ESP32_New_TimerInterrupt v1.5.0"
98 |
99 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_MAJOR 1
100 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_MINOR 5
101 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_PATCH 0
102 |
103 | #define ESP32_NEW_TIMERINTERRUPT_VERSION_INT 1005000
104 | #endif
105 |
106 | #ifndef TIMER_INTERRUPT_DEBUG
107 | #define TIMER_INTERRUPT_DEBUG 0
108 | #endif
109 |
110 | #include "TimerInterrupt_Generic_Debug.h"
111 |
112 | #include
113 |
114 | /*
115 | //ESP32 core v1.0.6, hw_timer_t defined in esp32/tools/sdk/include/driver/driver/timer.h:
116 |
117 | #define TIMER_BASE_CLK (APB_CLK_FREQ) //Frequency of the clock on the input of the timer groups
118 |
119 |
120 | //@brief Selects a Timer-Group out of 2 available groups
121 |
122 | typedef enum
123 | {
124 | TIMER_GROUP_0 = 0, // Hw timer group 0
125 | TIMER_GROUP_1 = 1, // Hw timer group 1
126 | TIMER_GROUP_MAX,
127 | } timer_group_t;
128 |
129 |
130 | //@brief Select a hardware timer from timer groups
131 |
132 | typedef enum
133 | {
134 | TIMER_0 = 0, // Select timer0 of GROUPx
135 | TIMER_1 = 1, // Select timer1 of GROUPx
136 | TIMER_MAX,
137 | } timer_idx_t;
138 |
139 |
140 | //@brief Decides the direction of counter
141 |
142 | typedef enum
143 | {
144 | TIMER_COUNT_DOWN = 0, //Descending Count from cnt.high|cnt.low
145 | TIMER_COUNT_UP = 1, //Ascending Count from Zero
146 | TIMER_COUNT_MAX
147 | } timer_count_dir_t;
148 |
149 |
150 | //@brief Decides whether timer is on or paused
151 |
152 | typedef enum
153 | {
154 | TIMER_PAUSE = 0, //Pause timer counter
155 | TIMER_START = 1, //Start timer counter
156 | } timer_start_t;
157 |
158 |
159 | //@brief Decides whether to enable alarm mode
160 |
161 | typedef enum
162 | {
163 | TIMER_ALARM_DIS = 0, //Disable timer alarm
164 | TIMER_ALARM_EN = 1, //Enable timer alarm
165 | TIMER_ALARM_MAX
166 | } timer_alarm_t;
167 |
168 |
169 | //@brief Select interrupt type if running in alarm mode.
170 |
171 | typedef enum
172 | {
173 | TIMER_INTR_LEVEL = 0, //Interrupt mode: level mode
174 | //TIMER_INTR_EDGE = 1, //Interrupt mode: edge mode, Not supported Now
175 | TIMER_INTR_MAX
176 | } timer_intr_mode_t;
177 |
178 |
179 | //@brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
180 |
181 | typedef enum
182 | {
183 | TIMER_AUTORELOAD_DIS = 0, //Disable auto-reload: hardware will not load counter value after an alarm event
184 | TIMER_AUTORELOAD_EN = 1, //Enable auto-reload: hardware will load counter value after an alarm event
185 | TIMER_AUTORELOAD_MAX,
186 | } timer_autoreload_t;
187 |
188 |
189 | //@brief Data structure with timer's configuration settings
190 |
191 | typedef struct
192 | {
193 | bool alarm_en; //Timer alarm enable
194 | bool counter_en; //Counter enable
195 | timer_intr_mode_t intr_type; //Interrupt mode
196 | timer_count_dir_t counter_dir; //Counter direction
197 | bool auto_reload; //Timer auto-reload
198 | uint32_t divider; //Counter clock divider. The divider's range is from from 2 to 65536.
199 | } timer_config_t;
200 |
201 | */
202 |
203 | /*
204 | //ESP32 core v2.0.4, timer_config_t defined in tools/sdk/esp32/include/hal/include/hal/timer_types.h:
205 | #if SOC_TIMER_GROUP_SUPPORT_XTAL
206 | typedef enum {
207 | TIMER_SRC_CLK_APB = 0, // Select APB as the source clock
208 | TIMER_SRC_CLK_XTAL = 1, // Select XTAL as the source clock
209 | } timer_src_clk_t;
210 | #endif
211 | typedef struct {
212 | timer_alarm_t alarm_en; // Timer alarm enable
213 | timer_start_t counter_en; // Counter enable
214 | timer_intr_mode_t intr_type; // Interrupt mode
215 | timer_count_dir_t counter_dir; // Counter direction
216 | timer_autoreload_t auto_reload; // Timer auto-reload
217 | uint32_t divider; // Counter clock divider. The divider's range is from from 2 to 65536
218 | #if SOC_TIMER_GROUP_SUPPORT_XTAL
219 | timer_src_clk_t clk_src; // Use XTAL as source clock
220 | #endif
221 | } timer_config_t;
222 |
223 | */
224 |
225 | class ESP32TimerInterrupt;
226 |
227 | typedef ESP32TimerInterrupt ESP32Timer;
228 |
229 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
230 | #define MAX_ESP32_NUM_TIMERS 2
231 | #else
232 | #define MAX_ESP32_NUM_TIMERS 4
233 | #endif
234 |
235 | #define TIMER_DIVIDER 80 // Hardware timer clock divider
236 | // TIMER_BASE_CLK = APB_CLK_FREQ = Frequency of the clock on the input of the timer groups
237 | #define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
238 |
239 |
240 | // In esp32/1.0.6/tools/sdk/esp32s2/include/driver/include/driver/timer.h
241 | // typedef bool (*timer_isr_t)(void *);
242 | //esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *arg, int intr_alloc_flags);
243 | //esp_err_t timer_isr_callback_remove(timer_group_t group_num, timer_idx_t timer_num);
244 | //timer_deinit(timer_group_t group_num, timer_idx_t timer_num);
245 | //esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
246 | //esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
247 |
248 | typedef bool (*esp32_timer_callback) (void *);
249 |
250 | // For ESP32_C3, TIMER_MAX == 1
251 | // For ESP32, ESP32_S2 and ESP32_S3, TIMER_MAX == 2
252 |
253 | typedef struct
254 | {
255 | timer_idx_t timer_idx;
256 | timer_group_t timer_group;
257 | //int alarm_interval;
258 | //timer_autoreload_t auto_reload;
259 | } timer_info_t;
260 |
261 | // Warning: TIMER_SRC_CLK_XTAL only good for ESP32
262 | // Use TIMER_SRC_CLK_APB for ESP32_C3, ESP32_S2 and ESP32_S3
263 |
264 | class ESP32TimerInterrupt
265 | {
266 | private:
267 |
268 | timer_config_t stdConfig =
269 | {
270 | .alarm_en = TIMER_ALARM_EN, //enable timer alarm
271 | .counter_en = TIMER_START, //starts counting counter once timer_init called
272 | .intr_type = TIMER_INTR_MAX,
273 | .counter_dir = TIMER_COUNT_UP, //counts from 0 to counter value
274 | .auto_reload = TIMER_AUTORELOAD_EN, //reloads counter automatically
275 | .divider = TIMER_DIVIDER,
276 | #if (SOC_TIMER_GROUP_SUPPORT_XTAL)
277 | #if (USING_ESP32_TIMERINTERRUPT)
278 | .clk_src = TIMER_SRC_CLK_XTAL //Use XTAL as source clock
279 | #else
280 | .clk_src = TIMER_SRC_CLK_APB //Use APB as source clock
281 | #endif
282 | #endif
283 | };
284 |
285 | timer_idx_t _timerIndex;
286 | timer_group_t _timerGroup;
287 | uint32_t interruptFlag; // either TIMER_INTR_T0 or TIMER_INTR_T1
288 |
289 | uint8_t _timerNo;
290 |
291 | esp32_timer_callback _callback; // pointer to the callback function
292 | float _frequency; // Timer frequency
293 | uint64_t _timerCount; // count to activate timer
294 |
295 | //xQueueHandle s_timer_queue;
296 |
297 | public:
298 |
299 | ESP32TimerInterrupt(uint8_t timerNo)
300 | {
301 | _callback = NULL;
302 |
303 | if (timerNo < MAX_ESP32_NUM_TIMERS)
304 | {
305 | _timerNo = timerNo;
306 |
307 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
308 |
309 | // Always using TIMER_INTR_T0
310 | _timerIndex = (timer_idx_t) ( (uint32_t) 0 );
311 |
312 | // timerNo == 0 => Group 0, timerNo == 1 => Group 1
313 | _timerGroup = (timer_group_t) ( (uint32_t) timerNo);
314 |
315 | #else
316 |
317 | _timerIndex = (timer_idx_t) (_timerNo % TIMER_MAX);
318 |
319 | _timerGroup = (timer_group_t) (_timerNo / TIMER_MAX);
320 |
321 | #endif
322 | }
323 | else
324 | {
325 | _timerNo = MAX_ESP32_NUM_TIMERS;
326 | }
327 | };
328 |
329 | // frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
330 | // No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
331 | bool setFrequency(const float& frequency, esp32_timer_callback callback)
332 | {
333 | if (_timerNo < MAX_ESP32_NUM_TIMERS)
334 | {
335 | // select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now.
336 | // Will use later if very low frequency is needed.
337 | _frequency = TIMER_BASE_CLK / TIMER_DIVIDER; //1000000;
338 | _timerCount = (uint64_t) _frequency / frequency;
339 | // count up
340 |
341 | #if USING_ESP32_S2_NEW_TIMERINTERRUPT
342 | TISR_LOGWARN3(F("ESP32_S2_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
343 | TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
344 | TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
345 | TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
346 | TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
347 | #elif USING_ESP32_S3_NEW_TIMERINTERRUPT
348 | // ESP32-S3 is embedded with four 54-bit general-purpose timers, which are based on 16-bit prescalers
349 | // and 54-bit auto-reload-capable up/down-timers
350 | TISR_LOGWARN3(F("ESP32_S3_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
351 | TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
352 | TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
353 | TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
354 | TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
355 | #else
356 | TISR_LOGWARN3(F("ESP32_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
357 | TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
358 | TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
359 | TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32), F("-"), (uint32_t) (_timerCount));
360 | TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
361 | #endif
362 |
363 | timer_init(_timerGroup, _timerIndex, &stdConfig);
364 |
365 | // Counter value to 0 => counting up to alarm value as .counter_dir == TIMER_COUNT_UP
366 | timer_set_counter_value(_timerGroup, _timerIndex, 0x00000000ULL);
367 |
368 | timer_set_alarm_value(_timerGroup, _timerIndex, TIMER_SCALE / frequency);
369 |
370 | // enable interrupts for _timerGroup, _timerIndex
371 | timer_enable_intr(_timerGroup, _timerIndex);
372 |
373 | _callback = callback;
374 |
375 | // Register the ISR handler
376 | // If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, the handler function must be declared with IRAM_ATTR attribute
377 | // and can only call functions in IRAM or ROM. It cannot call other timer APIs.
378 | //timer_isr_register(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, ESP_INTR_FLAG_IRAM, NULL);
379 | timer_isr_callback_add(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, 0);
380 |
381 | timer_start(_timerGroup, _timerIndex);
382 |
383 | return true;
384 | }
385 | else
386 | {
387 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
388 | TISR_LOGERROR(F("Error. Timer must be 0-1"));
389 | #else
390 | TISR_LOGERROR(F("Error. Timer must be 0-3"));
391 | #endif
392 |
393 | return false;
394 | }
395 | }
396 |
397 | // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
398 | // No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
399 | bool setInterval(const unsigned long& interval, esp32_timer_callback callback)
400 | {
401 | return setFrequency((float) (1000000.0f / interval), callback);
402 | }
403 |
404 | bool attachInterrupt(const float& frequency, esp32_timer_callback callback)
405 | {
406 | return setFrequency(frequency, callback);
407 | }
408 |
409 | // interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
410 | // No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
411 | bool attachInterruptInterval(const unsigned long& interval, esp32_timer_callback callback)
412 | {
413 | return setFrequency( (float) ( 1000000.0f / interval), callback);
414 | }
415 |
416 | void detachInterrupt()
417 | {
418 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
419 | timer_group_intr_disable(_timerGroup, TIMER_INTR_T0);
420 | #else
421 | timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
422 | #endif
423 | }
424 |
425 | void disableTimer()
426 | {
427 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
428 | timer_group_intr_disable(_timerGroup, TIMER_INTR_T0);
429 | #else
430 | timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
431 | #endif
432 | }
433 |
434 | // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
435 | void reattachInterrupt()
436 | {
437 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
438 | timer_group_intr_enable(_timerGroup, TIMER_INTR_T0);
439 | #else
440 | timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
441 | #endif
442 | }
443 |
444 | // Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
445 | void enableTimer()
446 | {
447 | #if USING_ESP32_C3_NEW_TIMERINTERRUPT
448 | timer_group_intr_enable(_timerGroup, TIMER_INTR_T0);
449 | #else
450 | timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
451 | #endif
452 | }
453 |
454 | // Just stop clock source, clear the count
455 | void stopTimer()
456 | {
457 | timer_pause(_timerGroup, _timerIndex);
458 | }
459 |
460 | // Just reconnect clock source, start current count from 0
461 | void restartTimer()
462 | {
463 | timer_set_counter_value(_timerGroup, _timerIndex, 0x00000000ULL);
464 | timer_start(_timerGroup, _timerIndex);
465 | }
466 |
467 | int8_t getTimer() __attribute__((always_inline))
468 | {
469 | return _timerIndex;
470 | };
471 |
472 | int8_t getTimerGroup() __attribute__((always_inline))
473 | {
474 | return _timerGroup;
475 | };
476 |
477 | }; // class ESP32TimerInterrupt
478 |
479 | #endif // ESP32_NEW_TIMERINTERRUPT_H
480 |
481 |
--------------------------------------------------------------------------------
/src/TimerInterrupt_Generic_Debug.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | TimerInterrupt_Generic_Debug.h
3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
4 | Written by Khoi Hoang
5 |
6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_New_TimerInterrupt
7 | Licensed under MIT license
8 |
9 | The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
10 | 1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
11 | 2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
12 |
13 | All the timers are based on 64 bits counters and 16 bit prescalers. The timer counters can be configured to count up or down
14 | and support automatic reload and software reload. They can also generate alarms when they reach a specific value, defined by
15 | the software. The value of the counter can be read by the software program.
16 |
17 | Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
18 | unsigned long miliseconds), you just consume only one ESP32-S2 timer and avoid conflicting with other cores' tasks.
19 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
20 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
21 | This important feature is absolutely necessary for mission-critical tasks.
22 |
23 | Based on SimpleTimer - A timer library for Arduino.
24 | Author: mromani@ottotecnica.com
25 | Copyright (c) 2010 OTTOTECNICA Italy
26 |
27 | Based on BlynkTimer.h
28 | Author: Volodymyr Shymanskyy
29 |
30 | Version: 1.5.0
31 |
32 | Version Modified By Date Comments
33 | ------- ----------- ---------- -----------
34 | 1.0.0 K Hoang 15/08/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0-rc1+
35 | 1.0.1 K.Hoang 14/11/2021 Avoid using float and D1 in examples due to issue with core v2.0.0 and v2.0.1
36 | 1.1.0 K.Hoang 18/01/2022 Fix `multiple-definitions` linker error.
37 | 1.2.0 K Hoang 12/02/2022 Add support to new ESP32-S3
38 | 1.2.1 K Hoang 16/06/2022 Add support to new Adafruit boards
39 | 1.3.0 K Hoang 03/08/2022 Suppress errors and warnings for new ESP32 core
40 | 1.4.0 K Hoang 11/08/2022 Add support and suppress warnings for ESP32_C3, ESP32_S2 and ESP32_S3 boards
41 | 1.5.0 K Hoang 16/11/2022 Fix doubled time for ESP32_C3, ESP32_S2 and ESP32_S3
42 | *****************************************************************************************************************************/
43 |
44 | #pragma once
45 |
46 | #ifndef TIMERINTERRUPT_GENERIC_DEBUG_H
47 | #define TIMERINTERRUPT_GENERIC_DEBUG_H
48 |
49 | #ifdef TIMERINTERRUPT_DEBUG_PORT
50 | #define TISR_DBG_PORT TIMERINTERRUPT_DEBUG_PORT
51 | #else
52 | #define TISR_DBG_PORT Serial
53 | #endif
54 |
55 | // Change _TIMERINTERRUPT_LOGLEVEL_ to set tracing and logging verbosity
56 | // 0: DISABLED: no logging
57 | // 1: ERROR: errors
58 | // 2: WARN: errors and warnings
59 | // 3: INFO: errors, warnings and informational (default)
60 | // 4: DEBUG: errors, warnings, informational and debug
61 |
62 | #ifndef _TIMERINTERRUPT_LOGLEVEL_
63 | #define _TIMERINTERRUPT_LOGLEVEL_ 1
64 | #endif
65 |
66 | /////////////////////////////////////////////////////////
67 |
68 | const char TISR_MARK[] = "[TISR] ";
69 |
70 | #define TISR_PRINT_MARK TISR_PRINT(TISR_MARK)
71 | #define TISR_PRINT_SP TISR_DBG_PORT.print(" ")
72 |
73 | #define TISR_PRINT TISR_DBG_PORT.print
74 | #define TISR_PRINTLN TISR_DBG_PORT.println
75 |
76 | /////////////////////////////////////////////////////////
77 |
78 | #define TISR_LOGERROR(x) if(_TIMERINTERRUPT_LOGLEVEL_>0) { TISR_PRINT_MARK; TISR_PRINTLN(x); }
79 | #define TISR_LOGERROR0(x) if(_TIMERINTERRUPT_LOGLEVEL_>0) { TISR_PRINT(x); }
80 | #define TISR_LOGERROR1(x,y) if(_TIMERINTERRUPT_LOGLEVEL_>0) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINTLN(y); }
81 | #define TISR_LOGERROR2(x,y,z) if(_TIMERINTERRUPT_LOGLEVEL_>0) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINTLN(z); }
82 | #define TISR_LOGERROR3(x,y,z,w) if(_TIMERINTERRUPT_LOGLEVEL_>0) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINT(z); TISR_PRINT_SP; TISR_PRINTLN(w); }
83 |
84 | /////////////////////////////////////////////////////////
85 |
86 | #define TISR_LOGWARN(x) if(_TIMERINTERRUPT_LOGLEVEL_>1) { TISR_PRINT_MARK; TISR_PRINTLN(x); }
87 | #define TISR_LOGWARN0(x) if(_TIMERINTERRUPT_LOGLEVEL_>1) { TISR_PRINT(x); }
88 | #define TISR_LOGWARN1(x,y) if(_TIMERINTERRUPT_LOGLEVEL_>1) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINTLN(y); }
89 | #define TISR_LOGWARN2(x,y,z) if(_TIMERINTERRUPT_LOGLEVEL_>1) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINTLN(z); }
90 | #define TISR_LOGWARN3(x,y,z,w) if(_TIMERINTERRUPT_LOGLEVEL_>1) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINT(z); TISR_PRINT_SP; TISR_PRINTLN(w); }
91 |
92 | /////////////////////////////////////////////////////////
93 |
94 | #define TISR_LOGINFO(x) if(_TIMERINTERRUPT_LOGLEVEL_>2) { TISR_PRINT_MARK; TISR_PRINTLN(x); }
95 | #define TISR_LOGINFO0(x) if(_TIMERINTERRUPT_LOGLEVEL_>2) { TISR_PRINT(x); }
96 | #define TISR_LOGINFO1(x,y) if(_TIMERINTERRUPT_LOGLEVEL_>2) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINTLN(y); }
97 | #define TISR_LOGINFO2(x,y,z) if(_TIMERINTERRUPT_LOGLEVEL_>2) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINTLN(z); }
98 | #define TISR_LOGINFO3(x,y,z,w) if(_TIMERINTERRUPT_LOGLEVEL_>2) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINT(z); TISR_PRINT_SP; TISR_PRINTLN(w); }
99 |
100 | /////////////////////////////////////////////////////////
101 |
102 | #define TISR_LOGDEBUG(x) if(_TIMERINTERRUPT_LOGLEVEL_>3) { TISR_PRINT_MARK; TISR_PRINTLN(x); }
103 | #define TISR_LOGDEBUG0(x) if(_TIMERINTERRUPT_LOGLEVEL_>3) { TISR_PRINT(x); }
104 | #define TISR_LOGDEBUG1(x,y) if(_TIMERINTERRUPT_LOGLEVEL_>3) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINTLN(y); }
105 | #define TISR_LOGDEBUG2(x,y,z) if(_TIMERINTERRUPT_LOGLEVEL_>3) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINTLN(z); }
106 | #define TISR_LOGDEBUG3(x,y,z,w) if(_TIMERINTERRUPT_LOGLEVEL_>3) { TISR_PRINT_MARK; TISR_PRINT(x); TISR_PRINT_SP; TISR_PRINT(y); TISR_PRINT_SP; TISR_PRINT(z); TISR_PRINT_SP; TISR_PRINTLN(w); }
107 |
108 | /////////////////////////////////////////////////////////
109 |
110 |
111 | #endif //TIMERINTERRUPT_GENERIC_DEBUG_H
112 |
--------------------------------------------------------------------------------
/utils/astyle_library.conf:
--------------------------------------------------------------------------------
1 | # Code formatting rules for Arduino libraries, modified from for KH libraries:
2 | #
3 | # https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf
4 | #
5 |
6 | # astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino
7 |
8 | --mode=c
9 | --lineend=linux
10 | --style=allman
11 |
12 | # -r or -R
13 | #--recursive
14 |
15 | # -c => Converts tabs into spaces
16 | convert-tabs
17 |
18 | # -s2 => 2 spaces indentation
19 | --indent=spaces=2
20 |
21 | # -t2 => tab =2 spaces
22 | #--indent=tab=2
23 |
24 | # -C
25 | --indent-classes
26 |
27 | # -S
28 | --indent-switches
29 |
30 | # -xW
31 | --indent-preproc-block
32 |
33 | # -Y => indent classes, switches (and cases), comments starting at column 1
34 | --indent-col1-comments
35 |
36 | # -M120 => maximum of 120 spaces to indent a continuation line
37 | --max-continuation-indent=120
38 |
39 | # -xC120 => max‑code‑length will break a line if the code exceeds # characters
40 | --max-code-length=120
41 |
42 | # -f =>
43 | --break-blocks
44 |
45 | # -p => put a space around operators
46 | --pad-oper
47 |
48 | # -xg => Insert space padding after commas
49 | --pad-comma
50 |
51 | # -H => put a space after if/for/while
52 | pad-header
53 |
54 | # -xb => Break one line headers (e.g. if/for/while)
55 | --break-one-line-headers
56 |
57 | # -c => Converts tabs into spaces
58 | #--convert-tabs
59 |
60 | # if you like one-liners, keep them
61 | #keep-one-line-statements
62 |
63 | # -xV
64 | --attach-closing-while
65 |
66 | #unpad-paren
67 |
68 | # -xp
69 | remove-comment-prefix
70 |
71 |
--------------------------------------------------------------------------------
/utils/restyle.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | for dir in . ; do
4 | find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \;
5 | done
6 |
7 |
--------------------------------------------------------------------------------