|
1 | 1 | /****************************************************************************************************************************
|
2 | 2 | Argument_None.ino
|
3 |
| - For ESP8266 boards |
| 3 | + For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.2+ |
4 | 4 | Written by Khoi Hoang
|
5 | 5 |
|
6 |
| - Built by Khoi Hoang https://github.com/khoih-prog/ESP8266TimerInterrupt |
| 6 | + Built by Khoi Hoang https://github.com/khoih-prog/ESP32TimerInterrupt |
7 | 7 | Licensed under MIT license
|
8 | 8 |
|
9 |
| - The ESP8266 timers are badly designed, using only 23-bit counter along with maximum 256 prescaler. They're only better than UNO / Mega. |
10 |
| - The ESP8266 has two hardware timers, but timer0 has been used for WiFi and it's not advisable to use. Only timer1 is available. |
11 |
| - The timer1's 23-bit counter terribly can count only up to 8,388,607. So the timer1 maximum interval is very short. |
12 |
| - Using 256 prescaler, maximum timer1 interval is only 26.843542 seconds !!! |
| 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 |
13 | 12 |
|
14 |
| - Now with these new 16 ISR-based timers, the maximum interval is practically unlimited (limited only by unsigned long miliseconds) |
| 13 | + All the timers are based on 64-bit counters (except 54-bit counter for ESP32_S3 counter) and 16 bit prescalers. |
| 14 | + The timer counters can be configured to count up or down and support automatic reload and software reload. |
| 15 | + They can also generate alarms when they reach a specific value, defined by the software. |
| 16 | + 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. |
15 | 20 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
|
16 | 21 | Therefore, their executions are not blocked by bad-behaving functions / tasks.
|
17 | 22 | This important feature is absolutely necessary for mission-critical tasks.
|
18 | 23 | *****************************************************************************************************************************/
|
19 | 24 |
|
20 |
| -/* Notes: |
| 25 | +/* |
| 26 | + Notes: |
21 | 27 | Special design is necessary to share data between interrupt code and the rest of your program.
|
22 | 28 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume
|
23 | 29 | variable can not spontaneously change. Because your function may change variables while your program is using them,
|
|
28 | 34 | or the entire sequence of your code which accesses the data.
|
29 | 35 | */
|
30 | 36 |
|
31 |
| -#if !defined(ESP8266) |
32 |
| - #error This code is designed to run on ESP8266 and ESP8266-based boards! Please check your Tools->Board setting. |
| 37 | +#if !defined( ESP32 ) |
| 38 | + #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. |
33 | 39 | #endif
|
34 | 40 |
|
35 |
| -// These define's must be placed at the beginning before #include "ESP8266TimerInterrupt.h" |
| 41 | +// These define's must be placed at the beginning before #include "_TIMERINTERRUPT_LOGLEVEL_.h" |
36 | 42 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
|
37 |
| -// Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. |
38 |
| -#define TIMER_INTERRUPT_DEBUG 0 |
39 |
| -#define _TIMERINTERRUPT_LOGLEVEL_ 0 |
| 43 | +#define _TIMERINTERRUPT_LOGLEVEL_ 3 |
40 | 44 |
|
41 |
| -// Select a Timer Clock |
42 |
| -#define USING_TIM_DIV1 false // for shortest and most accurate timer |
43 |
| -#define USING_TIM_DIV16 false // for medium time and medium accurate timer |
44 |
| -#define USING_TIM_DIV256 true // for longest timer but least accurate. Default |
| 45 | +// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error |
| 46 | +#include "ESP32TimerInterrupt.h" |
45 | 47 |
|
46 |
| -#include "ESP8266TimerInterrupt.h" |
| 48 | +// Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868 |
| 49 | +// Don't use PIN_D2 with ESP32_C3 (crash) |
| 50 | +#define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32 |
| 51 | +#define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32 |
47 | 52 |
|
48 |
| -#ifndef LED_BUILTIN |
49 |
| - #define LED_BUILTIN 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266, NodeMCU and WeMoS, control on-board LED |
50 |
| -#endif |
51 | 53 |
|
52 |
| -volatile uint32_t lastMillis = 0; |
| 54 | +// With core v2.0.0+, you can't use Serial.print/println in ISR or crash. |
| 55 | +// and you can't use float calculation inside ISR |
| 56 | +// Only OK in core v1.0.6- |
| 57 | +bool IRAM_ATTR TimerHandler0(void * timerNo) |
| 58 | +{ |
| 59 | + static bool toggle0 = false; |
| 60 | + |
| 61 | + //timer interrupt toggles pin PIN_D19 |
| 62 | + digitalWrite(PIN_D19, toggle0); |
| 63 | + toggle0 = !toggle0; |
| 64 | + |
| 65 | + return true; |
| 66 | +} |
53 | 67 |
|
54 |
| -void IRAM_ATTR TimerHandler() |
| 68 | +// With core v2.0.0+, you can't use Serial.print/println in ISR or crash. |
| 69 | +// and you can't use float calculation inside ISR |
| 70 | +// Only OK in core v1.0.6- |
| 71 | +bool IRAM_ATTR TimerHandler1(void * timerNo) |
55 | 72 | {
|
56 |
| - static bool toggle = false; |
57 |
| - static bool started = false; |
58 |
| - |
59 |
| - if (!started) |
60 |
| - { |
61 |
| - started = true; |
62 |
| - pinMode(LED_BUILTIN, OUTPUT); |
63 |
| - } |
64 |
| - |
65 |
| -#if (TIMER_INTERRUPT_DEBUG > 0) |
66 |
| - Serial.print("Delta ms = "); |
67 |
| - Serial.println(millis() - lastMillis); |
68 |
| - lastMillis = millis(); |
69 |
| -#endif |
| 73 | + ///////////////////////////////////////////////////////// |
| 74 | + |
| 75 | + static bool toggle1 = false; |
| 76 | + |
| 77 | + //timer interrupt toggles outputPin |
| 78 | + digitalWrite(PIN_D3, toggle1); |
| 79 | + toggle1 = !toggle1; |
70 | 80 |
|
71 |
| - //timer interrupt toggles pin LED_BUILTIN |
72 |
| - digitalWrite(LED_BUILTIN, toggle); |
73 |
| - toggle = !toggle; |
| 81 | + return true; |
74 | 82 | }
|
75 | 83 |
|
76 |
| -#define TIMER_INTERVAL_MS 1000 |
| 84 | +#define TIMER0_INTERVAL_MS 100 |
77 | 85 |
|
78 |
| -// Init ESP8266 timer 1 |
79 |
| -ESP8266Timer ITimer; |
| 86 | +#define TIMER1_INTERVAL_MS 5000 |
| 87 | + |
| 88 | +// Init ESP32 timer 0 and 1 |
| 89 | +ESP32Timer ITimer0(0); |
| 90 | +ESP32Timer ITimer1(1); |
80 | 91 |
|
81 | 92 | void setup()
|
82 | 93 | {
|
83 |
| - Serial.begin(115200); |
| 94 | + pinMode(PIN_D19, OUTPUT); |
| 95 | + pinMode(PIN_D3, OUTPUT); |
| 96 | + |
| 97 | + Serial.begin(115200); |
84 | 98 |
|
85 |
| - while (!Serial && millis() < 5000); |
| 99 | + while (!Serial && millis() < 5000); |
86 | 100 |
|
87 | 101 | delay(500);
|
88 | 102 |
|
89 |
| - Serial.print(F("\nStarting Argument_None on ")); |
90 |
| - Serial.println(ARDUINO_BOARD); |
91 |
| - Serial.println(ESP8266_TIMER_INTERRUPT_VERSION); |
92 |
| - Serial.print(F("CPU Frequency = ")); |
93 |
| - Serial.print(F_CPU / 1000000); |
94 |
| - Serial.println(F(" MHz")); |
95 |
| - |
96 |
| - // Interval in microsecs |
97 |
| - if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler)) |
98 |
| - { |
99 |
| - lastMillis = millis(); |
100 |
| - Serial.print(F("Starting ITimer OK, millis() = ")); |
101 |
| - Serial.println(lastMillis); |
102 |
| - } |
103 |
| - else |
104 |
| - Serial.println(F("Can't set ITimer correctly. Select another freq. or interval")); |
| 103 | + Serial.print(F("\nStarting Argument_None on ")); |
| 104 | + Serial.println(ARDUINO_BOARD); |
| 105 | + Serial.println(ESP32_TIMER_INTERRUPT_VERSION); |
| 106 | + Serial.print(F("CPU Frequency = ")); |
| 107 | + Serial.print(F_CPU / 1000000); |
| 108 | + Serial.println(F(" MHz")); |
| 109 | + |
| 110 | + // Using ESP32 => 80 / 160 / 240MHz CPU clock , |
| 111 | + // For 64-bit timer counter |
| 112 | + // For 16-bit timer prescaler up to 1024 |
| 113 | + |
| 114 | + // Interval in microsecs |
| 115 | + if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0)) |
| 116 | + //if (ITimer0.attachInterrupt(1, TimerHandler0)) |
| 117 | + { |
| 118 | + Serial.print(F("Starting ITimer0 OK, millis() = ")); |
| 119 | + Serial.println(millis()); |
| 120 | + } |
| 121 | + else |
| 122 | + Serial.println(F("Can't set ITimer0. Select another Timer, freq. or timer")); |
| 123 | + |
| 124 | + |
| 125 | + // Interval in microsecs |
| 126 | + if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)) |
| 127 | + //if (ITimer1.attachInterrupt(2, TimerHandler1)) |
| 128 | + { |
| 129 | + Serial.print(F("Starting ITimer1 OK, millis() = ")); |
| 130 | + Serial.println(millis()); |
| 131 | + } |
| 132 | + else |
| 133 | + Serial.println(F("Can't set ITimer1. Select another Timer, freq. or timer")); |
105 | 134 | }
|
106 | 135 |
|
107 | 136 | void loop()
|
108 | 137 | {
|
109 |
| - |
| 138 | + delay(1); |
110 | 139 | }
|
0 commit comments