diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4db52c6..ee079f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,21 +1,21 @@ -## Contributing to nRF52_Slow_PWM +## Contributing to AVR_Slow_PWM ### Reporting Bugs -Please report bugs in nRF52_Slow_PWM if you find them. +Please report bugs in AVR_Slow_PWM if you find them. However, before reporting a bug please check through the following: -* [Existing Open Issues](https://github.com/khoih-prog/nRF52_Slow_PWM/issues) - someone might have already encountered this. +* [Existing Open Issues](https://github.com/khoih-prog/AVR_Slow_PWM/issues) - someone might have already encountered this. -If you don't find anything, please [open a new issue](https://github.com/khoih-prog/nRF52_Slow_PWM/issues/new). +If you don't find anything, please [open a new issue](https://github.com/khoih-prog/AVR_Slow_PWM/issues/new). ### How to submit a bug report Please ensure to specify the following: * Arduino IDE version (e.g. 1.8.16) or Platform.io version -* `nRF52` Core Version (e.g. Adafruit nRF52 core v1.0.0) +* Arduino / Adafruit / Sparkfun `AVR` Core Version (e.g. Arduino AVR core v1.8.3) * Contextual information (e.g. what you were trying to achieve) * Simplest possible steps to reproduce * Anything that might be relevant in your opinion, such as: @@ -27,9 +27,9 @@ Please ensure to specify the following: ``` Arduino IDE version: 1.8.16 -Arduino NRF52 Core Version 1.0.0 +Arduino AVR core v1.8.3 OS: Ubuntu 20.04 LTS -Linux xy-Inspiron-3593 5.4.0-80-generic #90-Ubuntu SMP Fri Jul 9 22:49:44 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux +Linux xy-Inspiron-3593 5.4.0-90-generic #101-Ubuntu SMP Fri Oct 15 20:00:55 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux Context: I encountered a crash while trying to use the Timer Interrupt. @@ -44,7 +44,7 @@ Steps to reproduce: Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. -There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/nRF52_Slow_PWM/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/AVR_Slow_PWM/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. ### Sending Pull Requests diff --git a/README.md b/README.md index b684331..1d2b50f 100644 --- a/README.md +++ b/README.md @@ -33,14 +33,18 @@ * [1. Init Hardware Timer](#1-init-hardware-timer) * [2. Set PWM Frequency, dutycycle, attach irqCallbackStartFunc and irqCallbackStopFunc functions](#2-Set-PWM-Frequency-dutycycle-attach-irqCallbackStartFunc-and-irqCallbackStopFunc-functions) * [Examples](#examples) - * [ 1. ISR_8_PWMs_Array](examples/ISR_8_PWMs_Array) - * [ 2. ISR_8_PWMs_Array_Complex](examples/ISR_8_PWMs_Array_Complex) - * [ 3. ISR_8_PWMs_Array_Simple](examples/ISR_8_PWMs_Array_Simple) + * [ 1. ISR_8_PWMs_Array](examples/ISR_8_PWMs_Array) + * [ 2. ISR_8_PWMs_Array_Complex](examples/ISR_8_PWMs_Array_Complex) + * [ 3. ISR_8_PWMs_Array_Simple](examples/ISR_8_PWMs_Array_Simple) + * [ 4. ISR_Changing_PWM](examples/ISR_Changing_PWM) + * [ 5. ISR_Modify_PWM](examples/ISR_Modify_PWM) * [Example ISR_8_PWMs_Array_Complex](#Example-ISR_8_PWMs_Array_Complex) * [Debug Terminal Output Samples](#debug-terminal-output-samples) * [1. ISR_8_PWMs_Array_Complex on Arduino AVR Leonardo ATMega32U4](#1-ISR_8_PWMs_Array_Complex-on-Arduino-AVR-Leonardo-ATMega32U4) * [2. ISR_8_PWMs_Array on Arduino AVR Mega2560/ADK](#2-isr_8_pwms_array-on-avr-mega2560adk) * [3. ISR_8_PWMs_Array_Simple on Arduino AVR Nano](#3-ISR_8_PWMs_Array_Simple-on-Arduino-AVR-Nano) + * [4. ISR_Modify_PWM on Arduino AVR Mega2560/ADK](#4-ISR_Modify_PWM-on-avr-mega2560adk) + * [5. ISR_Changing_PWM on Arduino AVR Mega2560/ADK](#5-ISR_Changing_PWM-on-avr-mega2560adk) * [Debug](#debug) * [Troubleshooting](#troubleshooting) * [Issues](#issues) @@ -58,7 +62,7 @@ ### Features -This library enables you to use ISR-based PWM channels on AVR-based boards, such as Mega-2560, UNO,Nano, Leonardo, etc., using AVR core to create and output PWM any GPIO pin. Because this library doesn't use the powerful purely hardware-controlled PWM with many limitations, the maximum PWM frequency is currently limited at **500Hz**, which is still suitable for many real-life applications. +This library enables you to use ISR-based PWM channels on AVR-based boards, such as Mega-2560, UNO,Nano, Leonardo, etc., using AVR core to create and output PWM any GPIO pin. Because this library doesn't use the powerful purely hardware-controlled PWM with many limitations, the maximum PWM frequency is currently limited at **500Hz**, which is still suitable for many real-life applications. Now you can also modify PWM settings on-the-fly. --- @@ -103,7 +107,7 @@ The catch is **your function is now part of an ISR (Interrupt Service Routine), ### Currently supported Boards -1. **AVR-based boards** such as **Mega-2560, UNO,Nano, Leonardo**, etc., using AVR core +1. **AVR-based boards** using ATMEGA_328P, ATMEGA_2560, ATMEGA_1280, ATMEGA_640, ATMEGA_16U4, ATMEGA_32U4, etc. boards such as **Mega-2560, UNO, Nano, Leonardo**, etc., using **Arduino, Adafruit or Sparkfun AVR core** --- @@ -120,7 +124,7 @@ The catch is **your function is now part of an ISR (Interrupt Service Routine), 1. [`Arduino IDE 1.8.16+` for Arduino](https://www.arduino.cc/en/Main/Software) 2. [`Arduino AVR core 1.8.3+`](https://github.com/arduino/ArduinoCore-avr) for Arduino AVR boards. Use Arduino Board Manager to install. [![Latest release](https://img.shields.io/github/release/arduino/ArduinoCore-avr.svg)](https://github.com/arduino/ArduinoCore-avr/releases/latest/) - 3. [`Adafruit AVR core 1.4.13+`](https://github.com/adafruit/Adafruit_Arduino_Boards) for Adafruit AVR boards. Use Arduino Board Manager to install. + 3. [`Adafruit AVR core 1.4.14+`](https://github.com/adafruit/Adafruit_Arduino_Boards) for Adafruit AVR boards. Use Arduino Board Manager to install. 4. [`Sparkfun AVR core 1.1.13+`](https://github.com/sparkfun/Arduino_Boards) for Sparkfun AVR boards. Use Arduino Board Manager to install. 5. To use with certain example @@ -270,7 +274,9 @@ void setup() 1. [ISR_8_PWMs_Array](examples/ISR_8_PWMs_Array) 2. [ISR_8_PWMs_Array_Complex](examples/ISR_8_PWMs_Array_Complex) - 3. [ISR_8_PWMs_Array_Simple](examples/ISR_8_PWMs_Array_Simple) + 3. [ISR_8_PWMs_Array_Simple](examples/ISR_8_PWMs_Array_Simple) + 4. [ISR_Changing_PWM](examples/ISR_Changing_PWM) + 5. [ISR_Modify_PWM](examples/ISR_Modify_PWM) --- @@ -405,11 +411,10 @@ uint32_t PWM_Period[NUMBER_ISR_PWMS] = 1000L, 500L, 333L, 250L, 200L, 166L, 142L, 125L }; - // You can assign any interval for any timer here, in Hz -uint32_t PWM_Freq[NUMBER_ISR_PWMS] = +double PWM_Freq[NUMBER_ISR_PWMS] = { - 1, 2, 3, 4, 5, 6, 7, 8 + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, }; // You can assign any interval for any timer here, in Microseconds @@ -770,7 +775,7 @@ The following is the sample terminal output when running example [ISR_8_PWMs_Arr ``` Starting ISR_8_PWMs_Array_Complex on Arduino AVR ATMega32U4 -AVR_Slow_PWM v1.0.0 +AVR_Slow_PWM v1.1.0 CPU Frequency = 16 MHz [PWM] T3 [PWM] Freq * 1000 = 10000000.00 @@ -815,7 +820,7 @@ The following is the sample terminal output when running example [**ISR_8_PWMs_A ``` Starting ISR_8_PWMs_Array_Complex on Arduino AVR Mega2560/ADK -AVR_Slow_PWM v1.0.0 +AVR_Slow_PWM v1.1.0 CPU Frequency = 16 MHz [PWM] T3 [PWM] Freq * 1000 = 10000000.00 @@ -856,11 +861,11 @@ PWM Channel : 7, prog Period (ms): 125.00, actual : 125008, prog DutyCycle : 45, ### 3. ISR_8_PWMs_Array_Simple on Arduino AVR Nano -The following is the sample terminal output when running example [**ISR_8_PWMs_Array_Simple**](examples/ISR_8_PWMs_Array_Simple) on **nRF52-based NRF52840_ITSYBITSY** to demonstrate how to use multiple PWM channels. +The following is the sample terminal output when running example [**ISR_8_PWMs_Array_Simple**](examples/ISR_8_PWMs_Array_Simple) on **Arduino AVR UNO** to demonstrate how to use multiple PWM channels. ``` Starting ISR_8_PWMs_Array_Complex on Arduino AVR UNO, Nano, etc. -AVR_Slow_PWM v1.0.0 +AVR_Slow_PWM v1.1.0 CPU Frequency = 16 MHz [PWM] T1 [PWM] Freq * 1000 = 10000000.00 @@ -898,6 +903,56 @@ PWM Channel : 6, prog Period (ms): 142.86, actual : 143012, prog DutyCycle : 40, PWM Channel : 7, prog Period (ms): 125.00, actual : 125012, prog DutyCycle : 45, actual : 44.95 ``` +--- + +### 4. ISR_Modify_PWM on AVR Mega2560/ADK + +The following is the sample terminal output when running example [ISR_Modify_PWM](examples/ISR_Modify_PWM) on **AVR Mega2560/ADK** to demonstrate how to modify PWM settings on-the-fly without deleting the PWM channel + +``` +Starting ISR_Modify_PWM on Arduino AVR Mega2560/ADK +AVR_Slow_PWM v1.1.0 +CPU Frequency = 16 MHz +[PWM] T3 +[PWM] Freq * 1000 = 10000000.00 +[PWM] F_CPU = 16000000 , preScalerDiv = 1 +[PWM] OCR = 1599 , preScalerIndex = 1 +[PWM] OK in loop => _OCR = 1599 +[PWM] _preScalerIndex = 1 , preScalerDiv = 1 +Starting ITimer3 OK, micros() = 2023160 +Using PWM Freq = 1.00, PWM DutyCycle = 10 +Channel : 0 Period : 1000000 OnTime : 100000 Start_Time : 2028040 +Channel : 0 Period : 500000 OnTime : 450000 Start_Time : 12033220 +Channel : 0 Period : 1000000 OnTime : 100000 Start_Time : 22034628 +Channel : 0 Period : 500000 OnTime : 450000 Start_Time : 32036036 +``` + +--- + +### 5. ISR_Changing_PWM on AVR Mega2560/ADK + +The following is the sample terminal output when running example [ISR_Changing_PWM](examples/ISR_Changing_PWM) on **AVR Mega2560/ADK** to demonstrate how to modify PWM settings on-the-fly by deleting the PWM channel and reinit the PWM channel + +``` +Starting ISR_Changing_PWM on Arduino AVR Mega2560/ADK +AVR_Slow_PWM v1.1.0 +CPU Frequency = 16 MHz +[PWM] T3 +[PWM] Freq * 1000 = 10000000.00 +[PWM] F_CPU = 16000000 , preScalerDiv = 1 +[PWM] OCR = 1599 , preScalerIndex = 1 +[PWM] OK in loop => _OCR = 1599 +[PWM] _preScalerIndex = 1 , preScalerDiv = 1 +Starting ITimer3 OK, micros() = 2023336 +Using PWM Freq = 1.00, PWM DutyCycle = 50 +Channel : 0 Period : 1000000 OnTime : 500000 Start_Time : 2028216 +Using PWM Freq = 2.00, PWM DutyCycle = 90 +Channel : 0 Period : 500000 OnTime : 450000 Start_Time : 12035408 +Using PWM Freq = 1.00, PWM DutyCycle = 50 +Channel : 0 Period : 1000000 OnTime : 500000 Start_Time : 22040404 +Using PWM Freq = 2.00, PWM DutyCycle = 90 +Channel : 0 Period : 500000 OnTime : 450000 Start_Time : 32045592 +``` --- --- @@ -942,6 +997,7 @@ Submit issues to: [AVR_Slow_PWM issues](https://github.com/khoih-prog/AVR_Slow_P 1. Basic hardware multi-channel PWM for **AVR boards, such as Mega-2560, UNO,Nano, Leonardo, etc.** using AVR core 2. Add Table of Contents +3. Add functions to modify PWM settings on-the-fly --- --- diff --git a/changelog.md b/changelog.md index 388a0a7..6ca1087 100644 --- a/changelog.md +++ b/changelog.md @@ -12,6 +12,7 @@ ## Table of Contents * [Changelog](#changelog) + * [Releases v1.1.0](#releases-v110) * [Initial Releases v1.0.0](#Initial-Releases-v100) --- @@ -19,6 +20,11 @@ ## Changelog +### Releases v1.1.0 + +1. Add functions to modify PWM settings on-the-fly +2. Add example to demo how to modify PWM settings on-the-fly + ### Initial Releases v1.0.0 1. Initial coding to support **AVR boards, such as Mega-2560, UNO,Nano, Leonardo, etc.**, etc. using AVR core diff --git a/examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino b/examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino index 0a1d665..7d70c11 100644 --- a/examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino +++ b/examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino @@ -17,12 +17,6 @@ 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. This important feature is absolutely necessary for mission-critical tasks. - - Version: 1.0.0 - - Version Modified By Date Comments - ------- ----------- ---------- ----------- - 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) *****************************************************************************************************************************/ #if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \ @@ -102,11 +96,10 @@ uint32_t PWM_Pin[] = #define NUMBER_ISR_PWMS ( sizeof(PWM_Pin) / sizeof(uint32_t) ) - // You can assign any interval for any timer here, in Hz -uint32_t PWM_Freq[NUMBER_ISR_PWMS] = +double PWM_Freq[NUMBER_ISR_PWMS] = { - 1, 2, 3, 4, 5, 6, 7, 8 + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, }; // You can assign any interval for any timer here, in Microseconds diff --git a/examples/ISR_8_PWMs_Array_Complex/ISR_8_PWMs_Array_Complex.ino b/examples/ISR_8_PWMs_Array_Complex/ISR_8_PWMs_Array_Complex.ino index 556c6f2..9348a96 100644 --- a/examples/ISR_8_PWMs_Array_Complex/ISR_8_PWMs_Array_Complex.ino +++ b/examples/ISR_8_PWMs_Array_Complex/ISR_8_PWMs_Array_Complex.ino @@ -17,12 +17,6 @@ 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. This important feature is absolutely necessary for mission-critical tasks. - - Version: 1.0.0 - - Version Modified By Date Comments - ------- ----------- ---------- ----------- - 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) *****************************************************************************************************************************/ #if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \ @@ -151,11 +145,10 @@ uint32_t PWM_Period[NUMBER_ISR_PWMS] = 1000L, 500L, 333L, 250L, 200L, 166L, 142L, 125L }; - // You can assign any interval for any timer here, in Hz -uint32_t PWM_Freq[NUMBER_ISR_PWMS] = +double PWM_Freq[NUMBER_ISR_PWMS] = { - 1, 2, 3, 4, 5, 6, 7, 8 + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, }; // You can assign any interval for any timer here, in Microseconds diff --git a/examples/ISR_8_PWMs_Array_Simple/ISR_8_PWMs_Array_Simple.ino b/examples/ISR_8_PWMs_Array_Simple/ISR_8_PWMs_Array_Simple.ino index 97744cc..a7d401f 100644 --- a/examples/ISR_8_PWMs_Array_Simple/ISR_8_PWMs_Array_Simple.ino +++ b/examples/ISR_8_PWMs_Array_Simple/ISR_8_PWMs_Array_Simple.ino @@ -17,12 +17,6 @@ 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. This important feature is absolutely necessary for mission-critical tasks. - - Version: 1.0.0 - - Version Modified By Date Comments - ------- ----------- ---------- ----------- - 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) *****************************************************************************************************************************/ #if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \ @@ -102,11 +96,10 @@ uint32_t PWM_Pin[] = #define NUMBER_ISR_PWMS ( sizeof(PWM_Pin) / sizeof(uint32_t) ) - // You can assign any interval for any timer here, in Hz -uint32_t PWM_Freq[NUMBER_ISR_PWMS] = +double PWM_Freq[NUMBER_ISR_PWMS] = { - 1, 2, 3, 4, 5, 6, 7, 8 + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, }; // You can assign any interval for any timer here, in Microseconds diff --git a/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino b/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino new file mode 100644 index 0000000..a476e69 --- /dev/null +++ b/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino @@ -0,0 +1,222 @@ +/**************************************************************************************************************************** + ISR_Changing_PWM.ino + For AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/AVR_Slow_PWM + Licensed under MIT license + + TCNTx - Timer/Counter Register. The actual timer value is stored here. + OCRx - Output Compare Register + ICRx - Input Capture Register (only for 16bit timer) + TIMSKx - Timer/Counter Interrupt Mask Register. To enable/disable timer interrupts. + TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt. + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one RP2040-based timer and avoid conflicting with other cores' tasks. + 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. + This important feature is absolutely necessary for mission-critical tasks. +*****************************************************************************************************************************/ + +#if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \ + defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) || defined(ARDUINO_AVR_ETHERNET) || \ + defined(ARDUINO_AVR_FIO) || defined(ARDUINO_AVR_BT) || defined(ARDUINO_AVR_LILYPAD) || defined(ARDUINO_AVR_PRO) || \ + defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(ARDUINO_AVR_FEATHER328P) || \ + defined(ARDUINO_AVR_METRO) || defined(ARDUINO_AVR_PROTRINKET5) || defined(ARDUINO_AVR_PROTRINKET3) || defined(ARDUINO_AVR_PROTRINKET5FTDI) || \ + defined(ARDUINO_AVR_PROTRINKET3FTDI) ) + #define USE_TIMER_1 true + #warning Using Timer1 +#else + #define USE_TIMER_3 true + #warning Using Timer3 +#endif + +// These define's must be placed at the beginning before #include "ESP32_PWM.h" +// _PWM_LOGLEVEL_ from 0 to 4 +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. +#define _PWM_LOGLEVEL_ 3 + +#define USING_MICROS_RESOLUTION true //false + +#include "AVR_Slow_PWM.h" + +#define LED_OFF HIGH +#define LED_ON LOW + +#ifndef LED_BUILTIN + #define LED_BUILTIN 13 +#endif + +#ifndef LED_BLUE + #define LED_BLUE 10 +#endif + +#ifndef LED_RED + #define LED_RED 11 +#endif + +// Don't change these numbers to make higher Timer freq. System can hang +#define HW_TIMER_INTERVAL_MS 0.1f +#define HW_TIMER_INTERVAL_FREQ 10000L + +volatile uint32_t startMicros = 0; + +// Init AVR_Slow_PWM, each can service 16 different ISR-based PWM channels +AVR_Slow_PWM ISR_PWM; + +////////////////////////////////////////////////////// + +void TimerHandler() +{ + ISR_PWM.run(); +} + +////////////////////////////////////////////////////// + +#define USING_PWM_FREQUENCY true + +////////////////////////////////////////////////////// + +// You can assign pins here. Be carefull to select good pin to use or crash +uint32_t PWM_Pin = LED_BUILTIN; + +// You can assign any interval for any timer here, in Hz +double PWM_Freq1 = 1.0f; +// You can assign any interval for any timer here, in Hz +double PWM_Freq2 = 2.0f; + +// You can assign any interval for any timer here, in microseconds +uint32_t PWM_Period1 = 1000000 / PWM_Freq1; +// You can assign any interval for any timer here, in microseconds +uint32_t PWM_Period2 = 1000000 / PWM_Freq2; + +// You can assign any duty_cycle for any PWM here, from 0-100 +uint32_t PWM_DutyCycle1 = 50; +// You can assign any duty_cycle for any PWM here, from 0-100 +uint32_t PWM_DutyCycle2 = 90; + +// Channel number used to identify associated channel +int channelNum; + +//////////////////////////////////////////////// + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + delay(2000); + + Serial.print(F("\nStarting ISR_Changing_PWM on ")); Serial.println(BOARD_NAME); + Serial.println(AVR_SLOW_PWM_VERSION); + Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz")); + + // Timer0 is used for micros(), millis(), delay(), etc and can't be used + // Select Timer 1-2 for UNO, 1-5 for MEGA, 1,3,4 for 16u4/32u4 + // Timer 2 is 8-bit timer, only for higher frequency + // Timer 4 of 16u4 and 32u4 is 8/10-bit timer, only for higher frequency + +#if USING_HW_TIMER_INTERVAL_MS + +#if USE_TIMER_1 + + ITimer1.init(); + + // Using ATmega328 used in UNO => 16MHz CPU clock , + + if (ITimer1.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler)) + { + Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer1. Select another freq. or timer")); + +#elif USE_TIMER_3 + + ITimer3.init(); + + if (ITimer3.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler)) + { + Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer3. Select another freq. or timer")); + +#endif + +#else + +#if USE_TIMER_1 + + ITimer1.init(); + + // Using ATmega328 used in UNO => 16MHz CPU clock , + + if (ITimer1.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler)) + { + Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer1. Select another freq. or timer")); + +#elif USE_TIMER_3 + + ITimer3.init(); + + if (ITimer3.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler)) + { + Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer3. Select another freq. or timer")); + +#endif + +#endif +} + +void loop() +{ + Serial.print(F("Using PWM Freq = ")); Serial.print(PWM_Freq1); Serial.print(F(", PWM DutyCycle = ")); Serial.println(PWM_DutyCycle1); + +#if USING_PWM_FREQUENCY + + // You can use this with PWM_Freq in Hz + channelNum = ISR_PWM.setPWM(PWM_Pin, PWM_Freq1, PWM_DutyCycle1); + +#else +#if USING_MICROS_RESOLUTION + // Or using period in microsecs resolution + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1, PWM_DutyCycle1); +#else + // Or using period in millisecs resolution + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000, PWM_DutyCycle1); +#endif +#endif + + delay(10000); + + ISR_PWM.deleteChannel((unsigned) channelNum); + + Serial.print(F("Using PWM Freq = ")); Serial.print(PWM_Freq2); Serial.print(F(", PWM DutyCycle = ")); Serial.println(PWM_DutyCycle2); + +#if USING_PWM_FREQUENCY + + // You can use this with PWM_Freq in Hz + channelNum = ISR_PWM.setPWM(PWM_Pin, PWM_Freq2, PWM_DutyCycle2); + +#else +#if USING_MICROS_RESOLUTION + // Or using period in microsecs resolution + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period2, PWM_DutyCycle2); +#else + // Or using period in millisecs resolution + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period2 / 1000, PWM_DutyCycle2); +#endif +#endif + + delay(10000); + + ISR_PWM.deleteChannel((unsigned) channelNum); +} diff --git a/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino b/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino new file mode 100644 index 0000000..50c63b7 --- /dev/null +++ b/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino @@ -0,0 +1,254 @@ +/**************************************************************************************************************************** + ISR_Modify_PWM.ino + For AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/AVR_Slow_PWM + Licensed under MIT license + + TCNTx - Timer/Counter Register. The actual timer value is stored here. + OCRx - Output Compare Register + ICRx - Input Capture Register (only for 16bit timer) + TIMSKx - Timer/Counter Interrupt Mask Register. To enable/disable timer interrupts. + TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt. + + Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by + unsigned long miliseconds), you just consume only one RP2040-based timer and avoid conflicting with other cores' tasks. + 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. + This important feature is absolutely necessary for mission-critical tasks. +*****************************************************************************************************************************/ + +#if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \ + defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) || defined(ARDUINO_AVR_ETHERNET) || \ + defined(ARDUINO_AVR_FIO) || defined(ARDUINO_AVR_BT) || defined(ARDUINO_AVR_LILYPAD) || defined(ARDUINO_AVR_PRO) || \ + defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(ARDUINO_AVR_FEATHER328P) || \ + defined(ARDUINO_AVR_METRO) || defined(ARDUINO_AVR_PROTRINKET5) || defined(ARDUINO_AVR_PROTRINKET3) || defined(ARDUINO_AVR_PROTRINKET5FTDI) || \ + defined(ARDUINO_AVR_PROTRINKET3FTDI) ) + #define USE_TIMER_1 true + #warning Using Timer1 +#else + #define USE_TIMER_3 true + #warning Using Timer3 +#endif + +// These define's must be placed at the beginning before #include "ESP32_PWM.h" +// _PWM_LOGLEVEL_ from 0 to 4 +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. +#define _PWM_LOGLEVEL_ 3 + +#define USING_MICROS_RESOLUTION true //false + +#include "AVR_Slow_PWM.h" + +#define LED_OFF HIGH +#define LED_ON LOW + +#ifndef LED_BUILTIN + #define LED_BUILTIN 13 +#endif + +#ifndef LED_BLUE + #define LED_BLUE 10 +#endif + +#ifndef LED_RED + #define LED_RED 11 +#endif + +// Don't change these numbers to make higher Timer freq. System can hang +#define HW_TIMER_INTERVAL_MS 0.1f +#define HW_TIMER_INTERVAL_FREQ 10000L + +volatile uint32_t startMicros = 0; + +// Init AVR_Slow_PWM, each can service 16 different ISR-based PWM channels +AVR_Slow_PWM ISR_PWM; + +////////////////////////////////////////////////////// + +void TimerHandler() +{ + ISR_PWM.run(); +} + +////////////////////////////////////////////////////// + +#define USING_PWM_FREQUENCY false //true + +////////////////////////////////////////////////////// + +// You can assign pins here. Be carefull to select good pin to use or crash +uint32_t PWM_Pin = LED_BUILTIN; + +// You can assign any interval for any timer here, in Hz +double PWM_Freq1 = 1.0f; +// You can assign any interval for any timer here, in Hz +double PWM_Freq2 = 2.0f; + +// You can assign any interval for any timer here, in microseconds +uint32_t PWM_Period1 = 1000000 / PWM_Freq1; +// You can assign any interval for any timer here, in microseconds +uint32_t PWM_Period2 = 1000000 / PWM_Freq2; + +// You can assign any duty_cycle for any PWM here, from 0-100 +uint32_t PWM_DutyCycle1 = 10; +// You can assign any duty_cycle for any PWM here, from 0-100 +uint32_t PWM_DutyCycle2 = 90; + +// Channel number used to identify associated channel +int channelNum; + +//////////////////////////////////////////////// + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + delay(2000); + + Serial.print(F("\nStarting ISR_Modify_PWM on ")); Serial.println(BOARD_NAME); + Serial.println(AVR_SLOW_PWM_VERSION); + Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz")); + + // Timer0 is used for micros(), millis(), delay(), etc and can't be used + // Select Timer 1-2 for UNO, 1-5 for MEGA, 1,3,4 for 16u4/32u4 + // Timer 2 is 8-bit timer, only for higher frequency + // Timer 4 of 16u4 and 32u4 is 8/10-bit timer, only for higher frequency + +#if USING_HW_TIMER_INTERVAL_MS + +#if USE_TIMER_1 + + ITimer1.init(); + + // Using ATmega328 used in UNO => 16MHz CPU clock , + + if (ITimer1.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler)) + { + Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer1. Select another freq. or timer")); + +#elif USE_TIMER_3 + + ITimer3.init(); + + if (ITimer3.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler)) + { + Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer3. Select another freq. or timer")); + +#endif + +#else + +#if USE_TIMER_1 + + ITimer1.init(); + + // Using ATmega328 used in UNO => 16MHz CPU clock , + + if (ITimer1.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler)) + { + Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer1. Select another freq. or timer")); + +#elif USE_TIMER_3 + + ITimer3.init(); + + if (ITimer3.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler)) + { + Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros()); + } + else + Serial.println(F("Can't set ITimer3. Select another freq. or timer")); + +#endif + +#endif + + // Just to demonstrate, don't use too many ISR Timers if not absolutely necessary + // You can use up to 16 timer for each ISR_PWM + //void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle + // , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr) + Serial.print(F("Using PWM Freq = ")); Serial.print(PWM_Freq1); Serial.print(F(", PWM DutyCycle = ")); Serial.println(PWM_DutyCycle1); + +#if USING_PWM_FREQUENCY + + // You can use this with PWM_Freq in Hz + ISR_PWM.setPWM(PWM_Pin, PWM_Freq1, PWM_DutyCycle1); + +#else +#if USING_MICROS_RESOLUTION + // Or using period in microsecs resolution + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1, PWM_DutyCycle1); +#else + // Or using period in millisecs resolution + channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000, PWM_DutyCycle1); +#endif +#endif +} + +//////////////////////////////////////////////// + +void changePWM() +{ + static uint8_t count = 1; + + double PWM_Freq; + uint32_t PWM_DutyCycle; + + if (count++ % 2) + { + PWM_Freq = PWM_Freq2; + PWM_DutyCycle = PWM_DutyCycle2; + } + else + { + PWM_Freq = PWM_Freq1; + PWM_DutyCycle = PWM_DutyCycle1; + } + + // You can use this with PWM_Freq in Hz + if (!ISR_PWM.modifyPWMChannel(channelNum, PWM_Pin, PWM_Freq, PWM_DutyCycle)) + { + Serial.print(F("modifyPWMChannel error for PWM_Period")); + } +} + +//////////////////////////////////////////////// + +void changingPWM() +{ + static unsigned long changingPWM_timeout = 0; + + static unsigned long current_millis; + +#define CHANGING_PWM_INTERVAL 10000L + + current_millis = millis(); + + // changePWM every CHANGING_PWM_INTERVAL (10) seconds. + if ( (current_millis > changingPWM_timeout) ) + { + if (changingPWM_timeout > 0) + changePWM(); + + changingPWM_timeout = current_millis + CHANGING_PWM_INTERVAL; + } +} + +//////////////////////////////////////////////// + +void loop() +{ + changingPWM(); +} diff --git a/keywords.txt b/keywords.txt index 045c0b1..16f7840 100644 --- a/keywords.txt +++ b/keywords.txt @@ -33,6 +33,8 @@ init KEYWORD2 run KEYWORD2 setPWM KEYWORD2 setPWM_Period KEYWORD2 +modifyPWMChannel KEYWORD2 +modifyPWMChannel_Period KEYWORD2 deleteChannel KEYWORD2 restartChannel KEYWORD2 isEnabled KEYWORD2 diff --git a/library.json b/library.json index e4836e8..e074106 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "name": "AVR_Slow_PWM", - "version": "1.0.0", + "version": "1.1.0", "keywords": "timing, device, control, timer, interrupt, hardware, isr, isr-based, hardware-timer, mission-critical, accuracy, precise, non-blocking, avr, mega-2560, nano, uno, leonardo, 32u4, 16u4, at-mega", - "description": "This library enables you to use ISR-based PWM channels on AVR-based boards, such as Mega-2560, UNO,Nano, Leonardo, etc., to create and output PWM any GPIO pin. It now supports 16 ISR-based PWM channels, while consuming only 1 Hardware Timer. PWM channel interval can be very long (ulong microsecs / millisecs). The most important feature is they're ISR-based PWM channels, supporting lower PWM frequencies with suitable accuracy. Their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These ISR-based PWMs, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWM using millis() or micros(). That's necessary if you need to control devices requiring high precision", + "description": "This library enables you to use ISR-based PWM channels on AVR-based boards, such as Mega-2560, UNO,Nano, Leonardo, etc., to create and output PWM any GPIO pin. It now supports 16 ISR-based PWM channels, while consuming only 1 Hardware Timer. PWM channel interval can be very long (ulong microsecs / millisecs). The most important feature is they're ISR-based PWM channels, supporting lower PWM frequencies with suitable accuracy. Their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These ISR-based PWMs, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWM using millis() or micros(). That's necessary if you need to control devices requiring high precision. Now you can change the PWM settings on-the-fly", "authors": { "name": "Khoi Hoang", diff --git a/library.properties b/library.properties index f9f74d9..eb430aa 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=AVR_Slow_PWM -version=1.0.0 +version=1.1.0 author=Khoi Hoang maintainer=Khoi Hoang sentence=This library enables you to use ISR-based PWM channels on AVR-based boards, such as Mega-2560, UNO,Nano, Leonardo, etc., to create and output PWM any GPIO pin. -paragraph= It now supports 16 ISR-based PWM channels, while consuming only 1 Hardware Timer. PWM channel interval can be very long (ulong microsecs / millisecs). The most important feature is they're ISR-based PWM channels, supporting lower PWM frequencies with suitable accuracy. Their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These ISR-based PWMs, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWM using millis() or micros(). That's necessary if you need to control devices requiring high precision +paragraph= It now supports 16 ISR-based PWM channels, while consuming only 1 Hardware Timer. PWM channel interval can be very long (ulong microsecs / millisecs). The most important feature is they're ISR-based PWM channels, supporting lower PWM frequencies with suitable accuracy. Their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These ISR-based PWMs, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWM using millis() or micros(). That's necessary if you need to control devices requiring high precision. Now you can change the PWM settings on-the-fly category=Device Control url=https://github.com/khoih-prog/AVR_Slow_PWM architectures=avr diff --git a/platformio/platformio.ini b/platformio/platformio.ini index b0e85ab..b4df438 100644 --- a/platformio/platformio.ini +++ b/platformio/platformio.ini @@ -8,23 +8,17 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html - [platformio] ; ============================================================ ; chose environment: -; ESP8266 -; ESP32 -; SAMD -; DUE -; NRF52 -; STM32 +; MEGAAVR +; AVR +; TEENSY + ; ============================================================ -;default_envs = ESP8266 -;default_envs = ESP32 -;default_envs = SAMD -default_envs = DUE -;default_envs = NRF52 -;default_envs = STM32 +;default_envs = MEGAAVR +default_envs = AVR +;default_envs = TEENSY [env] ; ============================================================ @@ -39,207 +33,66 @@ upload_speed = 921600 ; Checks for the compatibility with frameworks and dev/platforms lib_compat_mode = strict -lib_deps = +lib_deps = ${common.lib_deps} build_flags = -; set your debug output (default=Serial) -; -D DEBUG_ESP_PORT=Serial -; comment the folowing line to enable WiFi debugging -; -D NDEBUG - -[env:DUE] -platform = atmelsam -board = due - -; change microcontroller -board_build.mcu = at91sam3x8e -; change MCU frequency -board_build.f_cpu = 84000000L - - -[env:ESP8266] -platform = espressif8266 +[env:MEGAAVR] +platform = atmelmegaavr framework = arduino -; ============================================================ -; Board configuration -; choose your board by uncommenting one of the following lines -; ============================================================ -;board = gen4iod -;board = huzzah -;board = oak -;board = esp_wroom_02 -;board = espduino -;board = espectro -;board = espino -;board = espresso_lite_v1 -;board = espresso_lite_v2 -;board = esp12e -;board = esp01_1m -;board = esp01 -;board = esp07 -;board = esp8285 -;board = heltec_wifi_kit_8 -;board = inventone -;board = nodemcu -board = nodemcuv2 -;board = modwifi -;board = phoenix_v1 -;board = phoenix_v2 -;board = sparkfunBlynk -;board = thing -;board = thingdev -;board = esp210 -;board = espinotee -;board = d1 -;board = d1_mini -;board = d1_mini_lite -;board = d1_mini_pro -;board = wifi_slot -;board = wifiduino -;board = wifinfo -;board = wio_link -;board = wio_node -;board = xinabox_cw01 -;board = esp32doit-devkit-v1 - -[env:ESP32] -platform = espressif32 -framework = arduino, espidf -; ============================================================ -; Board configuration -; choose your board by uncommenting one of the following lines -; ============================================================ -;board = esp32cam -;board = alksesp32 -;board = featheresp32 -;board = espea32 -;board = bpi-bit -;board = d-duino-32 -board = esp32doit-devkit-v1 -;board = pocket_32 -;board = fm-devkit -;board = pico32 -;board = esp32-evb -;board = esp32-gateway -;board = esp32-pro -;board = esp32-poe -;board = oroca_edubot -;board = onehorse32dev -;board = lopy -;board = lopy4 -;board = wesp32 -;board = esp32thing -;board = sparkfun_lora_gateway_1-channel -;board = ttgo-lora32-v1 -;board = ttgo-t-beam -;board = turta_iot_node -;board = lolin_d32 -;board = lolin_d32_pro -;board = lolin32 -;board = wemosbat -;board = widora-air -;board = xinabox_cw02 -;board = iotbusio -;board = iotbusproteus -;board = nina_w10 -[env:SAMD] -platform = atmelsam -framework = arduino ; ============================================================ ; Choose your board by uncommenting one of the following lines ; ============================================================ -; ============================================================ -; Board configuration Adafruit SAMD -; ============================================================ - -;board = adafruit_feather_m0 -;board = adafruit_feather_m0_express -;board = adafruit_metro_m0 -;board = adafruit_circuitplayground_m0 -;board = adafruit_gemma_m0 -;board = adafruit_trinket_m0 -;board = adafruit_itsybitsy_m0 -;board = adafruit_pirkey -;board = adafruit_hallowing -;board = adafruit_crickit_m0 -;board = adafruit_metro_m4 -;board = adafruit_grandcentral_m4 -board = adafruit_itsybitsy_m4 -;board = adafruit_feather_m4 -;board = adafruit_trellis_m4 -;board = adafruit_pyportal_m4 -;board = adafruit_pyportal_m4_titano -;board = adafruit_pybadge_m4 -;board = adafruit_metro_m4_airliftlite -;board = adafruit_pygamer_m4 -;board = adafruit_pygamer_advance_m4 -;board = adafruit_pybadge_airlift_m4 -;board = adafruit_monster_m4sk -;board = adafruit_hallowing_m4 - -; ============================================================ -; Board configuration Arduino SAMD and SAM -; ============================================================ - -;board = arduino_zero_edbg -;board = arduino_zero_native -;board = mkr1000 -;board = mkrzero -;board = mkrwifi1010 -;board = nano_33_iot -;board = mkrfox1200 -;board = mkrwan1300 -;board = mkrwan1310 -;board = mkrgsm1400 -;board = mkrnb1500 -;board = mkrvidor4000 -;board = adafruit_circuitplayground_m0 -;board = mzero_pro_bl_dbg -;board = mzero_pro_bl -;board = mzero_bl -;board = tian -;board = tian_cons -;board = arduino_due_x_dbg -;board = arduino_due_x ; ============================================================ -; Board configuration Seeeduino SAMD +; Board configuration MEGAAVR ; ============================================================ -;board = seeed_wio_terminal -;board = Seeed_femto_m0 -;board = seeed_XIAO_m0 -;board = Wio_Lite_MG126 -;board = WioGPS -;board = zero -;board = rolawan -;board = seeed_grove_ui_wireless +;board = uno2018 +;board = nona4809 +;board = uno_wifi_rev2 +;board = nano_every - -[env:NRF52] -platform = nordicnrf52 +[env:AVR] +platform = atmelavr framework = arduino -; ============================================================ -; Board configuration Adafruit nRF52 -; choose your board by uncommenting one of the following lines -; ============================================================ -;board = feather52832 -board = feather52840 -;board = feather52840sense -;board = itsybitsy52840 -;board = cplaynrf52840 -;board = cluenrf52840 -;board = metro52840 -;board = pca10056 -;board = particle_xenon -;board = mdbt50qrx -;board = ninab302 -;board = ninab112 -[env:STM32] -platform = ststm32 +; ============================================================ +; Board configuration AVR +; ============================================================ + +;board = yun +;board = uno +;board = diecimila +;board = nano +;board = nanoatmega328 +;board = mega +board = megaatmega2560 +;board = megaADK +;board = leonardo +;board = leonardoeth +;board = micro +;board = esplora +;board = mini +;board = ethernet +;board = fio +;board = bt +;board = LilyPadUSB +;board = lilypad +;board = pro +;board = atmegang +;board = robotControl +;board = robotMotor +;board = gemma +;board = circuitplay32u4cat +;board = yunmini +;board = chiwawa +;board = one +;board = unowifi + +[env:TEENSY] +platform = teensy framework = arduino ; ============================================================ @@ -247,106 +100,15 @@ framework = arduino ; ============================================================ ; ============================================================ -; Board configuration Nucleo-144 +; Board configuration MEGAAVR ; ============================================================ -;board = nucleo_f207zg -;board = nucleo_f429zi -;board = nucleo_f746zg -;board = nucleo_f756zg -;board = nucleo_f767zi -;board = nucleo_h743zi -;board = nucleo_l496zg -;board = nucleo_l496zg-p -;board = nucleo_l4r5zi -;board = nucleo_l4r5zi-p - -; ============================================================ -; Board configuration Nucleo-64 -; ============================================================ - -;board = nucleo_f030r8 -;board = nucleo_f072rb - -;board = nucleo_f091rc -;board = nucleo_f103rb -;board = nucleo_f302r8 -;board = nucleo_f303re -;board = nucleo_f401re -;board = nucleo_f411re -;board = nucleo_f446re -;board = nucleo_g071rb -;board = nucleo_g431rb -;board = nucleo_g474re -;board = nucleo_l053r8 -;board = nucleo_l073rz -;board = nucleo_l152re -;board = nucleo_l433rc_p -;board = nucleo_l452re -;board = nucleo_l452re-p -;board = nucleo_l476rg -;board = pnucleo_wb55rg - -; ============================================================ -; Board configuration Nucleo-32 -; ============================================================ - -;board = nucleo_f031k6 -;board = nucleo_l031k6 -;board = nucleo_l412kb -;board = nucleo_l432lc -;board = nucleo_f303k8 -;board = nucleo_g431kb - -; ============================================================ -; Board configuration Discovery Boards -; ============================================================ - -;board = disco_f030r8 -;board = disco_f072rb -;board = disco_f030r8 -;board = disco_f100rb -;board = disco_f407vg -;board = disco_f413zh -;board = disco_f746ng -;board = disco_g0316 -;board = disco_l475vg_iot -;board = disco_f072cz-lrwan1 - -; ============================================================ -; Board configuration STM32MP1 Boards -; ============================================================ - -;board = stm32mp157a-dk1 -;board = stm32mp157c-dk2 - -; ============================================================ -; Board configuration Generic Boards -; ============================================================ - -;board = bluepill_f103c6 -;board = bluepill_f103c8 -;board = blackpill_f103c8 -;board = stm32f103cx -;board = stm32f103rx -;board = stm32f103tx -;board = stm32f103vx -;board = stm32f103zx -;board = stm32f103zet6 -;board = maplemini_f103cb -;board = blackpill_f303cc -;board = black_f407ve -;board = black_f407vg -;board = black_f407ze -;board = black_f407zg -;board = blue_f407ve_mini -;board = blackpill_f401cc -;board = blackpill_f411ce -;board = coreboard_f401rc -;board = feather_f405 - -; ============================================================ -; Board configuration Many more Boards to be filled -; ============================================================ - - +;board = teensy2 +;board = teensy2pp +;board = teensy30 +;board = teensy31 +;board = teensylc +;board = teensy35 +;board = teensy36 +;board = teensy40 +;board = teensy41 diff --git a/src/AVR_Slow_PWM.h b/src/AVR_Slow_PWM.h index af28aca..b6b607d 100644 --- a/src/AVR_Slow_PWM.h +++ b/src/AVR_Slow_PWM.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -99,7 +100,7 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.0.0") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.1.0") #endif #ifndef _PWM_LOGLEVEL_ diff --git a/src/AVR_Slow_PWM.hpp b/src/AVR_Slow_PWM.hpp index 19f9829..b6b05f5 100644 --- a/src/AVR_Slow_PWM.hpp +++ b/src/AVR_Slow_PWM.hpp @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly ****************************************************************************************************************************/ #pragma once diff --git a/src/AVR_Slow_PWM_ISR.h b/src/AVR_Slow_PWM_ISR.h index c3b27c9..c7e4e29 100644 --- a/src/AVR_Slow_PWM_ISR.h +++ b/src/AVR_Slow_PWM_ISR.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -99,7 +100,7 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.0.0") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.1.0") #endif #ifndef _PWM_LOGLEVEL_ @@ -151,42 +152,71 @@ class AVR_Slow_PWM_ISR ////////////////////////////////////////////////////////////////// // PWM - void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr, + // Return the channelNum if OK, -1 if error + int setPWM(uint32_t pin, double frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr, timer_callback StopCallback = nullptr) { uint32_t period = 0; - if ( ( frequency != 0 ) && ( frequency <= 1000 ) ) + if ( ( frequency != 0 ) && ( frequency <= 1000 ) ) { #if USING_MICROS_RESOLUTION // period in us - period = 1000000 / frequency; + period = 1000000.0f / frequency; #else // period in ms - period = 1000 / frequency; + period = 1000.0f / frequency; #endif } else { - PWM_LOGERROR(F("Error: Invalid frequency, max is 500Hz")); + PWM_LOGERROR("Error: Invalid frequency, max is 1000Hz"); + + return -1; } - setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); + return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); } + // period in us + // Return the channelNum if OK, -1 if error + int setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, + timer_callback StopCallback = nullptr) + { + return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); + } + + ////////////////////////////////////////////////////////////////// + + // low level function to modify a PWM channel + // returns the true on success or false on failure + bool modifyPWMChannel(unsigned channelNum, uint32_t pin, double frequency, uint32_t dutycycle) + { + uint32_t period = 0; + + if ( ( frequency > 0 ) && ( frequency <= 1000 ) ) + { #if USING_MICROS_RESOLUTION - //period in us - void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) + // period in us + period = 1000000.0f / frequency; #else - // PWM - //period in ms - void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) -#endif - { - setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); - } + // period in ms + period = 1000.0f / frequency; +#endif + } + else + { + PWM_LOGERROR("Error: Invalid frequency, max is 1000Hz"); + return false; + } + + return modifyPWMChannel_Period(channelNum, pin, period, dutycycle); + } + + ////////////////////////////////////////////////////////////////// + + //period in us + bool modifyPWMChannel_Period(unsigned channelNum, uint32_t pin, uint32_t period, uint32_t dutycycle); ////////////////////////////////////////////////////////////////// diff --git a/src/AVR_Slow_PWM_ISR.hpp b/src/AVR_Slow_PWM_ISR.hpp index fc55176..8ca3457 100644 --- a/src/AVR_Slow_PWM_ISR.hpp +++ b/src/AVR_Slow_PWM_ISR.hpp @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -179,6 +180,8 @@ int AVR_Slow_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t du digitalWrite(pin, HIGH); PWM[channelNum].pinHigh = true; + PWM[channelNum].prevTime = timeNow(); + PWM[channelNum].callbackStart = cbStartFunc; PWM[channelNum].callbackStop = cbStopFunc; @@ -194,6 +197,44 @@ int AVR_Slow_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t du return channelNum; } +/////////////////////////////////////////////////// + +bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(unsigned channelNum, uint32_t pin, uint32_t period, uint32_t dutycycle) +{ + // Invalid input, such as period = 0, etc + if ( (period == 0) || (dutycycle > 100) ) + { + PWM_LOGERROR("Error: Invalid period or dutycycle"); + return false; + } + + if (channelNum > MAX_NUMBER_CHANNELS) + { + PWM_LOGERROR("Error: channelNum > MAX_NUMBER_CHANNELS"); + return false; + } + + if (PWM[channelNum].pin != pin) + { + PWM_LOGERROR("Error: channelNum and pin mismatched"); + return false; + } + + PWM[channelNum].period = period; + PWM[channelNum].onTime = ( period * dutycycle ) / 100; + + digitalWrite(pin, HIGH); + PWM[channelNum].pinHigh = true; + + PWM[channelNum].prevTime = timeNow(); + + PWM_LOGINFO0("Channel : "); PWM_LOGINFO0(channelNum); PWM_LOGINFO0("\tPeriod : "); PWM_LOGINFO0(PWM[channelNum].period); + PWM_LOGINFO0("\t\tOnTime : "); PWM_LOGINFO0(PWM[channelNum].onTime); PWM_LOGINFO0("\tStart_Time : "); PWM_LOGINFOLN0(PWM[channelNum].prevTime); + + return true; +} + + /////////////////////////////////////////////////// void AVR_Slow_PWM_ISR::deleteChannel(unsigned channelNum) diff --git a/src/PWM_Generic_Debug.h b/src/PWM_Generic_Debug.h index 506ef75..2707989 100644 --- a/src/PWM_Generic_Debug.h +++ b/src/PWM_Generic_Debug.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once diff --git a/src_cpp/AVR_Slow_PWM.cpp b/src_cpp/AVR_Slow_PWM.cpp index 574e726..47ff51a 100644 --- a/src_cpp/AVR_Slow_PWM.cpp +++ b/src_cpp/AVR_Slow_PWM.cpp @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly ****************************************************************************************************************************/ #ifndef _PWM_LOGLEVEL_ diff --git a/src_cpp/AVR_Slow_PWM.h b/src_cpp/AVR_Slow_PWM.h index 70f7306..7c19d90 100644 --- a/src_cpp/AVR_Slow_PWM.h +++ b/src_cpp/AVR_Slow_PWM.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -99,7 +100,7 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.0.0") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.1.0") #endif #ifndef _PWM_LOGLEVEL_ diff --git a/src_cpp/AVR_Slow_PWM_ISR.cpp b/src_cpp/AVR_Slow_PWM_ISR.cpp index d5bfc8a..5cb5ead 100644 --- a/src_cpp/AVR_Slow_PWM_ISR.cpp +++ b/src_cpp/AVR_Slow_PWM_ISR.cpp @@ -18,17 +18,18 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ -#include - #include "AVR_Slow_PWM_ISR.h" +#include + /////////////////////////////////////////////////// @@ -176,6 +177,8 @@ int AVR_Slow_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t du digitalWrite(pin, HIGH); PWM[channelNum].pinHigh = true; + PWM[channelNum].prevTime = timeNow(); + PWM[channelNum].callbackStart = cbStartFunc; PWM[channelNum].callbackStop = cbStopFunc; @@ -191,6 +194,44 @@ int AVR_Slow_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t du return channelNum; } +/////////////////////////////////////////////////// + +bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(unsigned channelNum, uint32_t pin, uint32_t period, uint32_t dutycycle) +{ + // Invalid input, such as period = 0, etc + if ( (period == 0) || (dutycycle > 100) ) + { + PWM_LOGERROR("Error: Invalid period or dutycycle"); + return false; + } + + if (channelNum > MAX_NUMBER_CHANNELS) + { + PWM_LOGERROR("Error: channelNum > MAX_NUMBER_CHANNELS"); + return false; + } + + if (PWM[channelNum].pin != pin) + { + PWM_LOGERROR("Error: channelNum and pin mismatched"); + return false; + } + + PWM[channelNum].period = period; + PWM[channelNum].onTime = ( period * dutycycle ) / 100; + + digitalWrite(pin, HIGH); + PWM[channelNum].pinHigh = true; + + PWM[channelNum].prevTime = timeNow(); + + PWM_LOGINFO0("Channel : "); PWM_LOGINFO0(channelNum); PWM_LOGINFO0("\tPeriod : "); PWM_LOGINFO0(PWM[channelNum].period); + PWM_LOGINFO0("\t\tOnTime : "); PWM_LOGINFO0(PWM[channelNum].onTime); PWM_LOGINFO0("\tStart_Time : "); PWM_LOGINFOLN0(PWM[channelNum].prevTime); + + return true; +} + + /////////////////////////////////////////////////// void AVR_Slow_PWM_ISR::deleteChannel(unsigned channelNum) diff --git a/src_cpp/AVR_Slow_PWM_ISR.h b/src_cpp/AVR_Slow_PWM_ISR.h index 659028c..3233b3c 100644 --- a/src_cpp/AVR_Slow_PWM_ISR.h +++ b/src_cpp/AVR_Slow_PWM_ISR.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -99,7 +100,7 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.0.0") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.1.0") #endif #ifndef _PWM_LOGLEVEL_ @@ -151,42 +152,71 @@ class AVR_Slow_PWM_ISR ////////////////////////////////////////////////////////////////// // PWM - void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr, + // Return the channelNum if OK, -1 if error + int setPWM(uint32_t pin, double frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr, timer_callback StopCallback = nullptr) { uint32_t period = 0; - if ( ( frequency != 0 ) && ( frequency <= 1000 ) ) + if ( ( frequency != 0 ) && ( frequency <= 1000 ) ) { #if USING_MICROS_RESOLUTION // period in us - period = 1000000 / frequency; + period = 1000000.0f / frequency; #else // period in ms - period = 1000 / frequency; + period = 1000.0f / frequency; #endif } else { - PWM_LOGERROR(F("Error: Invalid frequency, max is 500Hz")); + PWM_LOGERROR("Error: Invalid frequency, max is 1000Hz"); + + return -1; } - setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); + return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); } + // period in us + // Return the channelNum if OK, -1 if error + int setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, + timer_callback StopCallback = nullptr) + { + return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); + } + + ////////////////////////////////////////////////////////////////// + + // low level function to modify a PWM channel + // returns the true on success or false on failure + bool modifyPWMChannel(unsigned channelNum, uint32_t pin, double frequency, uint32_t dutycycle) + { + uint32_t period = 0; + + if ( ( frequency > 0 ) && ( frequency <= 1000 ) ) + { #if USING_MICROS_RESOLUTION - //period in us - void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) + // period in us + period = 1000000.0f / frequency; #else - // PWM - //period in ms - void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) -#endif - { - setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); - } + // period in ms + period = 1000.0f / frequency; +#endif + } + else + { + PWM_LOGERROR("Error: Invalid frequency, max is 1000Hz"); + return false; + } + + return modifyPWMChannel_Period(channelNum, pin, period, dutycycle); + } + + ////////////////////////////////////////////////////////////////// + + //period in us + bool modifyPWMChannel_Period(unsigned channelNum, uint32_t pin, uint32_t period, uint32_t dutycycle); ////////////////////////////////////////////////////////////////// @@ -263,7 +293,6 @@ class AVR_Slow_PWM_ISR }; - #endif // AVR_SLOW_PWM_ISR_H diff --git a/src_cpp/PWM_Generic_Debug.h b/src_cpp/PWM_Generic_Debug.h index 506ef75..2707989 100644 --- a/src_cpp/PWM_Generic_Debug.h +++ b/src_cpp/PWM_Generic_Debug.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once diff --git a/src_h/AVR_Slow_PWM.h b/src_h/AVR_Slow_PWM.h index af28aca..b6b607d 100644 --- a/src_h/AVR_Slow_PWM.h +++ b/src_h/AVR_Slow_PWM.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -99,7 +100,7 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.0.0") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.1.0") #endif #ifndef _PWM_LOGLEVEL_ diff --git a/src_h/AVR_Slow_PWM.hpp b/src_h/AVR_Slow_PWM.hpp index f714394..b6b05f5 100644 --- a/src_h/AVR_Slow_PWM.hpp +++ b/src_h/AVR_Slow_PWM.hpp @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly ****************************************************************************************************************************/ #pragma once @@ -30,8 +31,8 @@ #ifndef AVR_SLOW_PWM_HPP #define AVR_SLOW_PWM_HPP -#ifndef TIMER_INTERRUPT_DEBUG - #define TIMER_INTERRUPT_DEBUG 0 +#ifndef _PWM_LOGLEVEL_ + #define _PWM_LOGLEVEL_ 0 #endif void TimerInterrupt::init(int8_t timer) diff --git a/src_h/AVR_Slow_PWM_ISR.h b/src_h/AVR_Slow_PWM_ISR.h index c3b27c9..c7e4e29 100644 --- a/src_h/AVR_Slow_PWM_ISR.h +++ b/src_h/AVR_Slow_PWM_ISR.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -99,7 +100,7 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.0.0") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.1.0") #endif #ifndef _PWM_LOGLEVEL_ @@ -151,42 +152,71 @@ class AVR_Slow_PWM_ISR ////////////////////////////////////////////////////////////////// // PWM - void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr, + // Return the channelNum if OK, -1 if error + int setPWM(uint32_t pin, double frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr, timer_callback StopCallback = nullptr) { uint32_t period = 0; - if ( ( frequency != 0 ) && ( frequency <= 1000 ) ) + if ( ( frequency != 0 ) && ( frequency <= 1000 ) ) { #if USING_MICROS_RESOLUTION // period in us - period = 1000000 / frequency; + period = 1000000.0f / frequency; #else // period in ms - period = 1000 / frequency; + period = 1000.0f / frequency; #endif } else { - PWM_LOGERROR(F("Error: Invalid frequency, max is 500Hz")); + PWM_LOGERROR("Error: Invalid frequency, max is 1000Hz"); + + return -1; } - setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); + return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); } + // period in us + // Return the channelNum if OK, -1 if error + int setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, + timer_callback StopCallback = nullptr) + { + return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); + } + + ////////////////////////////////////////////////////////////////// + + // low level function to modify a PWM channel + // returns the true on success or false on failure + bool modifyPWMChannel(unsigned channelNum, uint32_t pin, double frequency, uint32_t dutycycle) + { + uint32_t period = 0; + + if ( ( frequency > 0 ) && ( frequency <= 1000 ) ) + { #if USING_MICROS_RESOLUTION - //period in us - void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) + // period in us + period = 1000000.0f / frequency; #else - // PWM - //period in ms - void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) -#endif - { - setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); - } + // period in ms + period = 1000.0f / frequency; +#endif + } + else + { + PWM_LOGERROR("Error: Invalid frequency, max is 1000Hz"); + return false; + } + + return modifyPWMChannel_Period(channelNum, pin, period, dutycycle); + } + + ////////////////////////////////////////////////////////////////// + + //period in us + bool modifyPWMChannel_Period(unsigned channelNum, uint32_t pin, uint32_t period, uint32_t dutycycle); ////////////////////////////////////////////////////////////////// diff --git a/src_h/AVR_Slow_PWM_ISR.hpp b/src_h/AVR_Slow_PWM_ISR.hpp index fc55176..8ca3457 100644 --- a/src_h/AVR_Slow_PWM_ISR.hpp +++ b/src_h/AVR_Slow_PWM_ISR.hpp @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once @@ -179,6 +180,8 @@ int AVR_Slow_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t du digitalWrite(pin, HIGH); PWM[channelNum].pinHigh = true; + PWM[channelNum].prevTime = timeNow(); + PWM[channelNum].callbackStart = cbStartFunc; PWM[channelNum].callbackStop = cbStopFunc; @@ -194,6 +197,44 @@ int AVR_Slow_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t du return channelNum; } +/////////////////////////////////////////////////// + +bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(unsigned channelNum, uint32_t pin, uint32_t period, uint32_t dutycycle) +{ + // Invalid input, such as period = 0, etc + if ( (period == 0) || (dutycycle > 100) ) + { + PWM_LOGERROR("Error: Invalid period or dutycycle"); + return false; + } + + if (channelNum > MAX_NUMBER_CHANNELS) + { + PWM_LOGERROR("Error: channelNum > MAX_NUMBER_CHANNELS"); + return false; + } + + if (PWM[channelNum].pin != pin) + { + PWM_LOGERROR("Error: channelNum and pin mismatched"); + return false; + } + + PWM[channelNum].period = period; + PWM[channelNum].onTime = ( period * dutycycle ) / 100; + + digitalWrite(pin, HIGH); + PWM[channelNum].pinHigh = true; + + PWM[channelNum].prevTime = timeNow(); + + PWM_LOGINFO0("Channel : "); PWM_LOGINFO0(channelNum); PWM_LOGINFO0("\tPeriod : "); PWM_LOGINFO0(PWM[channelNum].period); + PWM_LOGINFO0("\t\tOnTime : "); PWM_LOGINFO0(PWM[channelNum].onTime); PWM_LOGINFO0("\tStart_Time : "); PWM_LOGINFOLN0(PWM[channelNum].prevTime); + + return true; +} + + /////////////////////////////////////////////////// void AVR_Slow_PWM_ISR::deleteChannel(unsigned channelNum) diff --git a/src_h/PWM_Generic_Debug.h b/src_h/PWM_Generic_Debug.h index 506ef75..2707989 100644 --- a/src_h/PWM_Generic_Debug.h +++ b/src_h/PWM_Generic_Debug.h @@ -18,11 +18,12 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.0.0 + Version: 1.1.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/09/2021 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly *****************************************************************************************************************************/ #pragma once