From 42d95b18776a96b132c945f74a0a5c973f852349 Mon Sep 17 00:00:00 2001 From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com> Date: Tue, 1 Feb 2022 21:29:51 -0500 Subject: [PATCH] v1.2.3 to replace `double` with `float` ### Releases v1.2.2 1. Use `float` for `DutyCycle` and `Freq`, `uint32_t` for `period`. 2. Optimize code by not calculation in ISR --- README.md | 90 +++++++------------ changelog.md | 6 ++ .../ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino | 6 +- .../ISR_8_PWMs_Array_Complex.ino | 14 +-- .../ISR_8_PWMs_Array_Simple.ino | 4 +- .../ISR_Changing_PWM/ISR_Changing_PWM.ino | 12 +-- examples/ISR_Modify_PWM/ISR_Modify_PWM.ino | 12 +-- .../multiFileProject/multiFileProject.ino | 4 +- library.json | 2 +- library.properties | 2 +- src/AVR_Slow_PWM.h | 3 +- src/AVR_Slow_PWM.hpp | 11 +-- src/AVR_Slow_PWM_ISR.h | 3 +- src/AVR_Slow_PWM_ISR.hpp | 40 +++++---- src/AVR_Slow_PWM_ISR_Impl.h | 38 ++++---- src/AVR_Slow_PWM_Impl.h | 3 +- src/PWM_Generic_Debug.h | 3 +- 17 files changed, 122 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index 995de10..285d97a 100644 --- a/README.md +++ b/README.md @@ -320,7 +320,7 @@ void setup() #define USING_MICROS_RESOLUTION true //false // Default is true, uncomment to false -//#define CHANGING_PWM_END_OF_CYCLE false +//#define CHANGING_PWM_END_OF_CYCLE false // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error #include "AVR_Slow_PWM.h" @@ -394,9 +394,9 @@ typedef struct irqCallback irqCallbackStartFunc; irqCallback irqCallbackStopFunc; - double PWM_Freq; + float PWM_Freq; - double PWM_DutyCycle; + float PWM_DutyCycle; uint32_t deltaMicrosStart; uint32_t previousMicrosStart; @@ -424,19 +424,19 @@ volatile unsigned long previousMicrosStop [] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // You can assign any interval for any timer here, in Microseconds -double PWM_Period[] = +uint32_t PWM_Period[] = { - 1000.0, 500.0, 333.333, 250.0, 200.0, 166.667, 142.857, 125.0 + 1000, 500, 333, 250, 200, 167, 143, 125 }; // You can assign any interval for any timer here, in Hz -double PWM_Freq[] = +float PWM_Freq[] = { 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 -double PWM_DutyCycle[] = +float PWM_DutyCycle[] = { 5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0 }; @@ -746,7 +746,7 @@ void setup() curISR_PWM_Data[i].previousMicrosStart = startMicros; //ISR_PWM.setInterval(curISR_PWM_Data[i].PWM_Period, curISR_PWM_Data[i].irqCallbackStartFunc); - //void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle + //void setPWM(uint32_t pin, float frequency, float dutycycle // , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr) // You can use this with PWM_Freq in Hz @@ -793,7 +793,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.2.1 +AVR_Slow_PWM v1.2.2 CPU Frequency = 16 MHz [PWM] T3 [PWM] Freq * 1000 = 10000000.00 @@ -837,8 +837,8 @@ PWM Channel : 7, prog Period (ms): 125.00, actual (uS) : 125192, prog DutyCycle The following is the sample terminal output when running example [**ISR_8_PWMs_Array**](examples/ISR_8_PWMs_Array) on **AVR Mega2560/ADK** to demonstrate how to use multiple PWM channels with simple callback functions. ``` -Starting ISR_8_PWMs_Array_Complex on Arduino AVR Mega2560/ADK -AVR_Slow_PWM v1.2.1 +Starting ISR_8_PWMs_Array on Arduino AVR Mega2560/ADK +AVR_Slow_PWM v1.2.2 CPU Frequency = 16 MHz [PWM] T3 [PWM] Freq * 1000 = 10000000.00 @@ -846,33 +846,15 @@ CPU Frequency = 16 MHz [PWM] OCR = 1599 , preScalerIndex = 1 [PWM] OK in loop => _OCR = 1599 [PWM] _preScalerIndex = 1 , preScalerDiv = 1 -Starting ITimer3 OK, micros() = 2024104 -Channel : 0 Period : 1000000 OnTime : 50000 Start_Time : 2024988 -Channel : 1 Period : 500000 OnTime : 50000 Start_Time : 2024988 -Channel : 2 Period : 333333 OnTime : 66666 Start_Time : 2024988 -Channel : 3 Period : 250000 OnTime : 62500 Start_Time : 2024988 -Channel : 4 Period : 200000 OnTime : 60000 Start_Time : 2024988 -Channel : 5 Period : 166666 OnTime : 58333 Start_Time : 2024988 -Channel : 6 Period : 142857 OnTime : 57142 Start_Time : 2024988 -Channel : 7 Period : 125000 OnTime : 56250 Start_Time : 2024988 -SimpleTimer (us): 2000, us : 12070388, Dus : 10045444 -PWM Channel : 0, prog Period (ms): 1000.00, actual (uS) : 1000000, prog DutyCycle : 5, actual : 4.98 -PWM Channel : 1, prog Period (ms): 500.00, actual (uS) : 499996, prog DutyCycle : 10, actual : 10.00 -PWM Channel : 2, prog Period (ms): 333.33, actual (uS) : 333396, prog DutyCycle : 20, actual : 19.98 -PWM Channel : 3, prog Period (ms): 250.00, actual (uS) : 250196, prog DutyCycle : 25, actual : 24.94 -PWM Channel : 4, prog Period (ms): 200.00, actual (uS) : 200192, prog DutyCycle : 30, actual : 29.88 -PWM Channel : 5, prog Period (ms): 166.67, actual (uS) : 166792, prog DutyCycle : 35, actual : 34.90 -PWM Channel : 6, prog Period (ms): 142.86, actual (uS) : 142988, prog DutyCycle : 40, actual : 39.87 -PWM Channel : 7, prog Period (ms): 125.00, actual (uS) : 125196, prog DutyCycle : 45, actual : 44.89 -SimpleTimer (us): 2000, us : 22144772, Dus : 10074384 -PWM Channel : 0, prog Period (ms): 1000.00, actual (uS) : 1000000, prog DutyCycle : 5, actual : 5.00 -PWM Channel : 1, prog Period (ms): 500.00, actual (uS) : 499996, prog DutyCycle : 10, actual : 10.00 -PWM Channel : 2, prog Period (ms): 333.33, actual (uS) : 333396, prog DutyCycle : 20, actual : 19.98 -PWM Channel : 3, prog Period (ms): 250.00, actual (uS) : 250196, prog DutyCycle : 25, actual : 24.94 -PWM Channel : 4, prog Period (ms): 200.00, actual (uS) : 200196, prog DutyCycle : 30, actual : 29.87 -PWM Channel : 5, prog Period (ms): 166.67, actual (uS) : 166792, prog DutyCycle : 35, actual : 34.90 -PWM Channel : 6, prog Period (ms): 142.86, actual (uS) : 143016, prog DutyCycle : 40, actual : 39.87 -PWM Channel : 7, prog Period (ms): 125.00, actual (uS) : 125008, prog DutyCycle : 45, actual : 44.96 +Starting ITimer3 OK, micros() = 2023732 +Channel : 0 Period : 1000000 OnTime : 50000 Start_Time : 2031420 +Channel : 1 Period : 500000 OnTime : 50000 Start_Time : 2042728 +Channel : 2 Period : 333333 OnTime : 66666 Start_Time : 2054724 +Channel : 3 Period : 250000 OnTime : 62500 Start_Time : 2067932 +Channel : 4 Period : 200000 OnTime : 60000 Start_Time : 2084232 +Channel : 5 Period : 166666 OnTime : 58333 Start_Time : 2115432 +Channel : 6 Period : 142857 OnTime : 57142 Start_Time : 3075536 +Channel : 7 Period : 125000 OnTime : 56250 Start_Time : 4221280 ``` --- @@ -883,7 +865,7 @@ The following is the sample terminal output when running example [**ISR_8_PWMs_A ``` Starting ISR_8_PWMs_Array_Complex on Arduino AVR UNO, Nano, etc. -AVR_Slow_PWM v1.2.1 +AVR_Slow_PWM v1.2.2 CPU Frequency = 16 MHz [PWM] T1 [PWM] Freq * 1000 = 10000000.00 @@ -929,7 +911,7 @@ The following is the sample terminal output when running example [ISR_Modify_PWM ``` Starting ISR_Modify_PWM on Arduino AVR Mega2560/ADK -AVR_Slow_PWM v1.2.1 +AVR_Slow_PWM v1.2.2 CPU Frequency = 16 MHz [PWM] T3 [PWM] Freq * 1000 = 10000000.00 @@ -937,12 +919,8 @@ CPU Frequency = 16 MHz [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 +Starting ITimer3 OK, micros() = 2023764 +Using PWM Freq = 1.00, PWM DutyCycle = 50.00 ``` --- @@ -953,7 +931,7 @@ The following is the sample terminal output when running example [ISR_Changing_P ``` Starting ISR_Changing_PWM on Arduino AVR Mega2560/ADK -AVR_Slow_PWM v1.2.1 +AVR_Slow_PWM v1.2.2 CPU Frequency = 16 MHz [PWM] T3 [PWM] Freq * 1000 = 10000000.00 @@ -961,15 +939,13 @@ CPU Frequency = 16 MHz [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 +Starting ITimer3 OK, micros() = 2023844 +Using PWM Freq = 1.00, PWM DutyCycle = 50.00 +Using PWM Freq = 2.00, PWM DutyCycle = 90.00 +Using PWM Freq = 1.00, PWM DutyCycle = 50.00 +Using PWM Freq = 2.00, PWM DutyCycle = 90.00 +Using PWM Freq = 1.00, PWM DutyCycle = 50.00 +Using PWM Freq = 2.00, PWM DutyCycle = 90.00 ``` --- @@ -1018,7 +994,7 @@ Submit issues to: [AVR_Slow_PWM issues](https://github.com/khoih-prog/AVR_Slow_P 3. Add functions to modify PWM settings on-the-fly 4. Fix `multiple-definitions` linker error. Drop `src_cpp` and `src_h` directories 5. Add example [multiFileProject](examples/multiFileProject) to demo for multiple-file project -6. Improve accuracy by using `double`, instead of `uint32_t` for `dutycycle`, `period` +6. Improve accuracy by using `float`, instead of `uint32_t` for `dutycycle` 7. Optimize library code by using `reference-passing` instead of `value-passing` 8. DutyCycle to be optionally updated at the end current PWM period instead of immediately. diff --git a/changelog.md b/changelog.md index dbb8a6e..fc51ebe 100644 --- a/changelog.md +++ b/changelog.md @@ -12,6 +12,7 @@ ## Table of Contents * [Changelog](#changelog) + * [Releases v1.2.2](#releases-v122) * [Releases v1.2.1](#releases-v121) * [Releases v1.2.0](#releases-v120) * [Releases v1.1.0](#releases-v110) @@ -22,6 +23,11 @@ ## Changelog +### Releases v1.2.2 + +1. Use `float` for `DutyCycle` and `Freq`, `uint32_t` for `period`. +2. Optimize code by not calculation in ISR + ### Releases v1.2.1 1. DutyCycle to be optionally updated at the end current PWM period instead of immediately. Check [DutyCycle to be updated at the end current PWM period #2](https://github.com/khoih-prog/ESP8266_PWM/issues/2) 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 ebf6840..69af5cc 100644 --- a/examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino +++ b/examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino @@ -101,13 +101,13 @@ 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 -double PWM_Freq[] = +float PWM_Freq[] = { 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 -double PWM_DutyCycle[] = +float PWM_DutyCycle[] = { 5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0 }; @@ -238,7 +238,7 @@ void setup() // You can use up to 16 timer for each ISR_PWM for (uint16_t i = 0; i < NUMBER_ISR_PWMS; i++) { - //void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle + //void setPWM(uint32_t pin, float frequency, float dutycycle // , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr) // You can use this with PWM_Freq in Hz 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 1e4b57d..cd271c8 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 @@ -114,9 +114,9 @@ typedef struct irqCallback irqCallbackStartFunc; irqCallback irqCallbackStopFunc; - double PWM_Freq; + float PWM_Freq; - double PWM_DutyCycle; + float PWM_DutyCycle; uint32_t deltaMicrosStart; uint32_t previousMicrosStart; @@ -144,19 +144,19 @@ volatile unsigned long previousMicrosStop [] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // You can assign any interval for any timer here, in Microseconds -double PWM_Period[] = +uint32_t PWM_Period[] = { - 1000.0, 500.0, 333.333, 250.0, 200.0, 166.667, 142.857, 125.0 + 1000, 500, 333, 250, 200, 167, 143, 125 }; // You can assign any interval for any timer here, in Hz -double PWM_Freq[] = +float PWM_Freq[] = { 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 -double PWM_DutyCycle[] = +float PWM_DutyCycle[] = { 5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0 }; @@ -466,7 +466,7 @@ void setup() curISR_PWM_Data[i].previousMicrosStart = startMicros; //ISR_PWM.setInterval(curISR_PWM_Data[i].PWM_Period, curISR_PWM_Data[i].irqCallbackStartFunc); - //void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle + //void setPWM(uint32_t pin, float frequency, float dutycycle // , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr) // You can use this with PWM_Freq in Hz 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 e29c829..c450e43 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 @@ -101,13 +101,13 @@ 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 -double PWM_Freq[] = +float PWM_Freq[] = { 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 -double PWM_DutyCycle[] = +float PWM_DutyCycle[] = { 5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0 }; diff --git a/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino b/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino index a5cb645..e370b58 100644 --- a/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino +++ b/examples/ISR_Changing_PWM/ISR_Changing_PWM.ino @@ -86,19 +86,19 @@ void TimerHandler() uint32_t PWM_Pin = LED_BUILTIN; // You can assign any interval for any timer here, in Hz -double PWM_Freq1 = 1.0f; +float PWM_Freq1 = 1.0f; // You can assign any interval for any timer here, in Hz -double PWM_Freq2 = 2.0f; +float PWM_Freq2 = 2.0f; // You can assign any interval for any timer here, in microseconds -double PWM_Period1 = 1000000.0 / PWM_Freq1; +uint32_t PWM_Period1 = 1000000 / PWM_Freq1; // You can assign any interval for any timer here, in microseconds -double PWM_Period2 = 1000000.0 / PWM_Freq2; +uint32_t PWM_Period2 = 1000000 / PWM_Freq2; // You can assign any duty_cycle for any PWM here, from 0-100 -double PWM_DutyCycle1 = 50.0; +float PWM_DutyCycle1 = 50.0; // You can assign any duty_cycle for any PWM here, from 0-100 -double PWM_DutyCycle2 = 90.0; +float PWM_DutyCycle2 = 90.0; // Channel number used to identify associated channel int channelNum; diff --git a/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino b/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino index 6d3e9ff..c2119c2 100644 --- a/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino +++ b/examples/ISR_Modify_PWM/ISR_Modify_PWM.ino @@ -86,19 +86,19 @@ void TimerHandler() uint32_t PWM_Pin = LED_BUILTIN; // You can assign any interval for any timer here, in Hz -double PWM_Freq1 = 1.0f; +float PWM_Freq1 = 1.0f; // You can assign any interval for any timer here, in Hz -double PWM_Freq2 = 2.0f; +float PWM_Freq2 = 2.0f; // You can assign any interval for any timer here, in microseconds -double PWM_Period1 = 1000000.0 / PWM_Freq1; +uint32_t PWM_Period1 = 1000000 / PWM_Freq1; // You can assign any interval for any timer here, in microseconds -double PWM_Period2 = 1000000.0 / PWM_Freq2; +uint32_t PWM_Period2 = 1000000 / PWM_Freq2; // You can assign any duty_cycle for any PWM here, from 0-100 -double PWM_DutyCycle1 = 10.0; +float PWM_DutyCycle1 = 50.0; // You can assign any duty_cycle for any PWM here, from 0-100 -double PWM_DutyCycle2 = 90.0; +float PWM_DutyCycle2 = 90.0; // Channel number used to identify associated channel int channelNum; diff --git a/examples/multiFileProject/multiFileProject.ino b/examples/multiFileProject/multiFileProject.ino index c3add11..bc3852b 100644 --- a/examples/multiFileProject/multiFileProject.ino +++ b/examples/multiFileProject/multiFileProject.ino @@ -23,8 +23,8 @@ #warning Using Timer3 #endif -#define AVR_SLOW_PWM_VERSION_MIN_TARGET F("AVR_Slow_PWM v1.2.0") -#define AVR_SLOW_PWM_VERSION_MIN 1002000 +#define AVR_SLOW_PWM_VERSION_MIN_TARGET F("AVR_Slow_PWM v1.2.2") +#define AVR_SLOW_PWM_VERSION_MIN 1002002 #include "multiFileProject.h" diff --git a/library.json b/library.json index 1672b1a..e189972 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "AVR_Slow_PWM", - "version": "1.2.1", + "version": "1.2.2", "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. Now you can change the PWM settings on-the-fly", "authors": diff --git a/library.properties b/library.properties index 48e5c4e..98c553d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AVR_Slow_PWM -version=1.2.1 +version=1.2.2 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. diff --git a/src/AVR_Slow_PWM.h b/src/AVR_Slow_PWM.h index c8b7793..667cfa9 100644 --- a/src/AVR_Slow_PWM.h +++ b/src/AVR_Slow_PWM.h @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code *****************************************************************************************************************************/ #pragma once diff --git a/src/AVR_Slow_PWM.hpp b/src/AVR_Slow_PWM.hpp index bad12b8..2ca432b 100644 --- a/src/AVR_Slow_PWM.hpp +++ b/src/AVR_Slow_PWM.hpp @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code *****************************************************************************************************************************/ #pragma once @@ -102,13 +103,13 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.2.1") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.2.2") #define AVR_SLOW_PWM_VERSION_MAJOR 1 #define AVR_SLOW_PWM_VERSION_MINOR 2 - #define AVR_SLOW_PWM_VERSION_PATCH 1 + #define AVR_SLOW_PWM_VERSION_PATCH 2 - #define AVR_SLOW_PWM_VERSION_INT 1002001 + #define AVR_SLOW_PWM_VERSION_INT 1002002 #endif #ifndef _PWM_LOGLEVEL_ @@ -189,7 +190,7 @@ class TimerInterrupt uint32_t _OCRValue; uint32_t _OCRValueRemaining; volatile long _toggle_count; - double _frequency; + float _frequency; void* _callback; // pointer to the callback function void* _params; // function parameter diff --git a/src/AVR_Slow_PWM_ISR.h b/src/AVR_Slow_PWM_ISR.h index b046a68..7484830 100644 --- a/src/AVR_Slow_PWM_ISR.h +++ b/src/AVR_Slow_PWM_ISR.h @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code *****************************************************************************************************************************/ #pragma once diff --git a/src/AVR_Slow_PWM_ISR.hpp b/src/AVR_Slow_PWM_ISR.hpp index 4ba9c4e..cd25e8a 100644 --- a/src/AVR_Slow_PWM_ISR.hpp +++ b/src/AVR_Slow_PWM_ISR.hpp @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code *****************************************************************************************************************************/ #pragma once @@ -102,13 +103,13 @@ #endif #ifndef AVR_SLOW_PWM_VERSION - #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.2.1") + #define AVR_SLOW_PWM_VERSION F("AVR_Slow_PWM v1.2.2") #define AVR_SLOW_PWM_VERSION_MAJOR 1 #define AVR_SLOW_PWM_VERSION_MINOR 2 - #define AVR_SLOW_PWM_VERSION_PATCH 1 + #define AVR_SLOW_PWM_VERSION_PATCH 2 - #define AVR_SLOW_PWM_VERSION_INT 1002001 + #define AVR_SLOW_PWM_VERSION_INT 1002002 #endif #ifndef _PWM_LOGLEVEL_ @@ -166,19 +167,19 @@ class AVR_Slow_PWM_ISR ////////////////////////////////////////////////////////////////// // PWM // Return the channelNum if OK, -1 if error - int8_t setPWM(const uint32_t& pin, const double& frequency, const double& dutycycle, timer_callback StartCallback = nullptr, + int8_t setPWM(const uint32_t& pin, const float& frequency, const float& dutycycle, timer_callback StartCallback = nullptr, timer_callback StopCallback = nullptr) { - double period = 0.0; + uint32_t period = 0; if ( ( frequency > 0.0 ) && ( frequency <= 1000.0 ) ) { #if USING_MICROS_RESOLUTION // period in us - period = 1000000.0f / frequency; + period = (uint32_t) (1000000.0f / frequency); #else // period in ms - period = 1000.0f / frequency; + period = (uint32_t) (1000.0f / frequency); #endif } else @@ -193,8 +194,8 @@ class AVR_Slow_PWM_ISR // period in us // Return the channelNum if OK, -1 if error - int8_t setPWM_Period(const uint32_t& pin, const double& period, const double& dutycycle, timer_callback StartCallback = nullptr, - timer_callback StopCallback = nullptr) + int8_t setPWM_Period(const uint32_t& pin, const uint32_t& period, const float& dutycycle, + timer_callback StartCallback = nullptr, timer_callback StopCallback = nullptr) { return setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback); } @@ -203,18 +204,18 @@ class AVR_Slow_PWM_ISR // low level function to modify a PWM channel // returns the true on success or false on failure - bool modifyPWMChannel(const uint8_t& channelNum, const uint32_t& pin, const double& frequency, const double& dutycycle) + bool modifyPWMChannel(const uint8_t& channelNum, const uint32_t& pin, const float& frequency, const float& dutycycle) { - double period = 0.0; + uint32_t period = 0; if ( ( frequency > 0.0 ) && ( frequency <= 1000.0 ) ) { #if USING_MICROS_RESOLUTION // period in us - period = 1000000.0f / frequency; + period = (uint32_t) (1000000.0f / frequency); #else // period in ms - period = 1000.0f / frequency; + period = (uint32_t) (1000.0f / frequency); #endif } else @@ -229,7 +230,7 @@ class AVR_Slow_PWM_ISR ////////////////////////////////////////////////////////////////// //period in us - bool modifyPWMChannel_Period(const uint8_t& channelNum, const uint32_t& pin, const double& period, const double& dutycycle); + bool modifyPWMChannel_Period(const uint8_t& channelNum, const uint32_t& pin, const uint32_t& period, const float& dutycycle); ////////////////////////////////////////////////////////////////// @@ -271,7 +272,7 @@ class AVR_Slow_PWM_ISR // low level function to initialize and enable a new PWM channel // returns the PWM channel number (channelNum) on success or // -1 on failure (f == NULL) or no free PWM channels - int8_t setupPWMChannel(const uint32_t& pin, const double& period, const double& dutycycle, void* cbStartFunc = nullptr, void* cbStopFunc = nullptr); + int8_t setupPWMChannel(const uint32_t& pin, const uint32_t& period, const float& dutycycle, void* cbStartFunc = nullptr, void* cbStopFunc = nullptr); // find the first available slot int8_t findFirstFreeSlot(); @@ -284,7 +285,7 @@ class AVR_Slow_PWM_ISR /////////////////////////////////// uint32_t prevTime; // value returned by the micros() or millis() function in the previous run() call - double period; // period value, in us / ms + uint32_t period; // period value, in us / ms uint32_t onTime; // onTime value, ( period * dutyCycle / 100 ) us / ms void* callbackStart; // pointer to the callback function when PWM pulse starts (HIGH) @@ -299,8 +300,9 @@ class AVR_Slow_PWM_ISR bool enabled; // true if enabled // New from v1.2.1 - double newPeriod; // period value, in us / ms - double newDutyCycle; // from 0.00 to 100.00, double precision + uint32_t newPeriod; // period value, in us / ms + uint32_t newOnTime; // onTime value, ( period * dutyCycle / 100 ) us / ms + float newDutyCycle; // from 0.00 to 100.00, float precision ////// } PWM_t; diff --git a/src/AVR_Slow_PWM_ISR_Impl.h b/src/AVR_Slow_PWM_ISR_Impl.h index c024145..fbf4bde 100644 --- a/src/AVR_Slow_PWM_ISR_Impl.h +++ b/src/AVR_Slow_PWM_ISR_Impl.h @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code *****************************************************************************************************************************/ #pragma once @@ -126,7 +127,7 @@ void AVR_Slow_PWM_ISR::run() PWM[channelNum].period = PWM[channelNum].newPeriod; PWM[channelNum].newPeriod = 0; - PWM[channelNum].onTime = ( PWM[channelNum].period * PWM[channelNum].newDutyCycle ) / 100; + PWM[channelNum].onTime = PWM[channelNum].newOnTime; } #endif } @@ -162,12 +163,12 @@ int8_t AVR_Slow_PWM_ISR::findFirstFreeSlot() /////////////////////////////////////////////////// -int8_t AVR_Slow_PWM_ISR::setupPWMChannel(const uint32_t& pin, const double& period, const double& dutycycle, void* cbStartFunc, void* cbStopFunc) +int8_t AVR_Slow_PWM_ISR::setupPWMChannel(const uint32_t& pin, const uint32_t& period, const float& dutycycle, void* cbStartFunc, void* cbStopFunc) { int channelNum; // Invalid input, such as period = 0, etc - if ( (period <= 0.0) || (dutycycle < 0.0) || (dutycycle > 100.0) ) + if ( (period == 0) || (dutycycle < 0.0) || (dutycycle > 100.0) ) { PWM_LOGERROR(F("Error: Invalid period or dutycycle")); return -1; @@ -202,10 +203,10 @@ int8_t AVR_Slow_PWM_ISR::setupPWMChannel(const uint32_t& pin, const double& peri PWM[channelNum].callbackStart = cbStartFunc; PWM[channelNum].callbackStop = cbStopFunc; - PWM_LOGDEBUG0("Channel : "); PWM_LOGDEBUG0(channelNum); - PWM_LOGDEBUG0("\t Period : "); PWM_LOGDEBUG0(PWM[channelNum].period); - PWM_LOGDEBUG0("\t\tOnTime : "); PWM_LOGDEBUG0(PWM[channelNum].onTime); - PWM_LOGDEBUG0("\tStart_Time : "); PWM_LOGDEBUGLN0(PWM[channelNum].prevTime); + PWM_LOGINFO0("Channel : "); PWM_LOGINFO0(channelNum); + PWM_LOGINFO0("\t Period : "); PWM_LOGINFO0(PWM[channelNum].period); + PWM_LOGINFO0("\t\tOnTime : "); PWM_LOGINFO0(PWM[channelNum].onTime); + PWM_LOGINFO0("\tStart_Time : "); PWM_LOGINFOLN0(PWM[channelNum].prevTime); numChannels++; @@ -216,10 +217,10 @@ int8_t AVR_Slow_PWM_ISR::setupPWMChannel(const uint32_t& pin, const double& peri /////////////////////////////////////////////////// -bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(const uint8_t& channelNum, const uint32_t& pin, const double& period, const double& dutycycle) +bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(const uint8_t& channelNum, const uint32_t& pin, const uint32_t& period, const float& dutycycle) { // Invalid input, such as period = 0, etc - if ( (period <= 0.0) || (dutycycle < 0.0) || (dutycycle > 100.0) ) + if ( (period == 0) || (dutycycle < 0.0) || (dutycycle > 100.0) ) { PWM_LOGERROR("Error: Invalid period or dutycycle"); return false; @@ -241,11 +242,12 @@ bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(const uint8_t& channelNum, const PWM[channelNum].newPeriod = period; PWM[channelNum].newDutyCycle = dutycycle; + PWM[channelNum].newOnTime = ( period * dutycycle ) / 100; - PWM_LOGDEBUG0("Channel : "); PWM_LOGDEBUG0(channelNum); - PWM_LOGDEBUG0("\tNew Period : "); PWM_LOGDEBUG0(PWM[channelNum].newPeriod); - PWM_LOGDEBUG0("\t\tOnTime : "); PWM_LOGDEBUG0(( period * dutycycle ) / 100); - PWM_LOGDEBUG0("\tStart_Time : "); PWM_LOGDEBUGLN0(PWM[channelNum].prevTime); + PWM_LOGINFO0("Channel : "); PWM_LOGINFO0(channelNum); + PWM_LOGINFO0("\tNew Period : "); PWM_LOGINFO0(PWM[channelNum].newPeriod); + PWM_LOGINFO0("\t\tOnTime : "); PWM_LOGINFO0(PWM[channelNum].newOnTime); + PWM_LOGINFO0("\tStart_Time : "); PWM_LOGINFOLN0(PWM[channelNum].prevTime); #else @@ -258,10 +260,10 @@ bool AVR_Slow_PWM_ISR::modifyPWMChannel_Period(const uint8_t& channelNum, const PWM[channelNum].prevTime = timeNow(); - PWM_LOGDEBUG0("Channel : "); PWM_LOGDEBUG0(channelNum); - PWM_LOGDEBUG0("\t Period : "); PWM_LOGDEBUG0(PWM[channelNum].period); - PWM_LOGDEBUG0("\t\tOnTime : "); PWM_LOGDEBUG0(PWM[channelNum].onTime); - PWM_LOGDEBUG0("\tStart_Time : "); PWM_LOGDEBUGLN0(PWM[channelNum].prevTime); + PWM_LOGINFO0("Channel : "); PWM_LOGINFO0(channelNum); + PWM_LOGINFO0("\t Period : "); PWM_LOGINFO0(PWM[channelNum].period); + PWM_LOGINFO0("\t\tOnTime : "); PWM_LOGINFO0(PWM[channelNum].onTime); + PWM_LOGINFO0("\tStart_Time : "); PWM_LOGINFOLN0(PWM[channelNum].prevTime); #endif diff --git a/src/AVR_Slow_PWM_Impl.h b/src/AVR_Slow_PWM_Impl.h index 688c306..90a7b3f 100644 --- a/src/AVR_Slow_PWM_Impl.h +++ b/src/AVR_Slow_PWM_Impl.h @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code ****************************************************************************************************************************/ #pragma once diff --git a/src/PWM_Generic_Debug.h b/src/PWM_Generic_Debug.h index e5b1eb8..5da16ad 100644 --- a/src/PWM_Generic_Debug.h +++ b/src/PWM_Generic_Debug.h @@ -18,7 +18,7 @@ Therefore, their executions are not blocked by bad-behaving functions / tasks. This important feature is absolutely necessary for mission-critical tasks. - Version: 1.2.1 + Version: 1.2.2 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -26,6 +26,7 @@ 1.1.0 K Hoang 10/11/2021 Add functions to modify PWM settings on-the-fly 1.2.0 K Hoang 29/01/2022 Fix multiple-definitions linker error. Improve accuracy 1.2.1 K Hoang 30/01/2022 DutyCycle to be updated at the end current PWM period + 1.2.2 K Hoang 01/02/2022 Use float for DutyCycle and Freq, uint32_t for period. Optimize code *****************************************************************************************************************************/ #pragma once