|
1 | 1 | /**************************************************************************************************************************** |
2 | 2 | Argument_None.ino |
3 | | - For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.2+ |
| 3 | + For ESP8266 boards |
4 | 4 | Written by Khoi Hoang |
5 | 5 |
|
6 | | - Built by Khoi Hoang https://github.com/khoih-prog/ESP32TimerInterrupt |
| 6 | + Built by Khoi Hoang https://github.com/khoih-prog/ESP8266TimerInterrupt |
7 | 7 | Licensed under MIT license |
8 | 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 |
| 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 !!! |
12 | 13 |
|
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. |
| 14 | + Now with these new 16 ISR-based timers, the maximum interval is practically unlimited (limited only by unsigned long milliseconds) |
20 | 15 | The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers |
21 | 16 | Therefore, their executions are not blocked by bad-behaving functions / tasks. |
22 | 17 | This important feature is absolutely necessary for mission-critical tasks. |
23 | 18 | *****************************************************************************************************************************/ |
24 | 19 |
|
25 | | -/* |
26 | | - Notes: |
| 20 | +/* Notes: |
27 | 21 | Special design is necessary to share data between interrupt code and the rest of your program. |
28 | 22 | Variables usually need to be "volatile" types. Volatile tells the compiler to avoid optimizations that assume |
29 | 23 | variable can not spontaneously change. Because your function may change variables while your program is using them, |
|
34 | 28 | or the entire sequence of your code which accesses the data. |
35 | 29 | */ |
36 | 30 |
|
37 | | -#if !defined( ESP32 ) |
38 | | - #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. |
| 31 | +#if !defined(ESP8266) |
| 32 | + #error This code is designed to run on ESP8266 and ESP8266-based boards! Please check your Tools->Board setting. |
39 | 33 | #endif |
40 | 34 |
|
41 | | -// These define's must be placed at the beginning before #include "_TIMERINTERRUPT_LOGLEVEL_.h" |
| 35 | +// These define's must be placed at the beginning before #include "ESP8266TimerInterrupt.h" |
42 | 36 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4 |
43 | | -#define _TIMERINTERRUPT_LOGLEVEL_ 3 |
44 | | - |
45 | | -// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error |
46 | | -#include "ESP32TimerInterrupt.h" |
47 | | - |
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 |
| 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 |
52 | 40 |
|
| 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 |
53 | 45 |
|
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; |
| 46 | +#include "ESP8266TimerInterrupt.h" |
60 | 47 |
|
61 | | - //timer interrupt toggles pin PIN_D19 |
62 | | - digitalWrite(PIN_D19, toggle0); |
63 | | - toggle0 = !toggle0; |
| 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 |
64 | 51 |
|
65 | | - return true; |
66 | | -} |
| 52 | +volatile uint32_t lastMillis = 0; |
67 | 53 |
|
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) |
| 54 | +void IRAM_ATTR TimerHandler() |
72 | 55 | { |
73 | | - ///////////////////////////////////////////////////////// |
74 | | - |
75 | | - static bool toggle1 = false; |
76 | | - |
77 | | - //timer interrupt toggles outputPin |
78 | | - digitalWrite(PIN_D3, toggle1); |
79 | | - toggle1 = !toggle1; |
| 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 |
80 | 70 |
|
81 | | - return true; |
| 71 | + //timer interrupt toggles pin LED_BUILTIN |
| 72 | + digitalWrite(LED_BUILTIN, toggle); |
| 73 | + toggle = !toggle; |
82 | 74 | } |
83 | 75 |
|
84 | | -#define TIMER0_INTERVAL_MS 100 |
| 76 | +#define TIMER_INTERVAL_MS 1000 |
85 | 77 |
|
86 | | -#define TIMER1_INTERVAL_MS 5000 |
87 | | - |
88 | | -// Init ESP32 timer 0 and 1 |
89 | | -ESP32Timer ITimer0(0); |
90 | | -ESP32Timer ITimer1(1); |
| 78 | +// Init ESP8266 timer 1 |
| 79 | +ESP8266Timer ITimer; |
91 | 80 |
|
92 | 81 | void setup() |
93 | 82 | { |
94 | | - pinMode(PIN_D19, OUTPUT); |
95 | | - pinMode(PIN_D3, OUTPUT); |
96 | | - |
97 | | - Serial.begin(115200); |
| 83 | + Serial.begin(115200); |
98 | 84 |
|
99 | | - while (!Serial && millis() < 5000); |
| 85 | + while (!Serial && millis() < 5000); |
100 | 86 |
|
101 | 87 | delay(500); |
102 | 88 |
|
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")); |
| 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")); |
134 | 105 | } |
135 | 106 |
|
136 | 107 | void loop() |
137 | 108 | { |
138 | | - delay(1); |
| 109 | + |
139 | 110 | } |
0 commit comments