From d5cab00656d9093fccc93241c27e0b671747cd92 Mon Sep 17 00:00:00 2001 From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:40:56 -0500 Subject: [PATCH] v1.2.0 to optimize speed and add `PWM_SpeedTest` ### Releases v1.2.0 1. Optimize speed with new `setPWM_DCPercentageInt_manual` function to improve speed almost 85% compared to `setPWM_DCPercentage_manual` 2. Add example [PWM_SpeedTest](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_SpeedTest) to demo the better speed of new `setPWM_DCPercentageInt_manual` function 3. Improve `README.md` so that links can be used in other sites, such as PIO --- README.md | 114 +++++++++----- changelog.md | 9 +- examples/PWM_SpeedTest/PWM_SpeedTest.ino | 182 +++++++++++++++++++++++ keywords.txt | 1 + library.json | 2 +- library.properties | 2 +- src/AVR_PWM.h | 22 ++- src/PWM_Generic_Debug.h | 3 +- 8 files changed, 288 insertions(+), 47 deletions(-) create mode 100644 examples/PWM_SpeedTest/PWM_SpeedTest.ino diff --git a/README.md b/README.md index abd0aad..fe8768b 100644 --- a/README.md +++ b/README.md @@ -38,15 +38,16 @@ * [3. Set or change PWM frequency or dutyCycle](#3-set-or-change-PWM-frequency-or-dutyCycle) * [4. Set or change PWM frequency and dutyCycle manually and efficiently in waveform creation](#4-Set-or-change-PWM-frequency-and-dutyCycle-manually-and-efficiently-in-waveform-creation) * [Examples](#examples) - * [ 1. PWM_Basic](examples/PWM_Basic) - * [ 2. PWM_DynamicDutyCycle](examples/PWM_DynamicDutyCycle) - * [ 3. PWM_DynamicDutyCycle_Int](examples/PWM_DynamicDutyCycle_Int) - * [ 4. PWM_DynamicFreq](examples/PWM_DynamicFreq) - * [ 5. PWM_Multi](examples/PWM_Multi) - * [ 6. PWM_MultiChannel](examples/PWM_MultiChannel) - * [ 7. PWM_Waveform](examples/PWM_Waveform) - * [ 8. PWM_StepperControl](examples/PWM_StepperControl) **New** - * [ 9. PWM_manual](examples/PWM_manual) **New** + * [ 1. PWM_Basic](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Basic) + * [ 2. PWM_DynamicDutyCycle](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicDutyCycle) + * [ 3. PWM_DynamicDutyCycle_Int](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicDutyCycle_Int) + * [ 4. PWM_DynamicFreq](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicFreq) + * [ 5. PWM_Multi](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Multi) + * [ 6. PWM_MultiChannel](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_MultiChannel) + * [ 7. PWM_Waveform](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Waveform) + * [ 8. PWM_StepperControl](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_StepperControl) **New** + * [ 9. PWM_manual](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_manual) **New** + * [10. PWM_SpeedTest](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_SpeedTest) **New** * [Example PWM_Multi](#example-PWM_Multi) * [Debug Terminal Output Samples](#debug-terminal-output-samples) * [1. PWM_DynamicDutyCycle on Arduino AVR Mega2560](#1-PWM_DynamicDutyCycle-on-Arduino-AVR-Mega2560) @@ -56,6 +57,7 @@ * [5. PWM_Waveform on Arduino AVR ATMega32U4](#5-PWM_Waveform-on-Arduino-AVR-ATMega32U4) * [6. PWM_Waveform on Arduino AVR Nano](#6-PWM_Waveform-on-Arduino-AVR-Nano) * [7. PWM_manual on Arduino AVR Nano](#7-PWM_manual-on-Arduino-AVR-Nano) + * [8. PWM_SpeedTest on Arduino AVR Nano](#8-PWM_SpeedTest-on-Arduino-AVR-Nano) * [Debug](#debug) * [Troubleshooting](#troubleshooting) * [Issues](#issues) @@ -101,7 +103,7 @@ This important feature is absolutely necessary for mission-critical tasks. These New efficient `setPWM_manual()` function enables waveform creation using PWM. -The [**PWM_Multi**](examples/PWM_Multi) example will demonstrate the usage of multichannel PWM using multiple Hardware-PWM blocks (slices). The 4 independent Hardware-PWM channels are used **to control 4 different PWM outputs**, with totally independent frequencies and dutycycles on `Arduino Mega`. +The [**PWM_Multi**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Multi) example will demonstrate the usage of multichannel PWM using multiple Hardware-PWM blocks (slices). The 4 independent Hardware-PWM channels are used **to control 4 different PWM outputs**, with totally independent frequencies and dutycycles on `Arduino Mega`. Being hardware-based PWM, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet or Blynk services. @@ -349,40 +351,52 @@ Need to call only once for each pin PWM_Instance->setPWM(PWM_Pins, frequency, dutyCycle); ``` -after that, if just changing `dutyCycle` / `level`, use +after that, if just changing `dutyCycle` / `level`, use the **fastest** ```cpp // For 50.0f dutycycle +// 8415-8423ns new_level = 50.0f * PWM_Instance->getPWMPeriod() / 100.0f ; PWM_Instance->setPWM_manual(PWM_Pins, new_level); ``` -or better and much easier to use +or better and much easier to use, but `slowest` ```cpp +// 52745ns new_DCPercentage = 50.0f; PWM_Instance->setPWM_DCPercentage_manual(PWM_Pins, new_DCPercentage); ``` +or the `faster` + +```cpp +// dutycyclePercent = 0-65535 == 0-100% +// Faster, 8863ns +dutycyclePercentInt = 1 << 15; // 50% +PWM_Instance->setPWM_DCPercentageInt_manual(pinToUse, dutycyclePercentInt); +``` + --- --- ### Examples: - 1. [PWM_Basic](examples/PWM_Basic) - 2. [PWM_DynamicDutyCycle](examples/PWM_DynamicDutyCycle) - 3. [PWM_DynamicDutyCycle_Int](examples/PWM_DynamicDutyCycle_Int) - 4. [PWM_DynamicFreq](examples/PWM_DynamicFreq) - 5. [PWM_Multi](examples/PWM_Multi) - 6. [PWM_MultiChannel](examples/PWM_MultiChannel) - 7. [PWM_Waveform](examples/PWM_Waveform) - 8. [PWM_StepperControl](examples/PWM_StepperControl) **New** - 9. [PWM_manual](examples/PWM_manual) **New** + 1. [PWM_Basic](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Basic) + 2. [PWM_DynamicDutyCycle](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicDutyCycle) + 3. [PWM_DynamicDutyCycle_Int](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicDutyCycle_Int) + 4. [PWM_DynamicFreq](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicFreq) + 5. [PWM_Multi](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Multi) + 6. [PWM_MultiChannel](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_MultiChannel) + 7. [PWM_Waveform](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Waveform) + 8. [PWM_StepperControl](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_StepperControl) **New** + 9. [PWM_manual](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_manual) **New** +10. [PWM_SpeedTest](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_SpeedTest) **New** --- --- -### Example [PWM_Multi](examples/PWM_Multi) +### Example [PWM_Multi](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Multi) https://github.com/khoih-prog/AVR_PWM/blob/22230c236f4eaf3c4b4ee35f2008e78349acdf11/examples/PWM_Multi/PWM_Multi.ino#L60-L176 @@ -394,12 +408,12 @@ https://github.com/khoih-prog/AVR_PWM/blob/22230c236f4eaf3c4b4ee35f2008e78349acd ### 1. PWM_DynamicDutyCycle on Arduino AVR Mega2560 -The following is the sample terminal output when running example [PWM_DynamicDutyCycle](examples/PWM_DynamicDutyCycle) on **AVR Mega2560**, to demonstrate the ability to provide high PWM frequencies and ability to change DutyCycle `on-the-fly`. +The following is the sample terminal output when running example [PWM_DynamicDutyCycle](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicDutyCycle) on **AVR Mega2560**, to demonstrate the ability to provide high PWM frequencies and ability to change DutyCycle `on-the-fly`. ```cpp Starting PWM_DynamicDutyCycle on Arduino AVR Mega2560/ADK -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 [PWM] AVR_PWM: _dutycycle = 32767 [PWM] setPWM_Int: _dutycycle = 32767 [PWM] setPWM_Int:using TIMER4C @@ -433,11 +447,11 @@ Actual data: pin = 8, PWM DC = 9.99, PWMPeriod = 8000.00, PWM Freq (Hz) = 1000.0 ### 2. PWM_Multi on Arduino AVR Mega2560 -The following is the sample terminal output when running example [**PWM_Multi**](examples/PWM_Multi) on **AVR Mega2560**, to demonstrate the ability to provide high PWM frequencies on multiple `PWM-capable` pins. +The following is the sample terminal output when running example [**PWM_Multi**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Multi) on **AVR Mega2560**, to demonstrate the ability to provide high PWM frequencies on multiple `PWM-capable` pins. ```cpp Starting PWM_Multi on Arduino AVR Mega2560/ADK -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 ===================================================================================== Index Pin PWM_freq DutyCycle Actual Freq ===================================================================================== @@ -463,11 +477,11 @@ Actual data: pin = 12, PWM DC = 89.90, PWMPeriod = 1000.00, PWM Freq (Hz) = 8000 ### 3. PWM_DynamicFreq on Arduino AVR Mega2560 -The following is the sample terminal output when running example [**PWM_DynamicFreq**](examples/PWM_DynamicFreq) on **AVR Mega2560**, to demonstrate the ability to change dynamically PWM frequencies. +The following is the sample terminal output when running example [**PWM_DynamicFreq**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_DynamicFreq) on **AVR Mega2560**, to demonstrate the ability to change dynamically PWM frequencies. ```cpp Starting PWM_DynamicFreq on Arduino AVR Mega2560/ADK -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 [PWM] AVR_PWM: _dutycycle = 32767 [PWM] setPWM_Int: _dutycycle = 32767 [PWM] setPWM_Int:using TIMER4C @@ -512,12 +526,12 @@ Actual data: pin = 8, PWM DC = 49.75, PWMPeriod = 400.00, PWM Freq (Hz) = 20000. ### 4. PWM_Waveform on Arduino AVR Mega2560 -The following is the sample terminal output when running example [**PWM_Waveform**](examples/PWM_Waveform) on **AVR Mega2560**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation +The following is the sample terminal output when running example [**PWM_Waveform**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Waveform) on **AVR Mega2560**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation ```cpp Starting PWM_Waveform on Arduino AVR Mega2560/ADK -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 [PWM] AVR_PWM: _dutycycle = 0 [PWM] setPWM: _dutycycle = 0 [PWM] setPWM_Int: _dutycycle = 0 @@ -567,12 +581,12 @@ Actual data: pin = 8, PWM DutyCycle = 0.00, PWMPeriod = 8000.00, PWM Freq (Hz) = ### 5. PWM_Waveform on Arduino AVR ATMega32U4 -The following is the sample terminal output when running example [**PWM_Waveform**](examples/PWM_Waveform) on **ATMega32U4**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation +The following is the sample terminal output when running example [**PWM_Waveform**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Waveform) on **ATMega32U4**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation ```cpp Starting PWM_Waveform on Arduino AVR ATMega32U4 -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 [PWM] AVR_PWM: _dutycycle = 0 [PWM] setPWM: _dutycycle = 0 [PWM] setPWM_Int: _dutycycle = 0 @@ -621,12 +635,12 @@ Actual data: pin = 9, PWM DutyCycle = 0.00, PWMPeriod = 8000.00, PWM Freq (Hz) = ### 6. PWM_Waveform on Arduino AVR Nano -The following is the sample terminal output when running example [**PWM_Waveform**](examples/PWM_Waveform) on **AVR Nano**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation +The following is the sample terminal output when running example [**PWM_Waveform**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_Waveform) on **AVR Nano**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation ```cpp Starting PWM_Waveform on Arduino AVR UNO, Nano, etc. -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 [PWM] AVR_PWM: _dutycycle = 0 [PWM] setPWM: _dutycycle = 0 [PWM] setPWM_Int: _dutycycle = 0 @@ -676,12 +690,12 @@ Actual data: pin = 10, PWM DutyCycle = 0.00, PWMPeriod = 8000.00, PWM Freq (Hz) ### 7. PWM_manual on Arduino AVR Nano -The following is the sample terminal output when running example [**PWM_manual**](examples/PWM_manual) on **AVR Nano**, to demonstrate how to use the `setPWM_manual()` and `setPWM_DCPercentage_manual()` functions in wafeform creation +The following is the sample terminal output when running example [**PWM_manual**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_manual) on **AVR Nano**, to demonstrate how to use the `setPWM_manual()` and `setPWM_DCPercentage_manual()` functions in wafeform creation ```cpp Starting PWM_manual on Arduino AVR UNO, Nano, etc. -AVR_PWM v1.1.0 +AVR_PWM v1.2.0 ================================================================================================= Actual data: pin = 10, PWM DutyCycle % = 0.00, PWMPeriod = 8000.00, PWM Freq (Hz) = 1000.0000 ================================================================================================= @@ -711,7 +725,28 @@ Actual data: pin = 10, PWM DutyCycle % = 8.00, PWMPeriod = 8000.00, PWM Freq (Hz ================================================================================================= ``` +--- + +### 8. PWM_SpeedTest on Arduino AVR Nano +The following is the sample terminal output when running example [**PWM_SpeedTest**](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_SpeedTest) on **AVR Nano**, to demonstrate how to use new faster `setPWM_DCPercentageInt_manual()` function in wafeform creation, The time is `8863ns` compared to `52745ns` when using `setPWM_DCPercentage_manual()` function. The fastest is `setPWM_manual` with `8423ns`, which is to be used with pre-calculated values in array + +``` +Starting PWM_SpeedTest on Arduino AVR UNO, Nano, etc. +AVR_PWM v1.2.0 +================================================================================================= +Actual data: pin = 10, PWM DutyCycle % = 0.00, PWMPeriod = 8000.00, PWM Freq (Hz) = 1000.0000 +================================================================================================= +Average time of setPWM function USING_DC_PERCENT +ns=8863 +ns=8854 +ns=8863 +ns=8854 +ns=8863 +ns=8854 +ns=8863 +... +``` --- --- @@ -758,10 +793,13 @@ Submit issues to: [AVR_PWM issues](https://github.com/khoih-prog/AVR_PWM/issues) - [`Arduino AVR core`](https://github.com/arduino/ArduinoCore-avr) - [`Adafruit AVR core`](https://github.com/adafruit/Adafruit_Arduino_Boards) - [`Sparkfun AVR core`](https://github.com/sparkfun/Arduino_Boards) - 2. Add example [PWM_StepperControl](https://github.com/khoih-prog/AVR_PWM/examples/PWM_StepperControl) to demo how to control Stepper Motor using PWM - 3. Add example [PWM_manual](https://github.com/khoih-prog/AVR_PWM/examples/PWM_manual) to demo how to correctly use PWM to generate waveform + 2. Add example [PWM_StepperControl](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_StepperControl) to demo how to control Stepper Motor using PWM + 3. Add example [PWM_manual](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_manual) to demo how to correctly use PWM to generate waveform 4. Add function `setPWM_DCPercentage_manual()` to facilitate the setting PWM DC manually by using DCPercentage, instead of absolute DCValue depending on varying PWMPeriod 5. Catch low frequency error and use lowest permissible frequency + 6. Optimize speed with new `setPWM_DCPercentageInt_manual` function to improve speed almost 85% compared to `setPWM_DCPercentage_manual` + 7. Add example [PWM_SpeedTest](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_SpeedTest) to demo the better speed of new `setPWM_DCPercentageInt_manual` function + --- --- diff --git a/changelog.md b/changelog.md index e97c340..205b1ef 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ ## Table of Contents * [Changelog](#changelog) + * [Releases v1.2.0](#Releases-v120) * [Releases v1.1.0](#Releases-v110) * [Releases v1.0.1](#Releases-v101) * [Initial Releases v1.0.0](#Initial-Releases-v100) @@ -25,9 +26,15 @@ ## Changelog +### Releases v1.2.0 + +1. Optimize speed with new `setPWM_DCPercentageInt_manual` function to improve speed almost 85% compared to `setPWM_DCPercentage_manual` +2. Add example [PWM_SpeedTest](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_SpeedTest) to demo the better speed of new `setPWM_DCPercentageInt_manual` function +3. Improve `README.md` so that links can be used in other sites, such as PIO + ### Releases v1.1.0 -1. Add example [PWM_manual](https://github.com/khoih-prog/AVR_PWM/examples/PWM_manual) to demo how to correctly use PWM to generate waveform. Check [About DCValue in setPWM_manual #2](https://github.com/khoih-prog/AVR_PWM/discussions/2) +1. Add example [PWM_manual](https://github.com/khoih-prog/AVR_PWM/tree/main/examples/PWM_manual) to demo how to correctly use PWM to generate waveform. Check [About DCValue in setPWM_manual #2](https://github.com/khoih-prog/AVR_PWM/discussions/2) 2. Add function `setPWM_DCPercentage_manual()` to facilitate the setting PWM DC manually by using DCPercentage, instead of absolute DCValue depending on varying PWMPeriod 3. Catch low frequency error and use lowest permissible frequency diff --git a/examples/PWM_SpeedTest/PWM_SpeedTest.ino b/examples/PWM_SpeedTest/PWM_SpeedTest.ino new file mode 100644 index 0000000..3655491 --- /dev/null +++ b/examples/PWM_SpeedTest/PWM_SpeedTest.ino @@ -0,0 +1,182 @@ +/**************************************************************************************************************************** + PWM_SpeedTest.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_PWM + Licensed under MIT license + + This is pure hardware-based PWM +*****************************************************************************************************************************/ +/****************************************************************************************************************************** + // For UNO / Nano + Timer0 ( 8-bit) used by delay(), millis() and micros(), and PWM generation on pins 5 (6 not usable) + Timer1 (16-bit) used by the Servo.h library and PWM generation on pins 9 and 10 + Timer2 ( 8-bit) used by Tone() and PWM generation on pins 3 and 11 + // For Mega + Timer0 ( 8-bit) used by delay(), millis() and micros(), and PWM generation on pins 4 (13 not usable) + Timer1 (16-bit) used by the Servo.h library and PWM generation on pins 11, 12 + Timer2 ( 8-bit) used by Tone() and PWM generation on pins 9 and 10 + Timer3 (16-bit) used by PWM generation on pins 2, 3 and 5 + Timer4 (16-bit) used by PWM generation on pins 6, 7 and 8 + Timer5 (16-bit) used by PWM generation on pins 44, 45 and 46 + + //////////////////////////////////////////// + // For Mega (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 44, 45, 46) + Pin 2 => TIMER3B // PE 4 ** 2 ** PWM2 + Pin 3 => TIMER3C // PE 5 ** 3 ** PWM3 + Pin 4 => TIMER0B // PG 5 ** 4 ** PWM4 + Pin 5 => TIMER3A // PE 3 ** 5 ** PWM5 + Pin 6 => TIMER4A // PH 3 ** 6 ** PWM6 + Pin 7 => TIMER4B // PH 4 ** 7 ** PWM7 + Pin 8 => TIMER4C // PH 5 ** 8 ** PWM8 + Pin 9 => TIMER2B // PH 6 ** 9 ** PWM9 + Pin 10 => TIMER2A // PB 4 ** 10 ** PWM10 + Pin 11 => TIMER1A // PB 5 ** 11 ** PWM11 + Pin 12 => TIMER1B // PB 6 ** 12 ** PWM12 + Pin 13 => TIMER0A // PB 7 ** 13 ** PWM13 + Pin 44 => TIMER5C // PL 5 ** 44 ** D44 + Pin 45 => TIMER5B // PL 4 ** 45 ** D45 + Pin 46 => TIMER5A // PL 3 ** 46 ** D46 + //////////////////////////////////////////// + // For 32u4 (3, 5, 6, 9, 10, 11, 13) + Pin 3 => TIMER0B + Pin 5 => TIMER3A + Pin 6 => TIMER4D + Pin 9 => TIMER1A + Pin 10 => TIMER1B + Pin 11 => TIMER0A + Pin 13 => TIMER4A + //////////////////////////////////////////// + // For UNO, Nano (3, 5, 6, 9, 10, 11) + Pin 3 => TIMER2B, + Pin 5 => TIMER0B + Pin 6 => TIMER0A + Pin 9 => TIMER1A + Pin 10 => TIMER1B + Pin 11 => TIMER2(A) +******************************************************************************************************************************/ + +#define _PWM_LOGLEVEL_ 1 + +#include "AVR_PWM.h" + +#define UPDATE_INTERVAL 1000L + +#define pinToUse 10 + +AVR_PWM* PWM_Instance; + +// If frequency < 244.1406Hz => forced using 244.1406Hz +//float frequency = 60.0f; +float frequency = 1000.0f; + +// Using setPWM_DCPercentage_manual if true +//#define USING_DC_PERCENT false +#define USING_DC_PERCENT true + +#if USING_DC_PERCENT + float dutycyclePercent = 0.0f; + float DCStepPercent = 5.0f; + + // dutycyclePercentInt = dutycyclePercent * 65535 / 100 + uint16_t dutycyclePercentInt = 0; +#else + uint16_t dutycycle = 0; + uint16_t DCStep; +#endif + +uint16_t PWMPeriod; + +char dashLine[] = "================================================================================================="; + +void printPWMInfo(AVR_PWM* PWM_Instance) +{ + Serial.println(dashLine); + Serial.print("Actual data: pin = "); + Serial.print(PWM_Instance->getPin()); + Serial.print(", PWM DutyCycle % = "); + Serial.print(PWM_Instance->getActualDutyCycle()); + Serial.print(", PWMPeriod = "); + Serial.print(PWM_Instance->getPWMPeriod()); + Serial.print(", PWM Freq (Hz) = "); + Serial.println(PWM_Instance->getActualFreq(), 4); + Serial.println(dashLine); +} + +void setup() +{ + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting PWM_SpeedTest on ")); + Serial.println(BOARD_NAME); + Serial.println(AVR_PWM_VERSION); + + // Create a dummy instance + PWM_Instance = new AVR_PWM(pinToUse, frequency, 0); + + if (PWM_Instance) + { + // setPWM_manual(uint8_t pin, uint16_t level) + PWM_Instance->setPWM(pinToUse, frequency, 0); + + PWMPeriod = PWM_Instance->getPWMPeriod(); + +#if USING_DC_PERCENT + dutycyclePercent = 50.0f; + + // dutycyclePercentInt = dutycyclePercent * 65535 / 100 + dutycyclePercentInt = 1 << 15; +#else + // 5% steps + DCStep = round( PWMPeriod / 20.0f); + + // 50% + dutycycle = PWMPeriod / 2; +#endif + + printPWMInfo(PWM_Instance); + } + + Serial.print(F("Average time of setPWM function")); + +#if USING_DC_PERCENT + Serial.println(F(" USING_DC_PERCENT")); +#else + Serial.println(F(" not USING_DC_PERCENT")); +#endif +} + +void loop() +{ + static unsigned long update_timeout = UPDATE_INTERVAL + millis(); + static uint64_t count = 0; + +#if USING_DC_PERCENT + // 52745ns + //PWM_Instance->setPWM_DCPercentage_manual(pinToUse, dutycyclePercent); + + // dutycyclePercent = 0-65535 == 0-100% + // Faster, 8863ns + PWM_Instance->setPWM_DCPercentageInt_manual(pinToUse, dutycyclePercentInt); +#else + // 8415-8423ns + PWM_Instance->setPWM_manual(pinToUse, dutycycle); +#endif + + count++; + + // Update DC every UPDATE_INTERVAL (1000) milliseconds + if (millis() > update_timeout) + { + Serial.print(F("ns=")); + Serial.println( (uint32_t) (UPDATE_INTERVAL * 1000000 / count)); + + count = 0; + update_timeout = millis() + UPDATE_INTERVAL; + } +} diff --git a/keywords.txt b/keywords.txt index b039f4a..dbdb2b6 100644 --- a/keywords.txt +++ b/keywords.txt @@ -17,6 +17,7 @@ setPWM KEYWORD2 setPWM_Period KEYWORD2 setPWM_manual KEYWORD2 setPWM_DCPercentage_manual KEYWORD2 +setPWM_DCPercentageInt_manual KEYWORD2 getActualDutyCycle KEYWORD2 getActualFreq KEYWORD2 getPWMPeriod KEYWORD2 diff --git a/library.json b/library.json index 2d62801..853c5a6 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "AVR_PWM", - "version": "1.1.0", + "version": "1.2.0", "keywords": "timing, device, control, timer, pwm, fast-pwm, hardware-based-pwm, high-frequency-pwm, hardware-pwm, mission-critical, accuracy, precise, non-blocking, avr, mega-2560, nano, uno, leonardo, 32u4, 16u4, at-mega", "description": "This library enables you to use Hardware-based PWM channels on AVR-based boards, such as Nano, UNO, Mega, Leonardo, 32u4, etc., to create and output PWM. The most important feature is they're purely hardware-based PWM channels, supporting very high PWM frequencies. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These hardware-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 ISR, millis() or micros(). That's necessary if you need to control devices requiring high precision. New efficient setPWM_manual function to facilitate waveform creation using PWM", "authors": diff --git a/library.properties b/library.properties index f265d82..b33f62b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AVR_PWM -version=1.1.0 +version=1.2.0 author=Khoi Hoang maintainer=Khoi Hoang sentence=This library enables you to use Hardware-based PWM channels on AVR-based boards, such as Nano, UNO, Mega, Leonardo, 32u4, etc., to create and output PWM. diff --git a/src/AVR_PWM.h b/src/AVR_PWM.h index 43506c9..5ce3a1e 100644 --- a/src/AVR_PWM.h +++ b/src/AVR_PWM.h @@ -8,13 +8,14 @@ This is pure hardware-based PWM - Version: 1.1.0 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/10/2022 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) 1.0.1 K Hoang 22/01/2023 Add `PWM_StepperControl` example 1.1.0 K Hoang 24/01/2023 Add `PWM_manual` example and function. Catch low frequency error + 1.2.0 K Hoang 27/01/2023 Add `PWM_SpeedTest` example and faster `setPWM_DCPercentageInt_manual` function *****************************************************************************************************************************/ #pragma once @@ -124,13 +125,13 @@ //////////////////////////////////////// #ifndef AVR_PWM_VERSION - #define AVR_PWM_VERSION F("AVR_PWM v1.1.0") + #define AVR_PWM_VERSION F("AVR_PWM v1.2.0") #define AVR_PWM_VERSION_MAJOR 1 - #define AVR_PWM_VERSION_MINOR 1 + #define AVR_PWM_VERSION_MINOR 2 #define AVR_PWM_VERSION_PATCH 0 - #define AVR_PWM_VERSION_INT 1001000 + #define AVR_PWM_VERSION_INT 1002000 #endif //////////////////////////////////////// @@ -1456,6 +1457,17 @@ class AVR_PWM return true; } + + /////////////////////////////////////////// + + // Faster than setPWM_DCPercentage_manual by not using float + // DCPercentage from 0-65535 for 0.0f - 100.0f + bool setPWM_DCPercentageInt_manual(const uint8_t& pin, const uint16_t& DCPercentage) + { + //PWM_LOGERROR3("DCPercentage =", DCPercentage, ", DC =", ( DCPercentage >> 8 ) * ( pwmPeriod >> 8) ); + // Convert to DCValue based on pwmPeriod + return setPWM_manual(pin, ( DCPercentage >> 8 ) * ( pwmPeriod >> 8) ); + } /////////////////////////////////////////// @@ -1463,7 +1475,7 @@ class AVR_PWM bool setPWM_DCPercentage_manual(const uint8_t& pin, const float& DCPercentage) { // Convert to DCValue based on pwmPeriod - return setPWM_manual(pin, (DCPercentage * pwmPeriod) /100.0f); + return setPWM_manual(pin, (DCPercentage * pwmPeriod) / 100.0f); } /////////////////////////////////////////// diff --git a/src/PWM_Generic_Debug.h b/src/PWM_Generic_Debug.h index 2a25d90..2302cce 100644 --- a/src/PWM_Generic_Debug.h +++ b/src/PWM_Generic_Debug.h @@ -8,13 +8,14 @@ This is pure hardware-based PWM - Version: 1.1.0 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K.Hoang 27/10/2022 Initial coding for AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) 1.0.1 K Hoang 22/01/2023 Add `PWM_StepperControl` example 1.1.0 K Hoang 24/01/2023 Add `PWM_manual` example and function. Catch low frequency error + 1.2.0 K Hoang 27/01/2023 Add `PWM_SpeedTest` example and faster `setPWM_DCPercentageInt_manual` function *****************************************************************************************************************************/ #pragma once