|
| 1 | +/**************************************************************************************************************************** |
| 2 | + ISR_16_PWMs_Array.ino |
| 3 | + For F/L/H/G/WB/MP1 boards |
| 4 | + Written by Khoi Hoang |
| 5 | +
|
| 6 | + Built by Khoi Hoang https://github.com/khoih-prog/STM32_Slow_PWM |
| 7 | + Licensed under MIT license |
| 8 | +
|
| 9 | + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by |
| 10 | + unsigned long miliseconds), you just consume only one timer and avoid conflicting with other cores' tasks. |
| 11 | + The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers |
| 12 | + Therefore, their executions are not blocked by bad-behaving functions / tasks. |
| 13 | + This important feature is absolutely necessary for mission-critical tasks. |
| 14 | +*****************************************************************************************************************************/ |
| 15 | + |
| 16 | +#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \ |
| 17 | + defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \ |
| 18 | + defined(STM32WB) || defined(STM32MP1) || defined(STM32L5)) |
| 19 | + #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting. |
| 20 | +#endif |
| 21 | + |
| 22 | +// These define's must be placed at the beginning before #include "STM32_Slow_PWM.h" |
| 23 | +// _PWM_LOGLEVEL_ from 0 to 4 |
| 24 | +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. |
| 25 | +#define _PWM_LOGLEVEL_ 3 |
| 26 | + |
| 27 | +#define USING_MICROS_RESOLUTION true //false |
| 28 | + |
| 29 | +// Default is true, uncomment to false |
| 30 | +//#define CHANGING_PWM_END_OF_CYCLE false |
| 31 | + |
| 32 | +#define MAX_STM32_PWM_FREQ 1000 |
| 33 | + |
| 34 | +// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error |
| 35 | +#include "STM32_Slow_PWM.h" |
| 36 | + |
| 37 | +#define LED_OFF LOW |
| 38 | +#define LED_ON HIGH |
| 39 | + |
| 40 | +#ifndef LED_BUILTIN |
| 41 | + #define LED_BUILTIN 13 |
| 42 | +#endif |
| 43 | + |
| 44 | +#ifndef LED_BLUE |
| 45 | + #define LED_BLUE 2 |
| 46 | +#endif |
| 47 | + |
| 48 | +#ifndef LED_RED |
| 49 | + #define LED_RED 3 |
| 50 | +#endif |
| 51 | + |
| 52 | +#define HW_TIMER_INTERVAL_US 20L |
| 53 | + |
| 54 | +volatile uint64_t startMicros = 0; |
| 55 | + |
| 56 | +// Depending on the board, you can select H7 Hardware Timer from TIM1-TIM22 |
| 57 | +// If you select a Timer not correctly, you'll get a message from compiler |
| 58 | +// 'TIMxx' was not declared in this scope; did you mean 'TIMyy'? |
| 59 | + |
| 60 | +// STM32 OK : TIM1, TIM4, TIM7, TIM8, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17 |
| 61 | +// STM32 Not OK : TIM2, TIM3, TIM5, TIM6, TIM18, TIM19, TIM20, TIM21, TIM22 |
| 62 | +// STM32 No timer : TIM9, TIM10, TIM11. Only for F2, F4 and STM32L1 |
| 63 | +// STM32 No timer : TIM18, TIM19, TIM20, TIM21, TIM22 |
| 64 | + |
| 65 | +// Init timer TIM1 |
| 66 | +STM32Timer ITimer(TIM1); |
| 67 | + |
| 68 | +// Init STM32_Slow_PWM |
| 69 | +STM32_Slow_PWM ISR_PWM; |
| 70 | + |
| 71 | +////////////////////////////////////////////////////// |
| 72 | + |
| 73 | +void TimerHandler() |
| 74 | +{ |
| 75 | + ISR_PWM.run(); |
| 76 | +} |
| 77 | + |
| 78 | +////////////////////////////////////////////////////// |
| 79 | + |
| 80 | +#define NUMBER_ISR_PWMS 16 |
| 81 | + |
| 82 | +#define PIN_D0 D0 |
| 83 | +#define PIN_D1 D1 |
| 84 | +#define PIN_D2 D2 |
| 85 | +#define PIN_D3 D3 |
| 86 | +#define PIN_D4 D4 |
| 87 | +#define PIN_D5 D5 |
| 88 | +#define PIN_D6 D6 |
| 89 | +#define PIN_D7 D7 |
| 90 | +#define PIN_D8 D8 |
| 91 | +#define PIN_D9 D9 |
| 92 | +#define PIN_D10 D10 |
| 93 | +#define PIN_D11 D11 |
| 94 | +#define PIN_D12 D12 |
| 95 | + |
| 96 | +////////////////////////////////////////////////////// |
| 97 | + |
| 98 | +#define USING_PWM_FREQUENCY true |
| 99 | + |
| 100 | +////////////////////////////////////////////////////// |
| 101 | + |
| 102 | +// You can assign pins here. Be carefull to select good pin to use or crash, e.g pin 6-11 |
| 103 | +uint32_t PWM_Pin[] = |
| 104 | +{ |
| 105 | + LED_BUILTIN, LED_BLUE, LED_RED, PIN_D0, PIN_D1, PIN_D2, PIN_D3, PIN_D4, |
| 106 | + PIN_D5, PIN_D6, PIN_D7, PIN_D8, PIN_D9, PIN_D10, PIN_D11, PIN_D12 |
| 107 | +}; |
| 108 | + |
| 109 | +// You can assign any interval for any timer here, in microseconds |
| 110 | +uint32_t PWM_Period[] = |
| 111 | +{ |
| 112 | + 1000000, 500000, 333333, 250000, 200000, 166667, 142857, 125000, |
| 113 | + 111111, 100000, 66667, 50000, 40000, 33333, 25000, 20000 |
| 114 | +}; |
| 115 | + |
| 116 | +// You can assign any interval for any timer here, in Hz |
| 117 | +float PWM_Freq[] = |
| 118 | +{ |
| 119 | + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, |
| 120 | + 9.0f, 10.0f, 15.0f, 20.0f, 25.0f, 30.0f, 40.0f, 50.0f |
| 121 | +}; |
| 122 | + |
| 123 | +// You can assign any interval for any timer here, in milliseconds |
| 124 | +float PWM_DutyCycle[] = |
| 125 | +{ |
| 126 | + 5.00, 10.00, 20.00, 30.00, 40.00, 45.00, 50.00, 55.00, |
| 127 | + 60.00, 65.00, 70.00, 75.00, 80.00, 85.00, 90.00, 95.00 |
| 128 | +}; |
| 129 | + |
| 130 | +typedef void (*irqCallback) (); |
| 131 | + |
| 132 | + |
| 133 | +// In STM32, avoid doing something fancy in ISR, for example complex Serial.print with String() argument |
| 134 | +// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment |
| 135 | +// Or you can get this run-time error / crash |
| 136 | +void doingSomething0() |
| 137 | +{ |
| 138 | +} |
| 139 | + |
| 140 | +void doingSomething1() |
| 141 | +{ |
| 142 | +} |
| 143 | + |
| 144 | +void doingSomething2() |
| 145 | +{ |
| 146 | +} |
| 147 | + |
| 148 | +void doingSomething3() |
| 149 | +{ |
| 150 | +} |
| 151 | + |
| 152 | +void doingSomething4() |
| 153 | +{ |
| 154 | +} |
| 155 | + |
| 156 | +void doingSomething5() |
| 157 | +{ |
| 158 | +} |
| 159 | + |
| 160 | +void doingSomething6() |
| 161 | +{ |
| 162 | +} |
| 163 | + |
| 164 | +void doingSomething7() |
| 165 | +{ |
| 166 | +} |
| 167 | + |
| 168 | +void doingSomething8() |
| 169 | +{ |
| 170 | +} |
| 171 | + |
| 172 | +void doingSomething9() |
| 173 | +{ |
| 174 | +} |
| 175 | + |
| 176 | +void doingSomething10() |
| 177 | +{ |
| 178 | +} |
| 179 | + |
| 180 | +void doingSomething11() |
| 181 | +{ |
| 182 | +} |
| 183 | + |
| 184 | +void doingSomething12() |
| 185 | +{ |
| 186 | +} |
| 187 | + |
| 188 | +void doingSomething13() |
| 189 | +{ |
| 190 | +} |
| 191 | + |
| 192 | +void doingSomething14() |
| 193 | +{ |
| 194 | +} |
| 195 | + |
| 196 | +void doingSomething15() |
| 197 | +{ |
| 198 | +} |
| 199 | + |
| 200 | +irqCallback irqCallbackStartFunc[NUMBER_ISR_PWMS] = |
| 201 | +{ |
| 202 | + doingSomething0, doingSomething1, doingSomething2, doingSomething3, |
| 203 | + doingSomething4, doingSomething5, doingSomething6, doingSomething7, |
| 204 | + doingSomething8, doingSomething9, doingSomething10, doingSomething11, |
| 205 | + doingSomething12, doingSomething13, doingSomething14, doingSomething15 |
| 206 | +}; |
| 207 | + |
| 208 | +//////////////////////////////////////////////// |
| 209 | + |
| 210 | +void setup() |
| 211 | +{ |
| 212 | + Serial.begin(115200); |
| 213 | + while (!Serial); |
| 214 | + |
| 215 | + delay(2000); |
| 216 | + |
| 217 | + Serial.print(F("\nStarting ISR_16_PWMs_Array on ")); Serial.println(BOARD_NAME); |
| 218 | + Serial.println(STM32_SLOW_PWM_VERSION); |
| 219 | + |
| 220 | + // Interval in microsecs |
| 221 | + if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_US, TimerHandler)) |
| 222 | + { |
| 223 | + startMicros = micros(); |
| 224 | + Serial.print(F("Starting ITimer OK, micros() = ")); Serial.println(startMicros); |
| 225 | + } |
| 226 | + else |
| 227 | + Serial.println(F("Can't set ITimer. Select another freq. or timer")); |
| 228 | + |
| 229 | +#if 1 |
| 230 | + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary |
| 231 | + // You can use up to 16 timer for each ISR_PWM |
| 232 | + for (uint16_t i = 0; i < NUMBER_ISR_PWMS; i++) |
| 233 | + { |
| 234 | + //void setPWM(uint32_t pin, float frequency, float dutycycle |
| 235 | + // , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr) |
| 236 | + |
| 237 | +#if USING_PWM_FREQUENCY |
| 238 | + |
| 239 | + // You can use this with PWM_Freq in Hz |
| 240 | + ISR_PWM.setPWM(PWM_Pin[i], PWM_Freq[i], PWM_DutyCycle[i], irqCallbackStartFunc[i]); |
| 241 | + |
| 242 | +#else |
| 243 | + #if USING_MICROS_RESOLUTION |
| 244 | + // Or using period in microsecs resolution |
| 245 | + ISR_PWM.setPWM_Period(PWM_Pin[i], PWM_Period[i], PWM_DutyCycle[i], irqCallbackStartFunc[i]); |
| 246 | + #else |
| 247 | + // Or using period in millisecs resolution |
| 248 | + ISR_PWM.setPWM_Period(PWM_Pin[i], PWM_Period[i] / 1000, PWM_DutyCycle[i], irqCallbackStartFunc[i]); |
| 249 | + #endif |
| 250 | +#endif |
| 251 | + } |
| 252 | +#endif |
| 253 | +} |
| 254 | + |
| 255 | +void loop() |
| 256 | +{ |
| 257 | +} |
0 commit comments