|
| 1 | +/**************************************************************************************************************************** |
| 2 | + ISR_16_PWMs_Array_Simple.ino |
| 3 | + For ESP8266 boards |
| 4 | + Written by Khoi Hoang |
| 5 | +
|
| 6 | + Built by Khoi Hoang https://github.com/khoih-prog/ESP8266_PWM |
| 7 | + Licensed under MIT license |
| 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 !!! |
| 13 | +
|
| 14 | + Now with these new 16 ISR-based timers, the maximum interval is practically unlimited (limited only by unsigned long miliseconds) |
| 15 | + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers |
| 16 | + Therefore, their executions are not blocked by bad-behaving functions / tasks. |
| 17 | + This important feature is absolutely necessary for mission-critical tasks. |
| 18 | +
|
| 19 | + Version: 1.0.0 |
| 20 | +
|
| 21 | + Version Modified By Date Comments |
| 22 | + ------- ----------- ---------- ----------- |
| 23 | + 1.0.0 K Hoang 21/09/2021 Initial coding for ESP8266 boards with ESP8266 core v3.0.2+ |
| 24 | +*****************************************************************************************************************************/ |
| 25 | + |
| 26 | +#if !defined(ESP8266) |
| 27 | +#error This code is designed to run on ESP8266 and ESP8266-based boards! Please check your Tools->Board setting. |
| 28 | +#endif |
| 29 | + |
| 30 | +// These define's must be placed at the beginning before #include "ESP8266_PWM.h" |
| 31 | +// _PWM_LOGLEVEL_ from 0 to 4 |
| 32 | +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. |
| 33 | +#define _PWM_LOGLEVEL_ 4 |
| 34 | + |
| 35 | +#define USING_MICROS_RESOLUTION true //false |
| 36 | + |
| 37 | +#include "ESP8266_PWM.h" |
| 38 | + |
| 39 | +#ifndef LED_BUILTIN |
| 40 | +#define LED_BUILTIN 2 |
| 41 | +#endif |
| 42 | + |
| 43 | +#define HW_TIMER_INTERVAL_US 20L |
| 44 | + |
| 45 | +volatile uint32_t startMicros = 0; |
| 46 | + |
| 47 | +// Init ESP8266Timer |
| 48 | +ESP8266Timer ITimer; |
| 49 | + |
| 50 | +// Init ESP8266_ISR_PWM |
| 51 | +ESP8266_PWM ISR_PWM; |
| 52 | + |
| 53 | +void IRAM_ATTR TimerHandler() |
| 54 | +{ |
| 55 | + ISR_PWM.run(); |
| 56 | +} |
| 57 | + |
| 58 | +////////////////////////////////////////////////////// |
| 59 | + |
| 60 | +//PIN_D0 can't be used for PWM/I2C |
| 61 | +#define PIN_D0 16 // Pin D0 mapped to pin GPIO16/USER/WAKE of ESP8266. This pin is also used for Onboard-Blue LED. PIN_D0 = 0 => LED ON |
| 62 | +#define PIN_D1 5 // Pin D1 mapped to pin GPIO5 of ESP8266 |
| 63 | +#define PIN_D2 4 // Pin D2 mapped to pin GPIO4 of ESP8266 |
| 64 | +#define PIN_D3 0 // Pin D3 mapped to pin GPIO0/FLASH of ESP8266 |
| 65 | +#define PIN_D4 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266 |
| 66 | +//#define PIN_LED 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266, NodeMCU and WeMoS, control on-board LED |
| 67 | +#define PIN_D5 14 // Pin D5 mapped to pin GPIO14/HSCLK of ESP8266 |
| 68 | +#define PIN_D6 12 // Pin D6 mapped to pin GPIO12/HMISO of ESP8266 |
| 69 | +#define PIN_D7 13 // Pin D7 mapped to pin GPIO13/RXD2/HMOSI of ESP8266 |
| 70 | +#define PIN_D8 15 // Pin D8 mapped to pin GPIO15/TXD2/HCS of ESP8266 |
| 71 | +#define PIN_D9 3 // Pin D9 /RX mapped to pin GPIO3/RXD0 of ESP8266 |
| 72 | +#define PIN_D10 1 // Pin D10/TX mapped to pin GPIO1/TXD0 of ESP8266 |
| 73 | + |
| 74 | +//Don't use pins GPIO6 to GPIO11 as already connected to flash, etc. Use them can crash the program |
| 75 | +//GPIO9(D11/SD2) and GPIO11 can be used only if flash in DIO mode ( not the default QIO mode) |
| 76 | +#define PIN_D11 9 // Pin D11/SD2 mapped to pin GPIO9/SDD2 of ESP8266 |
| 77 | +#define PIN_D12 10 // Pin D12/SD3 mapped to pin GPIO10/SDD3 of ESP8266 |
| 78 | + |
| 79 | +////////////////////////////////////////////////////// |
| 80 | + |
| 81 | +#define USING_PWM_FREQUENCY true |
| 82 | + |
| 83 | +////////////////////////////////////////////////////// |
| 84 | + |
| 85 | +// You can assign pins here. Be carefull to select good pin to use or crash |
| 86 | +uint32_t PWM_Pin = LED_BUILTIN; |
| 87 | + |
| 88 | +// You can assign any interval for any timer here, in microseconds |
| 89 | +uint32_t PWM_Period1 = 1000000L; |
| 90 | +// You can assign any interval for any timer here, in microseconds |
| 91 | +uint32_t PWM_Period2 = 500000L; |
| 92 | + |
| 93 | +// You can assign any interval for any timer here, in Hz |
| 94 | +uint32_t PWM_Freq1 = 1; |
| 95 | +// You can assign any interval for any timer here, in Hz |
| 96 | +uint32_t PWM_Freq2 = 2; |
| 97 | + |
| 98 | +// You can assign any duty_cycle for any PWM here, from 0-100 |
| 99 | +uint32_t PWM_DutyCycle1 = 50; |
| 100 | +// You can assign any duty_cycle for any PWM here, from 0-100 |
| 101 | +uint32_t PWM_DutyCycle2 = 90; |
| 102 | + |
| 103 | +// Channel number used to identify associated channel |
| 104 | +int channelNum; |
| 105 | + |
| 106 | +//////////////////////////////////////////////// |
| 107 | + |
| 108 | +void setup() |
| 109 | +{ |
| 110 | + Serial.begin(115200); |
| 111 | + while (!Serial); |
| 112 | + |
| 113 | + delay(2000); |
| 114 | + |
| 115 | + Serial.print(F("\nStarting ISR_Changing_PWM on ")); Serial.println(ARDUINO_BOARD); |
| 116 | + Serial.println(ESP8266_PWM_VERSION); |
| 117 | + Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz")); |
| 118 | + |
| 119 | + // Interval in microsecs |
| 120 | + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_US, TimerHandler)) |
| 121 | + { |
| 122 | + startMicros = micros(); |
| 123 | + Serial.print(F("Starting ITimer OK, micros() = ")); Serial.println(startMicros); |
| 124 | + } |
| 125 | + else |
| 126 | + Serial.println(F("Can't set ITimer. Select another freq. or timer")); |
| 127 | + |
| 128 | + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary |
| 129 | + // You can use up to 16 timer for each ISR_PWM |
| 130 | + //void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle |
| 131 | + // , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr) |
| 132 | +} |
| 133 | + |
| 134 | +void loop() |
| 135 | +{ |
| 136 | + Serial.print(F("Using PWM Freq = ")); Serial.print(PWM_Freq1); Serial.print(F(", PWM DutyCycle = ")); Serial.println(PWM_DutyCycle1); |
| 137 | + |
| 138 | +#if USING_PWM_FREQUENCY |
| 139 | + |
| 140 | + // You can use this with PWM_Freq in Hz |
| 141 | + ISR_PWM.setPWM(PWM_Pin, PWM_Freq1, PWM_DutyCycle1); |
| 142 | + |
| 143 | +#else |
| 144 | + #if USING_MICROS_RESOLUTION |
| 145 | + // Or using period in microsecs resolution |
| 146 | + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Freq1, PWM_DutyCycle1); |
| 147 | + #else |
| 148 | + // Or using period in millisecs resolution |
| 149 | + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000, PWM_DutyCycle1); |
| 150 | + #endif |
| 151 | +#endif |
| 152 | + |
| 153 | + delay(10000); |
| 154 | + |
| 155 | + ISR_PWM.deleteChannel((unsigned) channelNum); |
| 156 | + |
| 157 | + Serial.print(F("Using PWM Freq = ")); Serial.print(PWM_Freq2); Serial.print(F(", PWM DutyCycle = ")); Serial.println(PWM_DutyCycle2); |
| 158 | + |
| 159 | +#if USING_PWM_FREQUENCY |
| 160 | + |
| 161 | + // You can use this with PWM_Freq in Hz |
| 162 | + ISR_PWM.setPWM(PWM_Pin, PWM_Freq2, PWM_DutyCycle2); |
| 163 | + |
| 164 | +#else |
| 165 | + #if USING_MICROS_RESOLUTION |
| 166 | + // Or using period in microsecs resolution |
| 167 | + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Freq2, PWM_DutyCycle2); |
| 168 | + #else |
| 169 | + // Or using period in millisecs resolution |
| 170 | + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period2 / 1000, PWM_DutyCycle2); |
| 171 | + #endif |
| 172 | +#endif |
| 173 | + |
| 174 | + delay(10000); |
| 175 | +} |
0 commit comments