├── utils ├── restyle.sh └── astyle_library.conf ├── .codespellrc ├── .github ├── workflows │ ├── auto-github-actions.yml │ ├── report-size-deltas.yml │ └── spell-check.yml ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── stale.yml ├── .gitignore ├── LICENSE ├── library.properties ├── keywords.txt ├── library.json ├── examples ├── PWM_Basic │ └── PWM_Basic.ino ├── PWM_StepperControl │ └── PWM_StepperControl.ino ├── PWM_DynamicFreq │ └── PWM_DynamicFreq.ino ├── PWM_DynamicDutyCycle │ └── PWM_DynamicDutyCycle.ino ├── PWM_DynamicDutyCycle_Int │ └── PWM_DynamicDutyCycle_Int.ino ├── PWM_MultiChannel │ └── PWM_MultiChannel.ino ├── PWM_Waveform │ └── PWM_Waveform.ino ├── PWM_SpeedTest │ └── PWM_SpeedTest.ino ├── PWM_manual │ └── PWM_manual.ino └── PWM_Multi │ └── PWM_Multi.ino ├── changelog.md ├── CONTRIBUTING.md ├── platformio └── platformio.ini ├── src ├── PWM_Generic_Debug.h └── ESP32_FastPWM.h └── README.md /utils/restyle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for dir in . ; do 4 | find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \; 5 | done 6 | 7 | -------------------------------------------------------------------------------- /.codespellrc: -------------------------------------------------------------------------------- 1 | # See: https://github.com/codespell-project/codespell#using-a-config-file 2 | [codespell] 3 | # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: 4 | ignore-words-list = , 5 | check-filenames = 6 | check-hidden = 7 | skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches 8 | -------------------------------------------------------------------------------- /.github/workflows/auto-github-actions.yml: -------------------------------------------------------------------------------- 1 | name: auto-github-actions 2 | on: [push] 3 | jobs: 4 | check-bats-version: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - uses: actions/setup-node@v3 9 | with: 10 | node-version: '14' 11 | - run: npm install -g bats 12 | - run: bats -v 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /.github/workflows/report-size-deltas.yml: -------------------------------------------------------------------------------- 1 | name: Report Size Deltas 2 | 3 | on: 4 | schedule: 5 | - cron: '*/5 * * * *' 6 | 7 | jobs: 8 | report: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Comment size deltas reports to PRs 13 | uses: arduino/report-size-deltas@v1 14 | with: 15 | # The name of the workflow artifact created by the "Compile Examples" workflow 16 | sketches-reports-source: sketches-reports 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file 2 | version: 2 3 | 4 | updates: 5 | # Configure check for outdated GitHub Actions actions in workflows. 6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot 7 | - package-ecosystem: github-actions 8 | directory: / # Check the repository's workflows under /.github/workflows/ 9 | schedule: 10 | interval: daily 11 | -------------------------------------------------------------------------------- /.github/workflows/spell-check.yml: -------------------------------------------------------------------------------- 1 | name: Spell Check 2 | 3 | on: 4 | pull_request: 5 | push: 6 | schedule: 7 | # run every Tuesday at 3 AM UTC 8 | - cron: "0 3 * * 2" 9 | workflow_dispatch: 10 | repository_dispatch: 11 | 12 | jobs: 13 | spellcheck: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | 20 | # See: https://github.com/codespell-project/actions-codespell/blob/master/README.md 21 | - name: Spell check 22 | uses: codespell-project/actions-codespell@master 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Is your feature request related to a problem? Please describe. 11 | 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 13 | 14 | ### Describe the solution you'd like 15 | 16 | A clear and concise description of what you want to happen. 17 | 18 | ### Describe alternatives you've considered 19 | 20 | A clear and concise description of any alternative solutions or features you've considered. 21 | 22 | ### Additional context 23 | 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | daysUntilStale: 60 4 | daysUntilClose: 14 5 | limitPerRun: 30 6 | staleLabel: stale 7 | exemptLabels: 8 | - pinned 9 | - security 10 | - "to be implemented" 11 | - "for reference" 12 | - "move to PR" 13 | - "enhancement" 14 | 15 | only: issues 16 | onlyLabels: [] 17 | exemptProjects: false 18 | exemptMilestones: false 19 | exemptAssignees: false 20 | 21 | markComment: > 22 | [STALE_SET] This issue has been automatically marked as stale because it has not had 23 | recent activity. It will be closed in 14 days if no further activity occurs. Thank you 24 | for your contributions. 25 | 26 | unmarkComment: > 27 | [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it opening the future. 28 | 29 | closeComment: > 30 | [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions. 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Khoi Hoang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32_FastPWM 2 | version=1.1.0 3 | author=Khoi Hoang 4 | maintainer=Khoi Hoang 5 | sentence=This library enables you to use Hardware-based PWM channels on ESP32, ESP32_S2, ESP32_S3 or ESP32_C3-based boards to create and output PWM to pins. 6 | paragraph=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 7 | category=Device Control 8 | url=https://github.com/khoih-prog/ESP32_FastPWM 9 | architectures=esp32 10 | repository=https://github.com/khoih-prog/ESP32_FastPWM 11 | license=MIT 12 | includes=ESP32_FastPWM.h 13 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Datatypes (KEYWORD1) 3 | ####################################### 4 | 5 | ESP32_FastPWM KEYWORD1 6 | 7 | ####################################### 8 | # Methods and Functions (KEYWORD2) 9 | ####################################### 10 | 11 | ################################### 12 | # Class ESP32_FastPWM 13 | ################################### 14 | 15 | setPWM_Int KEYWORD2 16 | setPWM KEYWORD2 17 | setPWM_Period KEYWORD2 18 | setPWM_manual KEYWORD2 19 | setPWM_DCPercentage_manual KEYWORD2 20 | getActualDutyCycle KEYWORD2 21 | getActualFreq KEYWORD2 22 | getPWMPeriod KEYWORD2 23 | get_freq_CPU KEYWORD2 24 | getPin KEYWORD2 25 | getResolution KEYWORD2 26 | 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | 32 | ESP32_FAST_PWM_VERSION LITERAL1 33 | ESP32_FAST_PWM_VERSION_MAJOR LITERAL1 34 | ESP32_FAST_PWM_VERSION_MINOR LITERAL1 35 | ESP32_FAST_PWM_VERSION_PATCH LITERAL1 36 | ESP32_FAST_PWM_VERSION_INT LITERAL1 37 | 38 | MAX_PWM_RESOLUTION_BIT LITERAL1 39 | MAX_PWM_RESOLUTION LITERAL1 40 | 41 | MAX_COUNT_16BIT LITERAL1 42 | 43 | _LEDC_CHANNELS LITERAL1 44 | 45 | _PWM_LOGLEVEL_ LITERAL1 46 | -------------------------------------------------------------------------------- /utils/astyle_library.conf: -------------------------------------------------------------------------------- 1 | # Code formatting rules for Arduino libraries, modified from for KH libraries: 2 | # 3 | # https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf 4 | # 5 | 6 | # astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino 7 | 8 | --mode=c 9 | --lineend=linux 10 | --style=allman 11 | 12 | # -r or -R 13 | #--recursive 14 | 15 | # -c => Converts tabs into spaces 16 | convert-tabs 17 | 18 | # -s2 => 2 spaces indentation 19 | --indent=spaces=2 20 | 21 | # -t2 => tab =2 spaces 22 | #--indent=tab=2 23 | 24 | # -C 25 | --indent-classes 26 | 27 | # -S 28 | --indent-switches 29 | 30 | # -xW 31 | --indent-preproc-block 32 | 33 | # -Y => indent classes, switches (and cases), comments starting at column 1 34 | --indent-col1-comments 35 | 36 | # -M120 => maximum of 120 spaces to indent a continuation line 37 | --max-continuation-indent=120 38 | 39 | # -xC120 => max‑code‑length will break a line if the code exceeds # characters 40 | --max-code-length=120 41 | 42 | # -f => 43 | --break-blocks 44 | 45 | # -p => put a space around operators 46 | --pad-oper 47 | 48 | # -xg => Insert space padding after commas 49 | --pad-comma 50 | 51 | # -H => put a space after if/for/while 52 | pad-header 53 | 54 | # -xb => Break one line headers (e.g. if/for/while) 55 | --break-one-line-headers 56 | 57 | # -c => Converts tabs into spaces 58 | #--convert-tabs 59 | 60 | # if you like one-liners, keep them 61 | #keep-one-line-statements 62 | 63 | # -xV 64 | --attach-closing-while 65 | 66 | #unpad-paren 67 | 68 | # -xp 69 | remove-comment-prefix 70 | 71 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ESP32_FastPWM", 3 | "version": "1.1.0", 4 | "keywords": "timing, device, control, pwm, timer, interrupt, hardware, isr, isr-based, hardware-timer, isr-timer, isr-based-timer, mission-critical, accuracy, precise, non-blocking, esp32, esp32-s2, esp32-c3, esp32-s3, synchronized-PWM, on-the-fly", 5 | "description": "This library enables you to use Hardware-based PWM channels on ESP32, ESP32_S2, ESP32_S3 or ESP32_C3-based boards to create and output PWM to pins. 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", 6 | "authors": 7 | { 8 | "name": "Khoi Hoang", 9 | "url": "https://github.com/khoih-prog", 10 | "maintainer": true 11 | }, 12 | "repository": 13 | { 14 | "type": "git", 15 | "url": "https://github.com/khoih-prog/ESP32_FastPWM.git" 16 | }, 17 | "homepage": "https://github.com/khoih-prog/ESP32_FastPWM", 18 | "export": { 19 | "exclude": [ 20 | "linux", 21 | "extras", 22 | "tests" 23 | ] 24 | }, 25 | "license": "MIT", 26 | "frameworks": "*", 27 | "platforms": "espressif32", 28 | "examples": "examples/*/*/*.ino", 29 | "headers": ["ESP32_FastPWM.h"] 30 | } 31 | -------------------------------------------------------------------------------- /examples/PWM_Basic/PWM_Basic.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_Basic.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #include "ESP32_FastPWM.h" 22 | 23 | #if ARDUINO_ESP32C3_DEV 24 | #define pinToUse 9 25 | #else 26 | #define pinToUse 16 27 | #endif 28 | 29 | // Max resolution is 20-bit 30 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 31 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 32 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 33 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 34 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 35 | int PWM_resolution = 12; 36 | 37 | //creates pwm instance 38 | ESP32_FAST_PWM* PWM_Instance; 39 | 40 | float frequency = 1000.0f; 41 | float dutyCycle = 0.0f; 42 | 43 | uint8_t channel = 0; 44 | 45 | void setup() 46 | { 47 | Serial.begin(115200); 48 | 49 | while (!Serial && millis() < 5000); 50 | 51 | delay(500); 52 | 53 | Serial.print(F("\nStarting PWM_Basic on ")); 54 | Serial.println(ARDUINO_BOARD); 55 | Serial.println(ESP32_FAST_PWM_VERSION); 56 | 57 | //assigns PWM frequency of 1.0 KHz and a duty cycle of 0%, channel 0, 12-bit resolution 58 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, dutyCycle, channel, PWM_resolution); 59 | } 60 | 61 | void loop() 62 | { 63 | frequency = 2000.0f; 64 | dutyCycle = 20.0f; 65 | 66 | PWM_Instance->setPWM(pinToUse, frequency, dutyCycle); 67 | 68 | delay(5000); 69 | dutyCycle = 90.0f; 70 | 71 | PWM_Instance->setPWM(pinToUse, frequency, dutyCycle); 72 | 73 | delay(5000); 74 | } 75 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # ESP32_FastPWM Library 2 | 3 | [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP32_FastPWM.svg?)](https://www.ardu-badge.com/ESP32_FastPWM) 4 | [![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP32_FastPWM.svg)](https://github.com/khoih-prog/ESP32_FastPWM/releases) 5 | [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/ESP32_FastPWM/blob/master/LICENSE) 6 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) 7 | [![GitHub issues](https://img.shields.io/github/issues/khoih-prog/ESP32_FastPWM.svg)](http://github.com/khoih-prog/ESP32_FastPWM/issues) 8 | 9 | 10 | Donate to my libraries using BuyMeACoffee 11 | 12 | 13 | 14 | --- 15 | --- 16 | 17 | ## Table of Contents 18 | 19 | * [Changelog](#changelog) 20 | * [Releases v1.1.0](#Releases-v110) 21 | * [Releases v1.0.1](#Releases-v101) 22 | * [Releases v1.0.0](#releases-v100) 23 | 24 | --- 25 | --- 26 | 27 | ## Changelog 28 | 29 | ### Releases v1.1.0 30 | 31 | 1. Add example [PWM_manual](https://github.com/khoih-prog/ESP32_FastPWM/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) 32 | 2. Add function `setPWM_DCPercentage_manual()` to facilitate the setting PWM DC manually by using `DCPercentage`, instead of `absolute DCValue` depending on varying resolution 33 | 3. Fix glitch when changing PWM frequency. Check [Frequency change on cycle end. #1](https://github.com/khoih-prog/ESP32_FastPWM/discussions/1) 34 | 35 | ### Releases v1.0.1 36 | 37 | 1. Add example [PWM_StepperControl](https://github.com/khoih-prog/ESP32_FastPWM/examples/PWM_StepperControl) to demo how to control Stepper Motor using PWM. Check [Using PWM to step a stepper driver #16](https://github.com/khoih-prog/RP2040_PWM/issues/16) 38 | 39 | 40 | ### Releases v1.0.0 41 | 42 | 1. Initial coding for ESP32, ESP32_S2, ESP32_S3 and ESP32_C3 boards using [ESP32 core](https://github.com/espressif/arduino-esp32) 43 | 44 | 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to ESP32_FastPWM 2 | 3 | ### Reporting Bugs 4 | 5 | Please report bugs in [ESP32_FastPWM Issues](https://github.com/khoih-prog/ESP32_FastPWM/issues) if you find them. 6 | 7 | However, before reporting a bug please check through the following: 8 | 9 | * [Existing Open Issues](https://github.com/khoih-prog/ESP32_FastPWM/issues) - someone might have already encountered this. 10 | 11 | If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ESP32_FastPWM/issues/new). 12 | 13 | --- 14 | 15 | ### How to submit a bug report 16 | 17 | Please ensure to specify the following: 18 | 19 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version 20 | * `ESP32` Core Version (e.g. ESP32 core v2.0.6) 21 | * `ESP32` Board type (e.g. ESP32_DEV Module, etc.) 22 | * `ESP32-S2` Board type (e.g. ESP32S2_DEV Module, ESP32_S2_Saola, etc.) 23 | * `ESP32_S3` Board type (e.g. ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.) 24 | * `ESP32-C3` Board type (e.g. ESP32C3_DEV Module, etc.) 25 | * Contextual information (e.g. what you were trying to achieve) 26 | * Simplest possible steps to reproduce 27 | * Anything that might be relevant in your opinion, such as: 28 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` 29 | * Network configuration 30 | 31 | 32 | Please be educated, civilized and constructive as you've always been. Disrespective posts against [GitHub Code of Conduct](https://docs.github.com/en/site-policy/github-terms/github-event-code-of-conduct) will be ignored and deleted. 33 | 34 | --- 35 | 36 | ### Example 37 | 38 | ``` 39 | Arduino IDE version: 1.8.19 40 | ESP32 core v2.0.6 41 | ESP32S3_DEV Module 42 | OS: Ubuntu 20.04 LTS 43 | Linux xy-Inspiron-3593 5.15.0-58-generic #64~20.04.1-Ubuntu SMP Fri Jan 6 16:42:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux 44 | 45 | Context: 46 | I encountered a crash while using TimerInterrupt. 47 | 48 | Steps to reproduce: 49 | 1. ... 50 | 2. ... 51 | 3. ... 52 | 4. ... 53 | ``` 54 | 55 | ### Additional context 56 | 57 | Add any other context about the problem here. 58 | 59 | --- 60 | 61 | ### Sending Feature Requests 62 | 63 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. 64 | 65 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESP32_FastPWM/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. 66 | 67 | --- 68 | 69 | ### Sending Pull Requests 70 | 71 | Pull Requests with changes and fixes are also welcome! 72 | 73 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) 74 | 75 | 1. Change directory to the library GitHub 76 | 77 | ``` 78 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESP32_FastPWM_GitHub/ 79 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_FastPWM_GitHub$ 80 | ``` 81 | 82 | 2. Issue astyle command 83 | 84 | ``` 85 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_FastPWM_GitHub$ bash utils/restyle.sh 86 | ``` 87 | 88 | -------------------------------------------------------------------------------- /examples/PWM_StepperControl/PWM_StepperControl.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_StepperControl.ino 3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 4 | Written by Khoi Hoang 5 | 6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 7 | Licensed under MIT license 8 | 9 | This is pure hardware-based PWM 10 | 11 | Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 12 | *****************************************************************************************************************************/ 13 | /****************************************************************************************************************************** 14 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 15 | // For ESP32, number of channels is 16, max 20-bit resolution 16 | // For ESP32_S2, ESP32_S3, number of channels is 8 17 | // For ESP32_C3, number of channels is 6 18 | ******************************************************************************************************************************/ 19 | 20 | // Use with Stepper-Motor driver, such as TMC2209 21 | 22 | #define _PWM_LOGLEVEL_ 4 23 | 24 | #include "ESP32_FastPWM.h" 25 | 26 | #if ARDUINO_ESP32C3_DEV 27 | #define STEP_PIN 9 28 | #else 29 | #define STEP_PIN 16 30 | #endif 31 | 32 | #define DIR_PIN 4 33 | 34 | // Max resolution is 20-bit 35 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 36 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 37 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 38 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 39 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 40 | int PWM_resolution = 10; 41 | 42 | //creates pwm instance 43 | ESP32_FAST_PWM* stepper; 44 | 45 | void setSpeed(int speed) 46 | { 47 | if (speed == 0) 48 | { 49 | // Use DC = 0 to stop stepper 50 | stepper->setPWM(STEP_PIN, 500, 0); 51 | } 52 | else 53 | { 54 | // Set the frequency of the PWM output and a duty cycle of 50% 55 | digitalWrite(DIR_PIN, (speed < 0)); 56 | stepper->setPWM(STEP_PIN, abs(speed), 50); 57 | } 58 | } 59 | 60 | void setup() 61 | { 62 | pinMode(DIR_PIN, OUTPUT); 63 | 64 | Serial.begin(115200); 65 | 66 | while (!Serial && millis() < 5000); 67 | 68 | delay(100); 69 | 70 | Serial.print(F("\nStarting PWM_StepperControl on ")); 71 | Serial.println(ARDUINO_BOARD); 72 | Serial.println(ESP32_FAST_PWM_VERSION); 73 | 74 | // Create PWM object and passed just a random frequency of 500 75 | // The duty cycle is how you turn the motor on and off 76 | stepper = new ESP32_FAST_PWM(STEP_PIN, 500, 0); 77 | } 78 | 79 | void loop() 80 | { 81 | setSpeed(1000); 82 | delay(3000); 83 | 84 | // Stop before reversing 85 | setSpeed(0); 86 | delay(3000); 87 | 88 | // Reversing 89 | setSpeed(-500); 90 | delay(3000); 91 | 92 | // Stop before reversing 93 | setSpeed(0); 94 | delay(3000); 95 | } 96 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the bug 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | ### Steps to Reproduce 15 | 16 | Steps to reproduce the behavior. Including the [MRE](https://stackoverflow.com/help/minimal-reproducible-example) sketches 17 | 18 | ### Expected behavior 19 | 20 | A clear and concise description of what you expected to happen. 21 | 22 | ### Actual behavior 23 | 24 | A clear and concise description of what you expected to happen. 25 | 26 | ### Debug and AT-command log (if applicable) 27 | 28 | A clear and concise description of what you expected to happen. 29 | 30 | ### Screenshots 31 | 32 | If applicable, add screenshots to help explain your problem. 33 | 34 | --- 35 | 36 | ### Information 37 | 38 | Please ensure to specify the following: 39 | 40 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version 41 | * `ESP32` Core Version (e.g. ESP32 core v2.0.6) 42 | * `ESP32` Board type (e.g. ESP32_DEV Module, etc.) 43 | * `ESP32-S2` Board type (e.g. ESP32S2_DEV Module, ESP32_S2_Saola, etc.) 44 | * `ESP32_S3` Board type (e.g. ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.) 45 | * `ESP32-C3` Board type (e.g. ESP32C3_DEV Module, etc.) 46 | * Contextual information (e.g. what you were trying to achieve) 47 | * Simplest possible steps to reproduce 48 | * Anything that might be relevant in your opinion, such as: 49 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` 50 | * Network configuration 51 | 52 | 53 | Please be educated, civilized and constructive as you've always been. Disrespective posts against [GitHub Code of Conduct](https://docs.github.com/en/site-policy/github-terms/github-event-code-of-conduct) will be ignored and deleted. 54 | 55 | --- 56 | 57 | ### Example 58 | 59 | ``` 60 | Arduino IDE version: 1.8.19 61 | ESP32 core v2.0.6 62 | ESP32S3_DEV Module 63 | OS: Ubuntu 20.04 LTS 64 | Linux xy-Inspiron-3593 5.15.0-58-generic #64~20.04.1-Ubuntu SMP Fri Jan 6 16:42:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux 65 | 66 | Context: 67 | I encountered a crash while using TimerInterrupt. 68 | 69 | Steps to reproduce: 70 | 1. ... 71 | 2. ... 72 | 3. ... 73 | 4. ... 74 | ``` 75 | 76 | ### Additional context 77 | 78 | Add any other context about the problem here. 79 | 80 | --- 81 | 82 | ### Sending Feature Requests 83 | 84 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. 85 | 86 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESP32_FastPWM/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. 87 | 88 | --- 89 | 90 | ### Sending Pull Requests 91 | 92 | Pull Requests with changes and fixes are also welcome! 93 | 94 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) 95 | 96 | 1. Change directory to the library GitHub 97 | 98 | ``` 99 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESP32_FastPWM_GitHub/ 100 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_FastPWM_GitHub$ 101 | ``` 102 | 103 | 2. Issue astyle command 104 | 105 | ``` 106 | xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_FastPWM_GitHub$ bash utils/restyle.sh 107 | ``` 108 | 109 | -------------------------------------------------------------------------------- /examples/PWM_DynamicFreq/PWM_DynamicFreq.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_DynamicFreq.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #include "ESP32_FastPWM.h" 22 | 23 | #if ARDUINO_ESP32C3_DEV 24 | #define pinToUse 9 25 | #else 26 | #define pinToUse 16 27 | #endif 28 | 29 | // Max resolution is 20-bit 30 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 31 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 32 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 33 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 34 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 35 | int PWM_resolution = 10; 36 | 37 | //creates pwm instance 38 | ESP32_FAST_PWM* PWM_Instance; 39 | 40 | float frequency; 41 | 42 | char dashLine[] = "====================================================================================="; 43 | 44 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 45 | { 46 | Serial.println(dashLine); 47 | Serial.print("Actual data: pin = "); 48 | Serial.print(PWM_Instance->getPin()); 49 | Serial.print(", PWM DC = "); 50 | Serial.print(PWM_Instance->getActualDutyCycle()); 51 | Serial.print(", PWMPeriod = "); 52 | Serial.print(PWM_Instance->getPWMPeriod()); 53 | Serial.print(", PWM Freq (Hz) = "); 54 | Serial.println(PWM_Instance->getActualFreq(), 4); 55 | Serial.println(dashLine); 56 | } 57 | 58 | void setup() 59 | { 60 | Serial.begin(115200); 61 | 62 | while (!Serial && millis() < 5000); 63 | 64 | delay(500); 65 | 66 | Serial.print(F("\nStarting PWM_DynamicFreq on ")); 67 | Serial.println(ARDUINO_BOARD); 68 | Serial.println(ESP32_FAST_PWM_VERSION); 69 | 70 | frequency = 10000.0f; 71 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 50.0f); 72 | 73 | if (PWM_Instance) 74 | { 75 | PWM_Instance->setPWM(); 76 | } 77 | 78 | Serial.println(dashLine); 79 | } 80 | 81 | void loop() 82 | { 83 | delay(5000); 84 | 85 | frequency = 20000.0f; 86 | 87 | Serial.print(F("Change PWM Freq to ")); 88 | Serial.println(frequency); 89 | PWM_Instance->setPWM(pinToUse, frequency, 50.0f); 90 | printPWMInfo(PWM_Instance); 91 | 92 | delay(5000); 93 | 94 | frequency = 10000.0f; 95 | 96 | Serial.print(F("Change PWM Freq to ")); 97 | Serial.println(frequency); 98 | PWM_Instance->setPWM(pinToUse, frequency, 50.0f); 99 | printPWMInfo(PWM_Instance); 100 | } 101 | -------------------------------------------------------------------------------- /examples/PWM_DynamicDutyCycle/PWM_DynamicDutyCycle.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_DynamicDutyCycle.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #include "ESP32_FastPWM.h" 22 | 23 | #if ARDUINO_ESP32C3_DEV 24 | #define pinToUse 9 25 | #else 26 | #define pinToUse 16 27 | #endif 28 | 29 | // Max resolution is 20-bit 30 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 31 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 32 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 33 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 34 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 35 | int PWM_resolution = 12; 36 | 37 | //creates pwm instance 38 | ESP32_FAST_PWM* PWM_Instance; 39 | 40 | float frequency; 41 | float dutyCycle; 42 | 43 | char dashLine[] = "====================================================================================="; 44 | 45 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 46 | { 47 | Serial.println(dashLine); 48 | Serial.print("Actual data: pin = "); 49 | Serial.print(PWM_Instance->getPin()); 50 | Serial.print(", PWM DC = "); 51 | Serial.print(PWM_Instance->getActualDutyCycle()); 52 | Serial.print(", PWMPeriod = "); 53 | Serial.print(PWM_Instance->getPWMPeriod()); 54 | Serial.print(", PWM Freq (Hz) = "); 55 | Serial.println(PWM_Instance->getActualFreq(), 4); 56 | Serial.println(dashLine); 57 | } 58 | 59 | void setup() 60 | { 61 | Serial.begin(115200); 62 | 63 | while (!Serial && millis() < 5000); 64 | 65 | delay(500); 66 | 67 | Serial.print(F("\nStarting PWM_DynamicDutyCycle on ")); 68 | Serial.println(ARDUINO_BOARD); 69 | Serial.println(ESP32_FAST_PWM_VERSION); 70 | 71 | frequency = 5000.0f; 72 | 73 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 50.0f); 74 | 75 | if (PWM_Instance) 76 | { 77 | if (!PWM_Instance->setPWM()) 78 | { 79 | Serial.println(F("Stop here")); 80 | 81 | // stop here 82 | while (true) 83 | delay(1000); 84 | } 85 | } 86 | 87 | Serial.println(dashLine); 88 | } 89 | 90 | void loop() 91 | { 92 | dutyCycle = 90.0f; 93 | 94 | Serial.print(F("Change PWM DutyCycle to ")); 95 | Serial.println(dutyCycle); 96 | PWM_Instance->setPWM(pinToUse, frequency, dutyCycle); 97 | 98 | printPWMInfo(PWM_Instance); 99 | 100 | delay(5000); 101 | dutyCycle = 20.0f; 102 | 103 | Serial.print(F("Change PWM DutyCycle to ")); 104 | Serial.println(dutyCycle); 105 | PWM_Instance->setPWM(pinToUse, frequency, dutyCycle); 106 | printPWMInfo(PWM_Instance); 107 | 108 | delay(5000); 109 | } 110 | -------------------------------------------------------------------------------- /examples/PWM_DynamicDutyCycle_Int/PWM_DynamicDutyCycle_Int.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_DynamicDutyCycle_Int.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #include "ESP32_FastPWM.h" 22 | 23 | #if ARDUINO_ESP32C3_DEV 24 | #define pinToUse 9 25 | #else 26 | #define pinToUse 16 27 | #endif 28 | 29 | // Max resolution is 20-bit 30 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 31 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 32 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 33 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 34 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 35 | int PWM_resolution = 12; 36 | 37 | //creates pwm instance 38 | ESP32_FAST_PWM* PWM_Instance; 39 | 40 | float frequency; 41 | uint32_t dutyCycle; 42 | 43 | char dashLine[] = "====================================================================================="; 44 | 45 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 46 | { 47 | Serial.println(dashLine); 48 | Serial.print("Actual data: pin = "); 49 | Serial.print(PWM_Instance->getPin()); 50 | Serial.print(", PWM DC = "); 51 | Serial.print(PWM_Instance->getActualDutyCycle()); 52 | Serial.print(", PWMPeriod = "); 53 | Serial.print(PWM_Instance->getPWMPeriod()); 54 | Serial.print(", PWM Freq (Hz) = "); 55 | Serial.println(PWM_Instance->getActualFreq(), 4); 56 | Serial.println(dashLine); 57 | } 58 | 59 | void setup() 60 | { 61 | Serial.begin(115200); 62 | 63 | while (!Serial && millis() < 5000); 64 | 65 | delay(500); 66 | 67 | Serial.print(F("\nStarting PWM_DynamicDutyCycle_Int on ")); 68 | Serial.println(ARDUINO_BOARD); 69 | Serial.println(ESP32_FAST_PWM_VERSION); 70 | 71 | frequency = 1000.0f; 72 | 73 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 50); 74 | 75 | if (PWM_Instance) 76 | { 77 | PWM_Instance->setPWM(); 78 | } 79 | 80 | Serial.println(dashLine); 81 | } 82 | 83 | void loop() 84 | { 85 | delay(5000); 86 | 87 | frequency = 5000.0f; 88 | 89 | // 50% dutyCycle = (real_dutyCycle * 65536) / 100 90 | dutyCycle = 32768; 91 | 92 | Serial.print(F("Change PWM DutyCycle to (%) ")); 93 | Serial.println((float) dutyCycle * 100 / 65536); 94 | PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle); 95 | 96 | printPWMInfo(PWM_Instance); 97 | 98 | delay(5000); 99 | 100 | // 20% dutyCycle = (real_dutyCycle * 65536) / 100 101 | dutyCycle = 13107; 102 | 103 | Serial.print(F("Change PWM DutyCycle to (%) ")); 104 | Serial.println((float) dutyCycle * 100 / 65536); 105 | PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle); 106 | printPWMInfo(PWM_Instance); 107 | } 108 | -------------------------------------------------------------------------------- /examples/PWM_MultiChannel/PWM_MultiChannel.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_MultiChannel.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #include "ESP32_FastPWM.h" 22 | 23 | // Max resolution is 20-bit 24 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 25 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 26 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 27 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 28 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 29 | int PWM_resolution = 12; 30 | 31 | #if ARDUINO_ESP32C3_DEV 32 | uint32_t PWM_Pins[] = { 8, 9 }; 33 | #else 34 | uint32_t PWM_Pins[] = { 16, 17 }; 35 | #endif 36 | 37 | uint32_t PWM_chan[] = { 0, 1 }; 38 | 39 | #define NUM_OF_PINS ( sizeof(PWM_Pins) / sizeof(uint32_t) ) 40 | 41 | float dutyCycle[] = { 20.0f, 50.0f }; 42 | 43 | // Must be same frequency for same channel 44 | float frequency = 2000.0f; 45 | 46 | //creates pwm instances 47 | ESP32_FAST_PWM* PWM_Instance[NUM_OF_PINS]; 48 | 49 | char dashLine[] = "====================================================================================="; 50 | 51 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 52 | { 53 | Serial.println(dashLine); 54 | Serial.print("Actual data: pin = "); 55 | Serial.print(PWM_Instance->getPin()); 56 | Serial.print(", PWM DC = "); 57 | Serial.print(PWM_Instance->getActualDutyCycle()); 58 | Serial.print(", PWMPeriod = "); 59 | Serial.print(PWM_Instance->getPWMPeriod()); 60 | Serial.print(", PWM Freq (Hz) = "); 61 | Serial.println(PWM_Instance->getActualFreq(), 4); 62 | Serial.println(dashLine); 63 | } 64 | 65 | void setup() 66 | { 67 | Serial.begin(115200); 68 | 69 | while (!Serial && millis() < 5000); 70 | 71 | delay(500); 72 | 73 | Serial.print(F("\nStarting PWM_MultiChannel on ")); 74 | Serial.println(ARDUINO_BOARD); 75 | Serial.println(ESP32_FAST_PWM_VERSION); 76 | 77 | for (uint8_t index = 0; index < NUM_OF_PINS; index++) 78 | { 79 | PWM_Instance[index] = new ESP32_FAST_PWM(PWM_Pins[index], frequency, dutyCycle[index], PWM_chan[index], PWM_resolution); 80 | 81 | if (PWM_Instance[index]) 82 | { 83 | PWM_Instance[index]->setPWM(); 84 | } 85 | } 86 | 87 | Serial.println(dashLine); 88 | Serial.println("Index\tPin\tPWM_freq\tDutyCycle\tActual Freq"); 89 | Serial.println(dashLine); 90 | 91 | for (uint8_t index = 0; index < NUM_OF_PINS; index++) 92 | { 93 | if (PWM_Instance[index]) 94 | { 95 | Serial.print(index); 96 | Serial.print("\t"); 97 | Serial.print(PWM_Pins[index]); 98 | Serial.print("\t"); 99 | Serial.print(frequency); 100 | Serial.print("\t\t"); 101 | Serial.print(dutyCycle[index]); 102 | Serial.print("\t\t"); 103 | Serial.println(PWM_Instance[index]->getActualFreq(), 4); 104 | } 105 | else 106 | { 107 | Serial.println(); 108 | } 109 | } 110 | 111 | for (uint8_t index = 0; index < NUM_OF_PINS; index++) 112 | { 113 | printPWMInfo(PWM_Instance[index]); 114 | } 115 | } 116 | 117 | void loop() 118 | { 119 | //Long delay has no effect on the operation of hardware-based PWM channels 120 | delay(1000000); 121 | } 122 | -------------------------------------------------------------------------------- /platformio/platformio.ini: -------------------------------------------------------------------------------- 1 | ;PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | ; ============================================================ 13 | ; chose environment: 14 | ; ESP32 15 | ; esp32s2 16 | ; esp32s3 17 | ; esp32c3 18 | 19 | ; ============================================================ 20 | default_envs = ESP32 21 | 22 | [env] 23 | ; ============================================================ 24 | ; Serial configuration 25 | ; choose upload speed, serial-monitor speed 26 | ; ============================================================ 27 | upload_speed = 921600 28 | ;upload_port = COM11 29 | ;monitor_speed = 9600 30 | ;monitor_port = COM11 31 | 32 | ; Checks for the compatibility with frameworks and dev/platforms 33 | lib_compat_mode = strict 34 | lib_ldf_mode = chain+ 35 | ;lib_ldf_mode = deep+ 36 | 37 | lib_deps = 38 | 39 | build_flags = 40 | ; set your debug output (default=Serial) 41 | -D DEBUG_ESP_PORT=Serial 42 | ; comment the following line to enable WiFi debugging 43 | -D NDEBUG 44 | 45 | [env:ESP32] 46 | platform = espressif32 47 | framework = arduino 48 | 49 | ; ============================================================ 50 | ; Board configuration 51 | ; choose your board by uncommenting one of the following lines 52 | ; ============================================================ 53 | ;board = esp32cam 54 | ;board = alksesp32 55 | ;board = featheresp32 56 | ;board = espea32 57 | ;board = bpi-bit 58 | ;board = d-duino-32 59 | board = esp32doit-devkit-v1 60 | ;board = pocket_32 61 | ;board = fm-devkit 62 | ;board = pico32 63 | ;board = esp32-evb 64 | ;board = esp32-gateway 65 | ;board = esp32-pro 66 | ;board = esp32-poe 67 | ;board = oroca_edubot 68 | ;board = onehorse32dev 69 | ;board = lopy 70 | ;board = lopy4 71 | ;board = wesp32 72 | ;board = esp32thing 73 | ;board = sparkfun_lora_gateway_1-channel 74 | ;board = ttgo-lora32-v1 75 | ;board = ttgo-t-beam 76 | ;board = turta_iot_node 77 | ;board = lolin_d32 78 | ;board = lolin_d32_pro 79 | ;board = lolin32 80 | ;board = wemosbat 81 | ;board = widora-air 82 | ;board = xinabox_cw02 83 | ;board = iotbusio 84 | ;board = iotbusproteus 85 | ;board = nina_w10 86 | 87 | [env:esp32s2] 88 | platform = espressif32 89 | framework = arduino 90 | 91 | ; toolchain download links see 92 | ; refer "name": "xtensa-esp32s2-elf-gcc","version": "gcc8_4_0-esp-2021r1" section of 93 | ; https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json 94 | ; e.g. Windows: https://github.com/espressif/crosstool-NG/releases/download/esp-2021r1/xtensa-esp32s2-elf-gcc8_4_0-esp-2021r1-win32.zip 95 | platform_packages = 96 | toolchain-xtensa32s2@file://C:\Users\Max\Downloads\xtensa-esp32s2-elf 97 | framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git#a4118ea88987c28aac3a49bcb9cc5d6c0acc6f3f 98 | platformio/tool-esptoolpy @ ~1.30100 99 | framework = arduino 100 | board = esp32dev 101 | board_build.mcu = esp32s2 102 | board_build.partitions = huge_app.csv 103 | board_build.variant = esp32s2 104 | board_build.f_cpu = 240000000L 105 | board_build.f_flash = 80000000L 106 | board_build.flash_mode = qio 107 | board_build.arduino.ldscript = esp32s2_out.ld 108 | build_unflags = 109 | -DARDUINO_ESP32_DEV 110 | -DARDUINO_VARIANT="esp32" 111 | build_flags = 112 | -DARDUINO_ESP32S2_DEV 113 | -DARDUINO_VARIANT="esp32s2" 114 | 115 | 116 | [env:esp32s3] 117 | platform = espressif32 118 | framework = arduino 119 | 120 | board_build.mcu = esp32s3 121 | board_build.partitions = huge_app.csv 122 | board_build.variant = esp32s3 123 | board_build.f_cpu = 240000000L 124 | board_build.f_flash = 80000000L 125 | board_build.flash_mode = qio 126 | board_build.arduino.ldscript = esp32s3_out.ld 127 | build_unflags = 128 | -DARDUINO_ESP32_DEV 129 | -DARDUINO_VARIANT="esp32" 130 | build_flags = 131 | -DARDUINO_ESP32S3_DEV 132 | -DARDUINO_VARIANT="esp32s3" 133 | 134 | 135 | [env:esp32sc3] 136 | platform = espressif32 137 | framework = arduino 138 | 139 | board_build.mcu = esp32c3 140 | board_build.partitions = huge_app.csv 141 | board_build.variant = esp32c3 142 | board_build.f_cpu = 160000000L 143 | board_build.f_flash = 80000000L 144 | board_build.flash_mode = qio 145 | board_build.arduino.ldscript = esp32c3_out.ld 146 | build_unflags = 147 | -DARDUINO_ESP32_DEV 148 | -DARDUINO_VARIANT="esp32" 149 | build_flags = 150 | -DARDUINO_ESP32S3_DEV 151 | -DARDUINO_VARIANT="esp32c3" 152 | -------------------------------------------------------------------------------- /examples/PWM_Waveform/PWM_Waveform.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_Waveform.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #include "ESP32_FastPWM.h" 22 | 23 | #if ARDUINO_ESP32C3_DEV 24 | #define pinToUse 9 25 | #else 26 | #define pinToUse 16 27 | #endif 28 | 29 | // Max resolution is 20-bit 30 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 31 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 32 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 33 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 34 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 35 | int PWM_resolution = 12; 36 | 37 | //creates pwm instance 38 | ESP32_FAST_PWM* PWM_Instance; 39 | 40 | typedef struct 41 | { 42 | uint16_t level; 43 | } PWD_Data; 44 | 45 | // Data for 0-100% 46 | PWD_Data PWM_data[] = 47 | { 48 | { 0 }, 49 | { 5 }, 50 | { 10 }, 51 | { 15 }, 52 | { 20 }, 53 | { 25 }, 54 | { 30 }, 55 | { 35 }, 56 | { 40 }, 57 | { 45 }, 58 | { 50 }, 59 | { 55 }, 60 | { 60 }, 61 | { 65 }, 62 | { 70 }, 63 | { 75 }, 64 | { 80 }, 65 | { 85 }, 66 | { 90 }, 67 | { 95 }, 68 | { 100 }, 69 | { 95 }, 70 | { 90 }, 71 | { 85 }, 72 | { 80 }, 73 | { 75 }, 74 | { 70 }, 75 | { 65 }, 76 | { 60 }, 77 | { 55 }, 78 | { 50 }, 79 | { 45 }, 80 | { 40 }, 81 | { 35 }, 82 | { 30 }, 83 | { 25 }, 84 | { 20 }, 85 | { 15 }, 86 | { 10 }, 87 | { 5 }, 88 | { 0 }, 89 | }; 90 | 91 | #define NUM_PWM_POINTS ( sizeof(PWM_data) / sizeof(PWD_Data) ) 92 | 93 | float frequency = 1000.0f; 94 | float dutyCycle = 0.0f; 95 | 96 | uint8_t channel = 0; 97 | 98 | // You can select any value 99 | PWD_Data PWM_data_idle = PWM_data[0]; 100 | 101 | char dashLine[] = "============================================================================================"; 102 | 103 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 104 | { 105 | Serial.println(dashLine); 106 | Serial.print("Actual data: pin = "); 107 | Serial.print(PWM_Instance->getPin()); 108 | Serial.print(", PWM DutyCycle = "); 109 | Serial.print(PWM_Instance->getActualDutyCycle()); 110 | Serial.print(", PWMPeriod = "); 111 | Serial.print(PWM_Instance->getPWMPeriod()); 112 | Serial.print(", PWM Freq (Hz) = "); 113 | Serial.println(PWM_Instance->getActualFreq(), 4); 114 | Serial.println(dashLine); 115 | } 116 | 117 | void setup() 118 | { 119 | Serial.begin(115200); 120 | 121 | while (!Serial && millis() < 5000); 122 | 123 | delay(500); 124 | 125 | Serial.print(F("\nStarting PWM_Waveform on ")); 126 | Serial.println(ARDUINO_BOARD); 127 | Serial.println(ESP32_FAST_PWM_VERSION); 128 | 129 | // Create a dummy instance 130 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, dutyCycle, channel, PWM_resolution); 131 | 132 | if (PWM_Instance) 133 | { 134 | // setPWM_manual(uint8_t pin, uint16_t level) 135 | PWM_Instance->setPWM(pinToUse, frequency, 0); 136 | 137 | printPWMInfo(PWM_Instance); 138 | } 139 | } 140 | 141 | void updateDC() 142 | { 143 | static uint16_t index = 0; 144 | 145 | static uint32_t actualDC; 146 | 147 | actualDC = (uint32_t) PWM_data[index].level * (1 << PWM_resolution) / 100; 148 | 149 | // Mapping data according to resolution 150 | PWM_Instance->setPWM_manual(pinToUse, actualDC ); 151 | 152 | // Use at low freq to check 153 | //printPWMInfo(PWM_Instance); 154 | 155 | index = (index + 1) % NUM_PWM_POINTS; 156 | } 157 | 158 | void check_status() 159 | { 160 | #define UPDATE_INTERVAL 100L 161 | 162 | static unsigned long update_timeout = UPDATE_INTERVAL; 163 | 164 | // Update DC every UPDATE_INTERVAL (100) milliseconds 165 | if (millis() > update_timeout) 166 | { 167 | updateDC(); 168 | update_timeout = millis() + UPDATE_INTERVAL; 169 | } 170 | } 171 | 172 | void loop() 173 | { 174 | check_status(); 175 | } 176 | -------------------------------------------------------------------------------- /examples/PWM_SpeedTest/PWM_SpeedTest.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_SpeedTest.ino 3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 4 | Written by Khoi Hoang 5 | 6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 7 | Licensed under MIT license 8 | 9 | This is pure hardware-based PWM 10 | *****************************************************************************************************************************/ 11 | /****************************************************************************************************************************** 12 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 13 | // For ESP32, number of channels is 16, max 20-bit resolution 14 | // For ESP32_S2, ESP32_S3, number of channels is 8 15 | // For ESP32_C3, number of channels is 6 16 | ******************************************************************************************************************************/ 17 | 18 | #define _PWM_LOGLEVEL_ 1 19 | 20 | #include "ESP32_FastPWM.h" 21 | 22 | #define UPDATE_INTERVAL 1000L 23 | 24 | #if ARDUINO_ESP32C3_DEV 25 | #define pinToUse 9 26 | #else 27 | #define pinToUse 16 28 | #endif 29 | 30 | // Max resolution is 20-bit 31 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 32 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 33 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 34 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 35 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 36 | int PWM_resolution = 10; 37 | 38 | ESP32_FAST_PWM* PWM_Instance; 39 | 40 | float frequency = 1000.0f; 41 | //float frequency = 10000.0f; 42 | 43 | // Using setPWM_DCPercentage_manual if true 44 | //#define USING_DC_PERCENT false 45 | #define USING_DC_PERCENT true 46 | 47 | #if USING_DC_PERCENT 48 | float dutycyclePercent = 0.0f; 49 | float DCStepPercent = 5.0f; 50 | #else 51 | uint16_t dutycycle = 0; 52 | uint16_t DCStep; 53 | #endif 54 | 55 | // Max resolution is 20-bit 56 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 57 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 58 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 59 | // Resolution 256 ( 8-bit) for higher frequencies, OK @ 100K, 200K 60 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 61 | uint8_t resolution = 16; 62 | uint8_t channel = 0; 63 | 64 | uint16_t PWMPeriod; 65 | 66 | char dashLine[] = "================================================================================================="; 67 | 68 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 69 | { 70 | Serial.println(dashLine); 71 | Serial.print("Actual data: pin = "); 72 | Serial.print(PWM_Instance->getPin()); 73 | Serial.print(", PWM DC = "); 74 | Serial.print(PWM_Instance->getActualDutyCycle()); 75 | Serial.print(", PWMPeriod = "); 76 | Serial.print(PWM_Instance->getPWMPeriod()); 77 | Serial.print(", PWM Freq (Hz) = "); 78 | Serial.println(PWM_Instance->getActualFreq(), 4); 79 | Serial.println(dashLine); 80 | } 81 | 82 | void setup() 83 | { 84 | Serial.begin(115200); 85 | 86 | while (!Serial && millis() < 5000); 87 | 88 | delay(100); 89 | 90 | Serial.print(F("\nStarting PWM_SpeedTest on ")); 91 | Serial.println(ARDUINO_BOARD); 92 | Serial.println(ESP32_FAST_PWM_VERSION); 93 | 94 | // Create a dummy instance 95 | // channel 0, 16-bit resolution 96 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 0, channel, resolution); 97 | // Default channel 0, 8-bit resolution 98 | //PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 0); 99 | 100 | if (PWM_Instance) 101 | { 102 | PWM_Instance->setPWM(); 103 | 104 | #if USING_DC_PERCENT 105 | dutycyclePercent = 50.0f; 106 | #else 107 | // 5% steps 108 | DCStep = round( PWMPeriod / 20.0f); 109 | 110 | // 50% 111 | dutycycle = PWMPeriod / 2; 112 | #endif 113 | 114 | printPWMInfo(PWM_Instance); 115 | } 116 | 117 | Serial.print(F("Average time of setPWM function")); 118 | 119 | #if USING_DC_PERCENT 120 | Serial.println(F(" USING_DC_PERCENT")); 121 | #else 122 | Serial.println(F(" not USING_DC_PERCENT")); 123 | #endif 124 | } 125 | 126 | void loop() 127 | { 128 | static unsigned long update_timeout = UPDATE_INTERVAL + millis(); 129 | static uint64_t count = 0; 130 | 131 | #if USING_DC_PERCENT 132 | // 12726ns 133 | PWM_Instance->setPWM_DCPercentage_manual(pinToUse, dutycyclePercent); 134 | #else 135 | // 12488ns 136 | PWM_Instance->setPWM_manual(pinToUse, dutycycle); 137 | #endif 138 | 139 | count++; 140 | 141 | // Update DC every UPDATE_INTERVAL (1000) milliseconds 142 | if (millis() > update_timeout) 143 | { 144 | Serial.print(F("ns=")); 145 | Serial.println(UPDATE_INTERVAL * 1000000 / count); 146 | 147 | count = 0; 148 | update_timeout = millis() + UPDATE_INTERVAL; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /examples/PWM_manual/PWM_manual.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_manual.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | ******************************************************************************************************************************/ 18 | 19 | #define _PWM_LOGLEVEL_ 4 20 | 21 | #define UPDATE_INTERVAL 1000L 22 | 23 | // Using setPWM_DCPercentage_manual if true 24 | #define USING_DC_PERCENT true 25 | 26 | #include "ESP32_FastPWM.h" 27 | 28 | #if ARDUINO_ESP32C3_DEV 29 | #define pinToUse 9 30 | #else 31 | #define pinToUse 16 32 | #endif 33 | 34 | // Max resolution is 20-bit 35 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 36 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 37 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 38 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 39 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 40 | int PWM_resolution = 10; 41 | 42 | ESP32_FAST_PWM* PWM_Instance; 43 | 44 | float frequency = 1000.0f; 45 | 46 | #if USING_DC_PERCENT 47 | float dutycyclePercent = 0.0f; 48 | float DCStepPercent = 5.0f; 49 | #else 50 | uint16_t dutycycle = 0; 51 | uint16_t DCStep; 52 | #endif 53 | 54 | // Max resolution is 20-bit 55 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 56 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 57 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 58 | // Resolution 256 ( 8-bit) for higher frequencies, OK @ 100K, 200K 59 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 60 | uint8_t resolution = 16; 61 | uint8_t channel = 0; 62 | 63 | char dashLine[] = "================================================================================================="; 64 | 65 | 66 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 67 | { 68 | Serial.println(dashLine); 69 | Serial.print("Actual data: pin = "); 70 | Serial.print(PWM_Instance->getPin()); 71 | Serial.print(", PWM DC = "); 72 | Serial.print(PWM_Instance->getActualDutyCycle()); 73 | Serial.print(", PWMPeriod = "); 74 | Serial.print(PWM_Instance->getPWMPeriod()); 75 | Serial.print(", PWM Freq (Hz) = "); 76 | Serial.println(PWM_Instance->getActualFreq(), 4); 77 | Serial.println(dashLine); 78 | } 79 | 80 | void setup() 81 | { 82 | Serial.begin(115200); 83 | 84 | while (!Serial && millis() < 5000); 85 | 86 | delay(100); 87 | 88 | Serial.print(F("\nStarting PWM_manual on ")); 89 | Serial.println(ARDUINO_BOARD); 90 | Serial.println(ESP32_FAST_PWM_VERSION); 91 | 92 | // Create a dummy instance 93 | // channel 0, 16-bit resolution 94 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 0, channel, resolution); 95 | // Default channel 0, 8-bit resolution 96 | //PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, 0); 97 | 98 | if (PWM_Instance) 99 | { 100 | PWM_Instance->setPWM(); 101 | 102 | //printPWMInfo(PWM_Instance); 103 | } 104 | else 105 | { 106 | Serial.print(F("Stop here forever")); 107 | 108 | while (true) 109 | delay(10000); 110 | } 111 | 112 | #if !USING_DC_PERCENT 113 | // 5% steps 114 | DCStep = round((1 << resolution) / 20.0f); 115 | #endif 116 | } 117 | 118 | void loop() 119 | { 120 | static unsigned long update_timeout = UPDATE_INTERVAL; 121 | 122 | // Update DC every UPDATE_INTERVAL (1000) milliseconds 123 | if (millis() > update_timeout) 124 | { 125 | #if USING_DC_PERCENT 126 | PWM_Instance->setPWM_DCPercentage_manual(pinToUse, dutycyclePercent); 127 | 128 | dutycyclePercent += DCStepPercent; 129 | 130 | if (dutycyclePercent > 100.0f) 131 | dutycyclePercent = 0.0f; 132 | #else 133 | if (dutycycle > (1 << resolution)) 134 | { 135 | PWM_Instance->setPWM_manual(pinToUse, (1 << resolution)); 136 | dutycycle = 0; 137 | } 138 | else 139 | { 140 | // Funny kludge to get around ESP32 bug, adding 4 to dutycycle each loop !!! 141 | if (dutycycle < DCStep) 142 | dutycycle = 0; 143 | 144 | PWM_Instance->setPWM_manual(pinToUse, dutycycle); 145 | dutycycle += DCStep; 146 | } 147 | #endif 148 | 149 | printPWMInfo(PWM_Instance); 150 | 151 | update_timeout = millis() + UPDATE_INTERVAL; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /examples/PWM_Multi/PWM_Multi.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_Multi.ino 3 | 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | This is pure hardware-based PWM 11 | *****************************************************************************************************************************/ 12 | /****************************************************************************************************************************** 13 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 14 | // For ESP32, number of channels is 16, max 20-bit resolution 15 | // For ESP32_S2, ESP32_S3, number of channels is 8 16 | // For ESP32_C3, number of channels is 6 17 | 18 | LEDC Chan to Group/Channel/Timer Mapping 19 | ** ledc: 0 => Group: 0, Channel: 0, Timer: 0 20 | ** ledc: 1 => Group: 0, Channel: 1, Timer: 0 21 | ** ledc: 2 => Group: 0, Channel: 2, Timer: 1 22 | ** ledc: 3 => Group: 0, Channel: 3, Timer: 1 23 | ** ledc: 4 => Group: 0, Channel: 4, Timer: 2 24 | ** ledc: 5 => Group: 0, Channel: 5, Timer: 2 25 | ** ledc: 6 => Group: 0, Channel: 6, Timer: 3 26 | ** ledc: 7 => Group: 0, Channel: 7, Timer: 3 27 | ** ledc: 8 => Group: 1, Channel: 0, Timer: 0 28 | ** ledc: 9 => Group: 1, Channel: 1, Timer: 0 29 | ** ledc: 10 => Group: 1, Channel: 2, Timer: 1 30 | ** ledc: 11 => Group: 1, Channel: 3, Timer: 1 31 | ** ledc: 12 => Group: 1, Channel: 4, Timer: 2 32 | ** ledc: 13 => Group: 1, Channel: 5, Timer: 2 33 | ** ledc: 14 => Group: 1, Channel: 6, Timer: 3 34 | ** ledc: 15 => Group: 1, Channel: 7, Timer: 3 35 | 36 | ******************************************************************************************************************************/ 37 | 38 | #define _PWM_LOGLEVEL_ 4 39 | 40 | #include "ESP32_FastPWM.h" 41 | 42 | #define pinToUse 16 43 | 44 | // Max resolution is 20-bit 45 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 46 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 47 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 48 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 49 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 50 | int PWM_resolution = 12; 51 | 52 | #if ARDUINO_ESP32C3_DEV 53 | uint32_t PWM_Pins[] = { 8, 9, 2, 3 }; 54 | #else 55 | uint32_t PWM_Pins[] = { 16, 17, 19, 21 }; 56 | #endif 57 | 58 | // Must use different group-timer for different frequency 59 | // e.g. chan 0 (Group0-T0) and chan8(Group1-T0) OK for dif. freq, but not chan0(Group0-T0) and chan1(Group0-T0) 60 | // timer = ((chan / 2) % 4) 61 | // group = (chan / 8) 62 | // For ESP32 63 | // Group 0: channel 0-1 => timer0, channel 2-3 => timer1, channel 4-5 => timer2, channel 6-7 => timer3 64 | // Group 1: channel 8-9 => timer0, channel 10-11 => timer1, channel 12-13 => timer2, channel 14-15 => timer3 65 | uint32_t PWM_chan[] = { 0, 2, 4, 6 }; 66 | 67 | // Still OK if different freq 68 | //uint32_t PWM_chan[] = { 0, 8, 4, 6 }; 69 | // Not OK if different freq 70 | //uint32_t PWM_chan[] = { 0, 1, 4, 6 }; 71 | 72 | #define NUM_OF_PINS ( sizeof(PWM_Pins) / sizeof(uint32_t) ) 73 | 74 | float dutyCycle[] = { 10.0f, 30.0f, 50.0f, 90.0f }; 75 | 76 | float frequency[] = { 2000.0f, 3000.0f, 4000.0f, 8000.0f }; 77 | 78 | ESP32_FAST_PWM* PWM_Instance[NUM_OF_PINS]; 79 | 80 | char dashLine[] = "====================================================================================="; 81 | 82 | void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) 83 | { 84 | Serial.println(dashLine); 85 | Serial.print("Actual data: pin = "); 86 | Serial.print(PWM_Instance->getPin()); 87 | Serial.print(", PWM DC = "); 88 | Serial.print(PWM_Instance->getActualDutyCycle()); 89 | Serial.print(", PWMPeriod = "); 90 | Serial.print(PWM_Instance->getPWMPeriod()); 91 | Serial.print(", PWM Freq (Hz) = "); 92 | Serial.println(PWM_Instance->getActualFreq(), 4); 93 | Serial.println(dashLine); 94 | } 95 | 96 | void setup() 97 | { 98 | Serial.begin(115200); 99 | 100 | while (!Serial && millis() < 5000); 101 | 102 | delay(500); 103 | 104 | Serial.print(F("\nStarting PWM_Multi on ")); 105 | Serial.println(ARDUINO_BOARD); 106 | Serial.println(ESP32_FAST_PWM_VERSION); 107 | 108 | for (uint8_t index = 0; index < NUM_OF_PINS; index++) 109 | { 110 | PWM_Instance[index] = new ESP32_FAST_PWM(PWM_Pins[index], frequency[index], dutyCycle[index], PWM_chan[index], 111 | PWM_resolution); 112 | 113 | if (PWM_Instance[index]) 114 | { 115 | PWM_Instance[index]->setPWM(); 116 | } 117 | } 118 | 119 | Serial.println(dashLine); 120 | Serial.println("Index\tPin\tPWM_freq\tDutyCycle\tActual Freq"); 121 | Serial.println(dashLine); 122 | 123 | for (uint8_t index = 0; index < NUM_OF_PINS; index++) 124 | { 125 | if (PWM_Instance[index]) 126 | { 127 | Serial.print(index); 128 | Serial.print("\t"); 129 | Serial.print(PWM_Pins[index]); 130 | Serial.print("\t"); 131 | Serial.print(frequency[index]); 132 | Serial.print("\t\t"); 133 | Serial.print(dutyCycle[index]); 134 | Serial.print("\t\t"); 135 | Serial.println(PWM_Instance[index]->getActualFreq(), 4); 136 | } 137 | else 138 | { 139 | Serial.println(); 140 | } 141 | } 142 | 143 | for (uint8_t index = 0; index < NUM_OF_PINS; index++) 144 | { 145 | printPWMInfo(PWM_Instance[index]); 146 | } 147 | } 148 | 149 | void loop() 150 | { 151 | //Long delay has no effect on the operation of hardware-based PWM channels 152 | delay(1000000); 153 | } 154 | -------------------------------------------------------------------------------- /src/PWM_Generic_Debug.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | PWM_GENERIC_Debug.h 3 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 4 | Written by Khoi Hoang 5 | 6 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 7 | Licensed under MIT license 8 | 9 | Version: 1.1.0 10 | 11 | Version Modified By Date Comments 12 | ------- ----------- ---------- ----------- 13 | 1.0.0 K Hoang 31/10/2022 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+ 14 | 1.0.1 K Hoang 22/01/2023 Add `PWM_StepperControl` example 15 | 1.1.0 K Hoang 25/01/2023 Add `PWM_manual` example and function 16 | *****************************************************************************************************************************/ 17 | 18 | #pragma once 19 | 20 | #ifndef PWM_GENERIC_DEBUG_H 21 | #define PWM_GENERIC_DEBUG_H 22 | 23 | #ifdef PWM_GENERIC_DEBUG_PORT 24 | #define PWM_DBG_PORT PWM_GENERIC_DEBUG_PORT 25 | #else 26 | #define PWM_DBG_PORT Serial 27 | #endif 28 | 29 | // Change _PWM_LOGLEVEL_ to set tracing and logging verbosity 30 | // 0: DISABLED: no logging 31 | // 1: ERROR: errors 32 | // 2: WARN: errors and warnings 33 | // 3: INFO: errors, warnings and informational (default) 34 | // 4: DEBUG: errors, warnings, informational and debug 35 | 36 | #ifndef _PWM_LOGLEVEL_ 37 | #define _PWM_LOGLEVEL_ 1 38 | #endif 39 | 40 | /////////////////////////////////////// 41 | 42 | const char PWM_MARK[] = "[PWM] "; 43 | const char PWM_SPACE[] = " "; 44 | 45 | #define PWM_PRINT PWM_DBG_PORT.print 46 | #define PWM_PRINTLN PWM_DBG_PORT.println 47 | 48 | #define PWM_PRINT_MARK PWM_PRINT(PWM_MARK) 49 | #define PWM_PRINT_SP PWM_PRINT(PWM_SPACE) 50 | #define PWM_PRINT_LINE PWM_PRINT(PWM_LINE) 51 | 52 | /////////////////////////////////////// 53 | 54 | #define PWM_LOGERROR0(x) if(_PWM_LOGLEVEL_>0) { PWM_PRINT(x); } 55 | #define PWM_LOGERROR(x) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINTLN(x); } 56 | #define PWM_LOGERROR1(x,y) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINTLN(y); } 57 | #define PWM_HEXLOGERROR1(x,y) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } 58 | #define PWM_LOGERROR2(x,y,z) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINTLN(z); } 59 | #define PWM_LOGERROR3(x,y,z,w) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINTLN(w); } 60 | #define PWM_LOGERROR5(x,y,z,w,xx,yy) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINTLN(yy); } 61 | #define PWM_LOGERROR7(x,y,z,w,xx,yy,zz,ww) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINT(yy); PWM_PRINT_SP; PWM_PRINT(zz); PWM_PRINT_SP; PWM_PRINTLN(ww); } 62 | 63 | ////////////////////////////////////////// 64 | 65 | #define PWM_LOGWARN0(x) if(_PWM_LOGLEVEL_>1) { PWM_PRINT(x); } 66 | #define PWM_LOGWARN(x) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINTLN(x); } 67 | #define PWM_LOGWARN1(x,y) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINTLN(y); } 68 | #define PWM_HEXLOGWARN1(x,y) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } 69 | #define PWM_LOGWARN2(x,y,z) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINTLN(z); } 70 | #define PWM_LOGWARN3(x,y,z,w) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINTLN(w); } 71 | #define PWM_LOGWARN5(x,y,z,w,xx,yy) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINTLN(yy); } 72 | #define PWM_LOGWARN7(x,y,z,w,xx,yy,zz,ww) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINT(yy); PWM_PRINT_SP; PWM_PRINT(zz); PWM_PRINT_SP; PWM_PRINTLN(ww); } 73 | 74 | ////////////////////////////////////////// 75 | 76 | #define PWM_LOGINFO0(x) if(_PWM_LOGLEVEL_>2) { PWM_PRINT(x); } 77 | #define PWM_LOGINFO(x) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINTLN(x); } 78 | #define PWM_LOGINFO1(x,y) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINTLN(y); } 79 | #define PWM_HEXLOGINFO1(x,y) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } 80 | #define PWM_LOGINFO2(x,y,z) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINTLN(z); } 81 | #define PWM_LOGINFO3(x,y,z,w) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINTLN(w); } 82 | #define PWM_LOGINFO5(x,y,z,w,xx,yy) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINTLN(yy); } 83 | #define PWM_LOGINFO7(x,y,z,w,xx,yy,zz,ww) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINT(yy); PWM_PRINT_SP; PWM_PRINT(zz); PWM_PRINT_SP; PWM_PRINTLN(ww); } 84 | 85 | ////////////////////////////////////////// 86 | 87 | #define PWM_LOGDEBUG0(x) if(_PWM_LOGLEVEL_>3) { PWM_PRINT(x); } 88 | #define PWM_LOGDEBUG(x) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINTLN(x); } 89 | #define PWM_LOGDEBUG1(x,y) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINTLN(y); } 90 | #define PWM_HEXLOGDEBUG1(x,y) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } 91 | #define PWM_LOGDEBUG2(x,y,z) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINTLN(z); } 92 | #define PWM_LOGDEBUG3(x,y,z,w) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINTLN(w); } 93 | #define PWM_LOGDEBUG5(x,y,z,w,xx,yy) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINTLN(yy); } 94 | #define PWM_LOGDEBUG7(x,y,z,w,xx,yy,zz,ww) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINT(y); PWM_PRINT_SP; PWM_PRINT(z); PWM_PRINT_SP; PWM_PRINT(w); PWM_PRINT_SP; PWM_PRINT(xx); PWM_PRINT_SP; PWM_PRINT(yy); PWM_PRINT_SP; PWM_PRINT(zz); PWM_PRINT_SP; PWM_PRINTLN(ww); } 95 | 96 | ////////////////////////////////////////// 97 | 98 | /////////////////////////////////////// 99 | 100 | #endif //PWM_GENERIC_DEBUG_H 101 | -------------------------------------------------------------------------------- /src/ESP32_FastPWM.h: -------------------------------------------------------------------------------- 1 | 2 | /**************************************************************************************************************************** 3 | ESP32_FastPWM.h 4 | For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ 5 | Written by Khoi Hoang 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/ESP32_FastPWM 8 | Licensed under MIT license 9 | 10 | Version: 1.1.0 11 | 12 | Version Modified By Date Comments 13 | ------- ----------- ---------- ----------- 14 | 1.0.0 K Hoang 31/10/2022 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+ 15 | 1.0.1 K Hoang 22/01/2023 Add `PWM_StepperControl` example 16 | 1.1.0 K Hoang 25/01/2023 Add `PWM_manual` example and function 17 | *****************************************************************************************************************************/ 18 | 19 | #pragma once 20 | 21 | #ifndef ESP32_FAST_PWM_HPP 22 | #define ESP32_FAST_PWM_HPP 23 | 24 | #if !defined( ESP32 ) 25 | #error This code is designed to run on ESP32 platform, not Arduino nor ESP8266! Please check your Tools->Board setting. 26 | #endif 27 | 28 | #if ( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \ 29 | ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \ 30 | ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM || ARDUINO_ADAFRUIT_QTPY_ESP32S2) 31 | #define FAST_PWM_USING_ESP32_S2 true 32 | #elif ( defined(ARDUINO_ESP32S3_DEV) || defined(ARDUINO_ESP32_S3_BOX) || defined(ARDUINO_TINYS3) || \ 33 | defined(ARDUINO_PROS3) || defined(ARDUINO_FEATHERS3) || defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_NOPSRAM) || \ 34 | defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM)) 35 | #define FAST_PWM_USING_ESP32_S3 true 36 | #elif ( ARDUINO_ESP32C3_DEV ) 37 | #define FAST_PWM_USING_ESP32_C3 true 38 | #elif defined(ESP32) 39 | #define FAST_PWM_USING_ESP32 true 40 | #else 41 | #error This code is ready to run on the ESP32 platform! Please check your Tools->Board setting. 42 | #endif 43 | 44 | #if defined(ARDUINO) 45 | #if ARDUINO >= 100 46 | #include 47 | #else 48 | #include 49 | #endif 50 | #endif 51 | 52 | #ifndef ESP32_FAST_PWM_VERSION 53 | #define ESP32_FAST_PWM_VERSION F("ESP32_FastPWM v1.1.0") 54 | 55 | #define ESP32_FAST_PWM_VERSION_MAJOR 1 56 | #define ESP32_FAST_PWM_VERSION_MINOR 1 57 | #define ESP32_FAST_PWM_VERSION_PATCH 0 58 | 59 | #define ESP32_FAST_PWM_VERSION_INT 1001000 60 | #endif 61 | 62 | #include "PWM_Generic_Debug.h" 63 | 64 | #include "driver/ledc.h" 65 | 66 | #define INVALID_ESP32_PIN 255 67 | 68 | //////////////////////////////////////// 69 | 70 | 71 | /* 72 | ESP32 LEDC Chan to Group/Channel/Timer Mapping 73 | ** ledc: 0 => Group: 0, Channel: 0, Timer: 0 74 | ** ledc: 1 => Group: 0, Channel: 1, Timer: 0 75 | ** ledc: 2 => Group: 0, Channel: 2, Timer: 1 76 | ** ledc: 3 => Group: 0, Channel: 3, Timer: 1 77 | ** ledc: 4 => Group: 0, Channel: 4, Timer: 2 78 | ** ledc: 5 => Group: 0, Channel: 5, Timer: 2 79 | ** ledc: 6 => Group: 0, Channel: 6, Timer: 3 80 | ** ledc: 7 => Group: 0, Channel: 7, Timer: 3 81 | ** ledc: 8 => Group: 1, Channel: 0, Timer: 0 82 | ** ledc: 9 => Group: 1, Channel: 1, Timer: 0 83 | ** ledc: 10 => Group: 1, Channel: 2, Timer: 1 84 | ** ledc: 11 => Group: 1, Channel: 3, Timer: 1 85 | ** ledc: 12 => Group: 1, Channel: 4, Timer: 2 86 | ** ledc: 13 => Group: 1, Channel: 5, Timer: 2 87 | ** ledc: 14 => Group: 1, Channel: 6, Timer: 3 88 | ** ledc: 15 => Group: 1, Channel: 7, Timer: 3 89 | */ 90 | 91 | #define MAX_COUNT_16BIT 65536UL 92 | 93 | // Max resolution is 20-bit 94 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 95 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 96 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 97 | // Resolution 256 ( 8-bit) for higher frequencies, OK @ 100K, 200K 98 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 99 | #define MAX_PWM_RESOLUTION_BIT SOC_LEDC_TIMER_BIT_WIDE_NUM 100 | #define MAX_PWM_RESOLUTION (1 << SOC_LEDC_TIMER_BIT_WIDE_NUM) 101 | 102 | //////////////////////////////////////// 103 | 104 | 105 | #ifdef SOC_LEDC_SUPPORT_HS_MODE 106 | #define _LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM << 1) 107 | #else 108 | #define _LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM) 109 | #endif 110 | 111 | static uint8_t channels_resolution[_LEDC_CHANNELS] = {0}; 112 | 113 | class ESP32_FAST_PWM 114 | { 115 | public: 116 | 117 | // Default 8-bit for higher freqs 118 | // dutycycle = 0.0f - 100.0f 119 | ESP32_FAST_PWM(const uint8_t& pin, const float& frequency, const float& dutycycle, 120 | const uint8_t& channel = 0, const float& resolution = 8) 121 | { 122 | if (resolution <= SOC_LEDC_TIMER_BIT_WIDE_NUM) 123 | _resolution = resolution; 124 | else 125 | { 126 | _resolution = SOC_LEDC_TIMER_BIT_WIDE_NUM; 127 | PWM_LOGERROR1(F("ESP32_FastPWM: _resolution too big, reset to"), SOC_LEDC_TIMER_BIT_WIDE_NUM); 128 | } 129 | 130 | if (channel <= _LEDC_CHANNELS) 131 | _channel = (ledc_channel_t) channel; 132 | else 133 | { 134 | _channel = (ledc_channel_t) _LEDC_CHANNELS; 135 | PWM_LOGERROR1(F("ESP32_FastPWM: _channel too big, reset to"), _LEDC_CHANNELS); 136 | } 137 | 138 | if (channels_resolution[_channel] == 0) 139 | { 140 | PWM_LOGDEBUG1(F("ESP32_FastPWM: new _channel ="), _channel); 141 | channels_resolution[_channel] = _resolution; 142 | } 143 | else if (channels_resolution[_channel] != _resolution) 144 | { 145 | PWM_LOGDEBUG3(F("ESP32_FastPWM: Change resolution of used _channel ="), _channel, F("to"), _resolution); 146 | channels_resolution[_channel] = _resolution; 147 | } 148 | 149 | _group = (ledc_mode_t) (_channel / 8); 150 | _timer = (_channel / 2) % 4; 151 | 152 | _pin = pin; 153 | _frequency = frequency; 154 | 155 | _dutycycle = round(map(dutycycle, 0, 100.0f, 0, MAX_COUNT_16BIT)); 156 | 157 | PWM_LOGDEBUG5(F("ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM ="), SOC_LEDC_CHANNEL_NUM, F(", LEDC_CHANNELS ="), _LEDC_CHANNELS, 158 | F(", LEDC_MAX_BIT_WIDTH ="), SOC_LEDC_TIMER_BIT_WIDE_NUM); 159 | 160 | PWM_LOGDEBUG1(F("ESP32_FastPWM: _dutycycle ="), _dutycycle); 161 | 162 | pinMode(pin, OUTPUT); 163 | 164 | ledcSetup(_channel, frequency, _resolution); 165 | ledcAttachPin(pin, _channel); 166 | } 167 | 168 | /////////////////////////////////////////// 169 | 170 | ~ESP32_FAST_PWM(); 171 | 172 | /////////////////////////////////////////// 173 | /////////////////////////////////////////// 174 | 175 | private: 176 | 177 | 178 | /////////////////////////////////////////// 179 | /////////////////////////////////////////// 180 | 181 | public: 182 | 183 | // dutycycle from 0-65535 for 0%-100% 184 | bool setPWM_Int(const uint8_t& pin, const float& frequency, const uint16_t& dutycycle) 185 | { 186 | // Convert to new resolution 187 | if ( _resolution < 16 ) 188 | _dutycycle = dutycycle >> (16 - _resolution); 189 | else if ( _resolution > 16 ) 190 | _dutycycle = dutycycle << (_resolution - 16); 191 | 192 | PWM_LOGDEBUG3(F("setPWM_Int: _dutycycle ="), _dutycycle, 193 | F(", DC % ="), _dutycycle * 100.0f / (1 << _resolution) ); 194 | 195 | // Reprogram freq if necessary 196 | if ( frequency != _frequency) 197 | { 198 | PWM_LOGDEBUG3(F("setPWM_Int: change frequency to"), frequency, F("from"), _frequency); 199 | 200 | _frequency = frequency; 201 | 202 | // To avoid glitch when changing frequency 203 | // esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz); 204 | ledc_set_freq(_group, (ledc_timer_t) _timer, frequency); 205 | } 206 | 207 | if (dutycycle == 0) 208 | { 209 | digitalWrite(pin, LOW); 210 | } 211 | else if (dutycycle >= (MAX_COUNT_16BIT - 1) ) 212 | { 213 | digitalWrite(pin, HIGH); 214 | } 215 | else 216 | { 217 | ledcWrite(_channel, _dutycycle); 218 | } 219 | 220 | return true; 221 | } 222 | 223 | /////////////////////////////////////////// 224 | 225 | bool setPWM() 226 | { 227 | return setPWM_Int(_pin, _frequency, _dutycycle); 228 | } 229 | 230 | /////////////////////////////////////////// 231 | 232 | bool setPWM(const uint8_t& pin, const float& frequency, const float& dutycycle) 233 | { 234 | _dutycycle = round(map(dutycycle, 0, 100.0f, 0, MAX_COUNT_16BIT)); 235 | 236 | PWM_LOGDEBUG3(F("setPWM: _dutycycle ="), _dutycycle, F(", frequency ="), frequency); 237 | 238 | return setPWM_Int(pin, frequency, _dutycycle); 239 | } 240 | 241 | /////////////////////////////////////////// 242 | 243 | bool setPWM_Period(const uint8_t& pin, const float& period_us, const float& dutycycle) 244 | { 245 | _dutycycle = round(map(dutycycle, 0, 100.0f, 0, MAX_COUNT_16BIT)); 246 | 247 | PWM_LOGDEBUG3(F("setPWM_Period: _dutycycle ="), _dutycycle, F(", period_us ="), period_us); 248 | 249 | return setPWM_Int(pin, round(1000000.0f / period_us), _dutycycle); 250 | } 251 | 252 | /////////////////////////////////////////// 253 | 254 | // Must have same frequency 255 | bool setPWM_manual(const uint8_t& pin, const uint16_t& DCValue) 256 | { 257 | // Not the same pin or overvalue 258 | if ( (_pin != pin) || (DCValue > (1 << _resolution) ) ) 259 | { 260 | PWM_LOGDEBUG3(F("setPWM_manual: Error! DCValue ="), DCValue, F(" > 1 << _resolution ="), 1 << _resolution); 261 | 262 | return false; 263 | } 264 | 265 | _dutycycle = (uint32_t) DCValue; 266 | 267 | ledc_set_duty(_group, _channel, DCValue); 268 | ledc_update_duty(_group, _channel); 269 | 270 | 271 | PWM_LOGDEBUG3(F("setPWM_manual: DCValue ="), DCValue, F(", _frequency ="), _frequency); 272 | 273 | return true; 274 | } 275 | 276 | /////////////////////////////////////////// 277 | 278 | // DCPercentage from 0.0f - 100.0f 279 | bool setPWM_DCPercentage_manual(const uint8_t& pin, const float& DCPercentage) 280 | { 281 | return setPWM_manual(pin, ( DCPercentage * (1 << _resolution) ) / 100.0f); 282 | } 283 | 284 | /////////////////////////////////////////// 285 | 286 | inline float getActualDutyCycle() 287 | { 288 | return ( (float) _dutycycle * 100 / (1 << _resolution) ); 289 | } 290 | 291 | /////////////////////////////////////////// 292 | 293 | inline float getActualFreq() 294 | { 295 | return _frequency; 296 | } 297 | 298 | /////////////////////////////////////////// 299 | 300 | inline float getPWMPeriod() 301 | { 302 | return (1000000.0f / _frequency); 303 | } 304 | 305 | /////////////////////////////////////////// 306 | 307 | inline uint32_t get_freq_CPU() 308 | { 309 | return F_CPU; 310 | } 311 | 312 | /////////////////////////////////////////// 313 | 314 | inline uint32_t getPin() 315 | { 316 | return _pin; 317 | } 318 | 319 | /////////////////////////////////////////// 320 | 321 | inline uint32_t getResolution() 322 | { 323 | return _resolution; 324 | } 325 | 326 | /////////////////////////////////////////////////////////////////// 327 | 328 | private: 329 | 330 | float _frequency; 331 | 332 | // dutycycle from 0-65535 for 0%-100% to make use of 16-bit top register 333 | // _dutycycle = round(map(dutycycle, 0, 100.0f, 0, MAX_COUNT_16BIT)) for better accuracy 334 | uint32_t _dutycycle; 335 | ////////// 336 | 337 | uint8_t _pin; 338 | 339 | #define INVALID_TIMER 255 340 | 341 | ledc_channel_t _channel; 342 | ledc_mode_t _group; 343 | uint8_t _timer = INVALID_TIMER; 344 | uint8_t _resolution; // bit size 345 | 346 | /////////////////////////////////////////// 347 | }; 348 | 349 | /////////////////////////////////////////// 350 | 351 | 352 | #endif // ESP32_FAST_PWM_HPP 353 | 354 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32_FastPWM Library 2 | 3 | [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP32_FastPWM.svg?)](https://www.ardu-badge.com/ESP32_FastPWM) 4 | [![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP32_FastPWM.svg)](https://github.com/khoih-prog/ESP32_FastPWM/releases) 5 | [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/ESP32_FastPWM/blob/main/LICENSE) 6 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) 7 | [![GitHub issues](https://img.shields.io/github/issues/khoih-prog/ESP32_FastPWM.svg)](http://github.com/khoih-prog/ESP32_FastPWM/issues) 8 | 9 | 10 | Donate to my libraries using BuyMeACoffee 11 | 12 | 13 | 14 | --- 15 | --- 16 | 17 | ## Table of Contents 18 | 19 | * [Why do we need this ESP32_FastPWM library](#why-do-we-need-this-ESP32_FastPWM-library) 20 | * [Features](#features) 21 | * [Why using hardware-based PWM is better](#why-using-hardware-based-pwm-is-better) 22 | * [Currently supported Boards](#currently-supported-boards) 23 | * [Changelog](changelog.md) 24 | * [Prerequisites](#prerequisites) 25 | * [Installation](#installation) 26 | * [Use Arduino Library Manager](#use-arduino-library-manager) 27 | * [Manual Install](#manual-install) 28 | * [VS Code & PlatformIO](#vs-code--platformio) 29 | * [HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE)](#howto-use-analogread-with-esp32-running-wifi-andor-bluetooth-btble) 30 | * [1. ESP32 has 2 ADCs, named ADC1 and ADC2](#1--esp32-has-2-adcs-named-adc1-and-adc2) 31 | * [2. ESP32 ADCs functions](#2-esp32-adcs-functions) 32 | * [3. ESP32 WiFi uses ADC2 for WiFi functions](#3-esp32-wifi-uses-adc2-for-wifi-functions) 33 | * [More useful Information](#more-useful-information) 34 | * [Usage](#usage) 35 | * [1. Create PWM Instance with Pin, Frequency, dutycycle, channel (default = 0) and PWM_resolution (default = 8)](#1-create-pwm-instance-with-pin-frequency-dutycycle-channel-default--0-and-pwm_resolution-default--8) 36 | * [2. Initialize PWM Instance](#2-Initialize-PWM-Instance) 37 | * [3. Set or change PWM frequency or dutyCycle](#3-set-or-change-PWM-frequency-or-dutyCycle) 38 | * [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) 39 | * [Examples](#examples) 40 | * [ 1. PWM_Basic](examples/PWM_Basic) 41 | * [ 2. PWM_DynamicDutyCycle](examples/PWM_DynamicDutyCycle) 42 | * [ 3. PWM_DynamicDutyCycle_Int](examples/PWM_DynamicDutyCycle_Int) 43 | * [ 4. PWM_DynamicFreq](examples/PWM_DynamicFreq) 44 | * [ 5. PWM_Multi](examples/PWM_Multi) 45 | * [ 6. PWM_MultiChannel](examples/PWM_MultiChannel) 46 | * [ 7. PWM_Waveform](examples/PWM_Waveform) 47 | * [ 8. PWM_StepperControl](examples/PWM_StepperControl) **New** 48 | * [ 9. PWM_manual](examples/PWM_manual) **New** 49 | * [Example PWM_Multi](#example-PWM_Multi) 50 | * [Debug Terminal Output Samples](#debug-terminal-output-samples) 51 | * [1. PWM_DynamicDutyCycle on ESP32_DEV](#1-PWM_DynamicDutyCycle-on-ESP32_DEV) 52 | * [2. PWM_Multi on ESP32_DEV](#2-PWM_Multi-on-ESP32_DEV) 53 | * [3. PWM_DynamicFreq on ESP32S3_DEV](#3-PWM_DynamicFreq-on-ESP32S3_DEV) 54 | * [4. PWM_Waveform on ESP32S2_DEV](#4-PWM_Waveform-on-ESP32S2_DEV) 55 | * [5. PWM_Waveform on ESP32C3_DEV](#5-PWM_Waveform-on-ESP32C3_DEV) 56 | * [6. PWM_Waveform on ESP32S3_DEV](#6-PWM_Waveform-on-ESP32S3_DEV) 57 | * [7. PWM_manual on ESP32_DEV](#7-PWM_manual-on-ESP32_DEV) 58 | * [Debug](#debug) 59 | * [Troubleshooting](#troubleshooting) 60 | * [Issues](#issues) 61 | * [TO DO](#to-do) 62 | * [DONE](#done) 63 | * [Contributions and Thanks](#contributions-and-thanks) 64 | * [Contributing](#contributing) 65 | * [License](#license) 66 | * [Copyright](#copyright) 67 | 68 | --- 69 | --- 70 | 71 | 72 | ### Why do we need this [ESP32_FastPWM library](https://github.com/khoih-prog/ESP32_FastPWM) 73 | 74 | ### Features 75 | 76 | This hardware-based PWM library, a wrapper and enhancement around ESP32-core `ledc` code, enables you to use Hardware-PWM on `ESP32, ESP32_S2, ESP32_S3 and ESP32_C3` boards to create and output PWM. These purely hardware-based PWM channels can generate very high PWM frequencies, depending on CPU clock and acceptable accuracy. The maximum resolution can be 20-bit with very low frequencies. Normally 8, 12 or 16-bit resolution is good enough. 77 | 78 | ```cpp 79 | // Max resolution is 20-bit 80 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 81 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 82 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 83 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 84 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 85 | ``` 86 | 87 | This library is using the **same or similar functions** as other FastPWM libraries, as follows, to enable you to **port your PWM code easily between platforms** 88 | 89 | 1. [**RP2040_PWM**](https://github.com/khoih-prog/RP2040_PWM) 90 | 2. [**AVR_PWM**](https://github.com/khoih-prog/AVR_PWM) 91 | 3. [**megaAVR_PWM**](https://github.com/khoih-prog/megaAVR_PWM) 92 | 4. [**ESP32_FastPWM**](https://github.com/khoih-prog/ESP32_FastPWM) 93 | 5. [**SAMD_PWM**](https://github.com/khoih-prog/SAMD_PWM) 94 | 6. [**SAMDUE_PWM**](https://github.com/khoih-prog/SAMDUE_PWM) 95 | 7. [**nRF52_PWM**](https://github.com/khoih-prog/nRF52_PWM) 96 | 8. [**Teensy_PWM**](https://github.com/khoih-prog/Teensy_PWM) 97 | 9. [**ATtiny_PWM**](https://github.com/khoih-prog/ATtiny_PWM) 98 | 10. [**Dx_PWM**](https://github.com/khoih-prog/Dx_PWM) 99 | 11. [**Portenta_H7_PWM**](https://github.com/khoih-prog/Portenta_H7_PWM) 100 | 12. [**MBED_RP2040_PWM**](https://github.com/khoih-prog/MBED_RP2040_PWM) 101 | 13. [**nRF52_MBED_PWM**](https://github.com/khoih-prog/nRF52_MBED_PWM) 102 | 14. [**STM32_PWM**](https://github.com/khoih-prog/STM32_PWM) 103 | 104 | --- 105 | 106 | The most important feature is they're purely hardware-based PWM channels. Therefore, their operations are **not blocked by bad-behaving software functions / tasks**. 107 | 108 | This important feature is absolutely necessary for mission-critical tasks. These hardware PWM-channels, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's necessary if you need to control external systems (Servo, etc.) requiring better accuracy. 109 | 110 | New efficient `setPWM_manual()` and `setPWM_DCPercentage_manual()` functions enable waveform creation using PWM. 111 | 112 | 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 `ESP32`. 113 | 114 | Being hardware-based PWM, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet or Blynk services. 115 | 116 | This non-being-blocked important feature is absolutely necessary for mission-critical tasks. 117 | 118 | 119 | ### Why using hardware-based PWM is better 120 | 121 | Imagine you have a system with a **mission-critical** function, controlling a robot or doing something much more important. You normally use a software timer to poll, or even place the function in loop(). But what if another function is **blocking** the loop() or setup(). 122 | 123 | So your function **might not be executed, and the result would be disastrous.** 124 | 125 | You'd prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.). 126 | 127 | The correct choice is to use `hardware-based PWM`. 128 | 129 | These hardware-based PWM channels 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 PWMs, using millis() or micros(). 130 | 131 | Functions using normal software-based PWMs, relying on loop() and calling millis(), won't work if the `loop()` or `setup()` is blocked by certain operation. For example, certain function is blocking while it's connecting to WiFi or some services. 132 | 133 | --- 134 | 135 | ### Currently supported Boards 136 | 137 | 1. ESP32 boards, such as `ESP32_DEV`, etc. 138 | 2. ESP32S2-based boards, such as `ESP32S2_DEV`, `ESP32_S2 Saola`, Adafruit QTPY_ESP32S2, etc. 139 | 3. ESP32C3-based boards, such as `ESP32C3_DEV`, etc. 140 | 4. ESP32_S3 (ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, FEATHER_ESP32S3_NOPSRAM and QTPY_ESP32S3_NOPSRAM, etc.) 141 | 142 | 143 | --- 144 | --- 145 | 146 | ## Prerequisites 147 | 148 | 1. [`Arduino IDE 1.8.19+` for Arduino](https://github.com/arduino/Arduino). [![GitHub release](https://img.shields.io/github/release/arduino/Arduino.svg)](https://github.com/arduino/Arduino/releases/latest) 149 | 2. [`ESP32 Core 2.0.6+`](https://github.com/espressif/arduino-esp32) for ESP32-based boards. [![Latest release](https://img.shields.io/github/release/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/latest/). 150 | 151 | 152 | 153 | --- 154 | --- 155 | 156 | ## Installation 157 | 158 | ### Use Arduino Library Manager 159 | 160 | The best and easiest way is to use `Arduino Library Manager`. Search for [**ESP32_FastPWM**](https://github.com/khoih-prog/ESP32_FastPWM), then select / install the latest version. 161 | You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP32_FastPWM.svg?)](https://www.ardu-badge.com/ESP32_FastPWM) for more detailed instructions. 162 | 163 | ### Manual Install 164 | 165 | Another way to install is to: 166 | 167 | 1. Navigate to [**ESP32_FastPWM**](https://github.com/khoih-prog/ESP32_FastPWM) page. 168 | 2. Download the latest release `ESP32_FastPWM-main.zip`. 169 | 3. Extract the zip file to `ESP32_FastPWM-main` directory 170 | 4. Copy whole `ESP32_FastPWM-main` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. 171 | 172 | ### VS Code & PlatformIO 173 | 174 | 1. Install [VS Code](https://code.visualstudio.com/) 175 | 2. Install [PlatformIO](https://platformio.org/platformio-ide) 176 | 3. Install [**ESP32_FastPWM** library](https://registry.platformio.org/libraries/khoih-prog/ESP32_FastPWM) by using [Library Manager](https://registry.platformio.org/libraries/khoih-prog/ESP32_FastPWM/installation). Search for **ESP32_FastPWM** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) 177 | 4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html) 178 | 179 | 180 | --- 181 | --- 182 | 183 | 184 | ### HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE) 185 | 186 | Please have a look at [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to have more detailed description and solution of the issue. 187 | 188 | #### 1. ESP32 has 2 ADCs, named ADC1 and ADC2 189 | 190 | #### 2. ESP32 ADCs functions 191 | 192 | - `ADC1` controls ADC function for pins **GPIO32-GPIO39** 193 | - `ADC2` controls ADC function for pins **GPIO0, 2, 4, 12-15, 25-27** 194 | 195 | #### 3.. ESP32 WiFi uses ADC2 for WiFi functions 196 | 197 | Look in file [**adc_common.c**](https://github.com/espressif/esp-idf/blob/master/components/driver/adc_common.c#L61) 198 | 199 | > In `ADC2`, there're two locks used for different cases: 200 | > 1. lock shared with app and Wi-Fi: 201 | > ESP32: 202 | > When Wi-Fi using the `ADC2`, we assume it will never stop, so app checks the lock and returns immediately if failed. 203 | > ESP32S2: 204 | > The controller's control over the ADC is determined by the arbiter. There is no need to control by lock. 205 | > 206 | > 2. lock shared between tasks: 207 | > when several tasks sharing the `ADC2`, we want to guarantee 208 | > all the requests will be handled. 209 | > Since conversions are short (about 31us), app returns the lock very soon, 210 | > we use a spinlock to stand there waiting to do conversions one by one. 211 | > 212 | > adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock. 213 | 214 | 215 | - In order to use `ADC2` for other functions, we have to **acquire complicated firmware locks and very difficult to do** 216 | - So, it's not advisable to use `ADC2` with WiFi/BlueTooth (BT/BLE). 217 | - Use `ADC1`, and pins **GPIO32-GPIO39** 218 | - If somehow it's a must to use those pins serviced by `ADC2` (**GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27**), use the **fix mentioned at the end** of [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to work with ESP32 WiFi/BlueTooth (BT/BLE) 219 | 220 | --- 221 | --- 222 | 223 | ## More useful Information 224 | 225 | ### ESP32 Hardware Timers 226 | 227 | - **The ESP32, ESP32_S2 and ESP32_S3 has two timer groups, each one with two general purpose hardware timers.** 228 | - **The ESP32_C3 has two timer groups, each one with only one general purpose hardware timer.** 229 | - All the timers are based on **64-bit counters (except 54-bit counter for ESP32_S3 counter) and 16-bit prescalers.** 230 | - The timer counters can be configured to count up or down and support automatic reload and software reload. 231 | - They can also generate alarms when they reach a specific value, defined by the software. 232 | - The value of the counter can be read by the software program. 233 | 234 | --- 235 | --- 236 | 237 | ## Usage 238 | 239 | Before using any PWM `Timer` and `channel`, you have to make sure the `Timer` and `channel` has not been used by any other purpose. 240 | 241 | ```cpp 242 | // Max resolution is 20-bit 243 | // Resolution 65536 (16-bit) for lower frequencies, OK @ 1K 244 | // Resolution 4096 (12-bit) for lower frequencies, OK @ 10K 245 | // Resolution 1024 (10-bit) for higher frequencies, OK @ 50K 246 | // Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K 247 | // Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K 248 | 249 | /////////////////////////////////////////////////////////////////// 250 | 251 | // All GPIO pins (but GPIO34-39) can be used to generate PWM 252 | // For ESP32, number of channels is 16, max 20-bit resolution 253 | // For ESP32_S2, ESP32_S3, number of channels is 8, max 20-bit resolution 254 | // For ESP32_C3, number of channels is 6, max 20-bit resolution 255 | ``` 256 | 257 | #### 1. Create PWM Instance with Pin, Frequency, dutycycle, channel (default = 0) and PWM_resolution (default = 8) 258 | 259 | ```cpp 260 | ESP32_FAST_PWM* PWM_Instance; 261 | 262 | PWM_Instance = new ESP32_FAST_PWM(pinToUse, frequency, dutyCycle, channel, PWM_resolution); 263 | ``` 264 | 265 | #### 2. Initialize PWM Instance 266 | 267 | ```cpp 268 | if (PWM_Instance) 269 | { 270 | PWM_Instance->setPWM(); 271 | } 272 | ``` 273 | 274 | #### 3. Set or change PWM frequency or dutyCycle 275 | 276 | To use `float new_dutyCycle` 277 | 278 | ```cpp 279 | PWM_Instance->setPWM(PWM_Pins, new_frequency, new_dutyCycle); 280 | ``` 281 | 282 | such as 283 | 284 | ```cpp 285 | dutyCycle = 10.0f; 286 | 287 | Serial.print(F("Change PWM DutyCycle to ")); Serial.println(dutyCycle); 288 | PWM_Instance->setPWM(pinToUse, frequency, dutyCycle); 289 | ``` 290 | 291 | --- 292 | 293 | To use `uint32_t new_dutyCycle` = `(real_dutyCycle * 65536) / 100` 294 | 295 | 296 | ```cpp 297 | PWM_Instance->setPWM_Int(PWM_Pins, new_frequency, new_dutyCycle); 298 | ``` 299 | 300 | such as for `real_dutyCycle = 50%` 301 | 302 | ```cpp 303 | // 50% dutyCycle = (real_dutyCycle * 65536) / 100 304 | dutyCycle = 32768; 305 | 306 | Serial.print(F("Change PWM DutyCycle to (%) ")); 307 | Serial.println((float) dutyCycle * 100 / 65536); 308 | PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle); 309 | ``` 310 | 311 | for `real_dutyCycle = 50%` 312 | 313 | ```cpp 314 | // 20% dutyCycle = (real_dutyCycle * 65536) / 100 315 | dutyCycle = 13107; 316 | 317 | Serial.print(F("Change PWM DutyCycle to (%) ")); 318 | Serial.println((float) dutyCycle * 100 / 65536); 319 | PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle); 320 | ``` 321 | 322 | #### 4. Set or change PWM frequency and dutyCycle manually and efficiently in waveform creation 323 | 324 | Function prototype 325 | 326 | ```cpp 327 | bool setPWM_manual(const uint8_t& pin, const uint16_t& DCValue); 328 | bool setPWM_DCPercentage_manual(const uint8_t& pin, const float& DCPercentage); 329 | ``` 330 | 331 | Need to call only once for each pin 332 | 333 | 334 | ```cpp 335 | PWM_Instance->setPWM(PWM_Pins, frequency, dutyCycle); 336 | ``` 337 | 338 | after that, if just changing `dutyCycle` / `level`, use 339 | 340 | ```cpp 341 | // For 50.0f dutycycle 342 | new_level = 50.0f * ( 1 << PWM_Instance->getResolution() ) / 100.0f ; 343 | PWM_Instance->setPWM_manual(PWM_Pins, new_level); 344 | ``` 345 | 346 | or better and much easier to use 347 | 348 | ```cpp 349 | new_DCPercentage = 50.0f; 350 | PWM_Instance->setPWM_DCPercentage_manual(PWM_Pins, new_DCPercentage); 351 | ``` 352 | 353 | --- 354 | --- 355 | 356 | ### Examples: 357 | 358 | 1. [PWM_Basic](examples/PWM_Basic) 359 | 2. [PWM_DynamicDutyCycle](examples/PWM_DynamicDutyCycle) 360 | 3. [PWM_DynamicDutyCycle_Int](examples/PWM_DynamicDutyCycle_Int) 361 | 4. [PWM_DynamicFreq](examples/PWM_DynamicFreq) 362 | 5. [PWM_Multi](examples/PWM_Multi) 363 | 6. [PWM_MultiChannel](examples/PWM_MultiChannel) 364 | 7. [PWM_Waveform](examples/PWM_Waveform) 365 | 8. [PWM_StepperControl](examples/PWM_StepperControl) **New** 366 | 9. [PWM_manual](examples/PWM_manual) **New** 367 | 368 | 369 | --- 370 | --- 371 | 372 | ### Example [PWM_Multi](examples/PWM_Multi) 373 | 374 | https://github.com/khoih-prog/ESP32_FastPWM/blob/09ea7daef68ab6660d298e9ef2e20f55d906416c/examples/PWM_Multi/PWM_Multi.ino#L12-L153 375 | 376 | 377 | --- 378 | --- 379 | 380 | ### Debug Terminal Output Samples 381 | 382 | ### 1. PWM_DynamicDutyCycle on ESP32_DEV 383 | 384 | The following is the sample terminal output when running example [PWM_DynamicDutyCycle](examples/PWM_DynamicDutyCycle) on *ESP32_DEV**, to demonstrate the ability to provide high PWM frequencies and ability to change DutyCycle `on-the-fly`. 385 | 386 | 387 | ```cpp 388 | Starting PWM_DynamicDutyCycle on ESP32_DEV 389 | ESP32_FastPWM v1.1.0 390 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 16 , LEDC_MAX_BIT_WIDTH = 20 391 | [PWM] ESP32_FastPWM: _dutycycle = 32768 392 | [PWM] setPWM_Int: _dutycycle = 128 , DC % = 50.00 393 | ===================================================================================== 394 | Change PWM DutyCycle to 90.00 395 | [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00 396 | [PWM] setPWM_Int: _dutycycle = 230 , DC % = 89.84 397 | ===================================================================================== 398 | Actual data: pin = 16, PWM DC = 89.84, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000 399 | ===================================================================================== 400 | Change PWM DutyCycle to 20.00 401 | [PWM] setPWM: _dutycycle = 13107 , frequency = 5000.00 402 | [PWM] setPWM_Int: _dutycycle = 51 , DC % = 19.92 403 | ===================================================================================== 404 | Actual data: pin = 16, PWM DC = 19.92, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000 405 | ===================================================================================== 406 | Change PWM DutyCycle to 90.00 407 | [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00 408 | [PWM] setPWM_Int: _dutycycle = 230 , DC % = 89.84 409 | ===================================================================================== 410 | Actual data: pin = 16, PWM DC = 89.84, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000 411 | ===================================================================================== 412 | ``` 413 | 414 | --- 415 | 416 | ### 2. PWM_Multi on ESP32_DEV 417 | 418 | The following is the sample terminal output when running example [**PWM_Multi**](examples/PWM_Multi) on **ESP32_DEV**, to demonstrate the ability to provide high PWM frequencies on multiple `PWM-capable` pins. 419 | 420 | ```cpp 421 | Starting PWM_Multi on ESP32_DEV 422 | ESP32_FastPWM v1.1.0 423 | [PWM] ESP32_FastPWM: new _channel = 0 424 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 16 , LEDC_MAX_BIT_WIDTH = 20 425 | [PWM] ESP32_FastPWM: _dutycycle = 6553 426 | [PWM] setPWM_Int: _dutycycle = 409 , DC % = 9.99 427 | [PWM] ESP32_FastPWM: new _channel = 2 428 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 16 , LEDC_MAX_BIT_WIDTH = 20 429 | [PWM] ESP32_FastPWM: _dutycycle = 19660 430 | [PWM] setPWM_Int: _dutycycle = 1228 , DC % = 29.98 431 | [PWM] ESP32_FastPWM: new _channel = 4 432 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 16 , LEDC_MAX_BIT_WIDTH = 20 433 | [PWM] ESP32_FastPWM: _dutycycle = 32768 434 | [PWM] setPWM_Int: _dutycycle = 2048 , DC % = 50.00 435 | [PWM] ESP32_FastPWM: new _channel = 6 436 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 16 , LEDC_MAX_BIT_WIDTH = 20 437 | [PWM] ESP32_FastPWM: _dutycycle = 58982 438 | [PWM] setPWM_Int: _dutycycle = 3686 , DC % = 89.99 439 | ===================================================================================== 440 | Index Pin PWM_freq DutyCycle Actual Freq 441 | ===================================================================================== 442 | 0 25 2000.00 10.00 2000.0000 443 | 1 27 3000.00 30.00 3000.0000 444 | 2 21 4000.00 50.00 4000.0000 445 | 3 22 8000.00 90.00 8000.0000 446 | ===================================================================================== 447 | Actual data: pin = 16, PWM DC = 9.99, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000 448 | ===================================================================================== 449 | ===================================================================================== 450 | Actual data: pin = 17, PWM DC = 29.98, PWMPeriod = 333.33, PWM Freq (Hz) = 3000.0000 451 | ===================================================================================== 452 | ===================================================================================== 453 | Actual data: pin = 19, PWM DC = 50.00, PWMPeriod = 250.00, PWM Freq (Hz) = 4000.0000 454 | ===================================================================================== 455 | ===================================================================================== 456 | Actual data: pin = 21, PWM DC = 89.99, PWMPeriod = 125.00, PWM Freq (Hz) = 8000.0000 457 | ===================================================================================== 458 | ``` 459 | 460 | --- 461 | 462 | ### 3. PWM_DynamicFreq on ESP32S3_DEV 463 | 464 | The following is the sample terminal output when running example [**PWM_DynamicFreq**](examples/PWM_DynamicFreq) on **ESP32S3_DEV**, to demonstrate the ability to change dynamically PWM frequencies. 465 | 466 | ```cpp 467 | Starting PWM_DynamicFreq on ESP32S3_DEV 468 | ESP32_FastPWM v1.1.0 469 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 8 , LEDC_MAX_BIT_WIDTH = 14 470 | [PWM] ESP32_FastPWM: _dutycycle = 32768 471 | [PWM] setPWM_Int: _dutycycle = 128 , DC % = 50.00 472 | ===================================================================================== 473 | Change PWM Freq to 20000.00 474 | [PWM] setPWM: _dutycycle = 32768 , frequency = 20000.00 475 | [PWM] setPWM_Int: _dutycycle = 128 , DC % = 50.00 476 | [PWM] setPWM_Int: change frequency to 20000.00 from 10000.00 477 | ===================================================================================== 478 | Actual data: pin = 16, PWM DC = 50.00, PWMPeriod = 50.00, PWM Freq (Hz) = 20000.0000 479 | ===================================================================================== 480 | Change PWM Freq to 10000.00 481 | [PWM] setPWM: _dutycycle = 32768 , frequency = 10000.00 482 | [PWM] setPWM_Int: _dutycycle = 128 , DC % = 50.00 483 | [PWM] setPWM_Int: change frequency to 10000.00 from 20000.00 484 | ===================================================================================== 485 | Actual data: pin = 16, PWM DC = 50.00, PWMPeriod = 100.00, PWM Freq (Hz) = 10000.0000 486 | ===================================================================================== 487 | Change PWM Freq to 20000.00 488 | [PWM] setPWM: _dutycycle = 32768 , frequency = 20000.00 489 | [PWM] setPWM_Int: _dutycycle = 128 , DC % = 50.00 490 | [PWM] setPWM_Int: change frequency to 20000.00 from 10000.00 491 | ===================================================================================== 492 | Actual data: pin = 16, PWM DC = 50.00, PWMPeriod = 50.00, PWM Freq (Hz) = 20000.0000 493 | ===================================================================================== 494 | Change PWM Freq to 10000.00 495 | [PWM] setPWM: _dutycycle = 32768 , frequency = 10000.00 496 | [PWM] setPWM_Int: _dutycycle = 128 , DC % = 50.00 497 | [PWM] setPWM_Int: change frequency to 10000.00 from 20000.00 498 | ===================================================================================== 499 | Actual data: pin = 16, PWM DC = 50.00, PWMPeriod = 100.00, PWM Freq (Hz) = 10000.0000 500 | ===================================================================================== 501 | ``` 502 | 503 | --- 504 | 505 | 506 | ### 4. PWM_Waveform on ESP32S2_DEV 507 | 508 | The following is the sample terminal output when running example [**PWM_Waveform**](examples/PWM_Waveform) on **ESP32S2_DEV**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation 509 | 510 | 511 | ```cpp 512 | Starting PWM_Waveform on ESP32S2_DEV 513 | ESP32_FastPWM v1.1.0 514 | [PWM] ESP32_FastPWM: new _channel = 0 515 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 8 , LEDC_MAX_BIT_WIDTH = 14 516 | [PWM] ESP32_FastPWM: _dutycycle = 0 517 | [PWM] setPWM: _dutycycle = 0 , frequency = 1000.00 518 | [PWM] setPWM_Int: _dutycycle = 0 , DC % = 0.00 519 | ============================================================================================ 520 | Actual data: pin = 16, PWM DutyCycle = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 521 | ============================================================================================ 522 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 523 | [PWM] setPWM_manual: DCValue = 204 , _frequency = 1000.00 524 | [PWM] setPWM_manual: DCValue = 409 , _frequency = 1000.00 525 | [PWM] setPWM_manual: DCValue = 614 , _frequency = 1000.00 526 | [PWM] setPWM_manual: DCValue = 819 , _frequency = 1000.00 527 | [PWM] setPWM_manual: DCValue = 1024 , _frequency = 1000.00 528 | [PWM] setPWM_manual: DCValue = 1228 , _frequency = 1000.00 529 | [PWM] setPWM_manual: DCValue = 1433 , _frequency = 1000.00 530 | [PWM] setPWM_manual: DCValue = 1638 , _frequency = 1000.00 531 | [PWM] setPWM_manual: DCValue = 1843 , _frequency = 1000.00 532 | [PWM] setPWM_manual: DCValue = 2048 , _frequency = 1000.00 533 | [PWM] setPWM_manual: DCValue = 2252 , _frequency = 1000.00 534 | [PWM] setPWM_manual: DCValue = 2457 , _frequency = 1000.00 535 | [PWM] setPWM_manual: DCValue = 2662 , _frequency = 1000.00 536 | [PWM] setPWM_manual: DCValue = 2867 , _frequency = 1000.00 537 | [PWM] setPWM_manual: DCValue = 3072 , _frequency = 1000.00 538 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 539 | [PWM] setPWM_manual: DCValue = 3481 , _frequency = 1000.00 540 | [PWM] setPWM_manual: DCValue = 3686 , _frequency = 1000.00 541 | [PWM] setPWM_manual: DCValue = 3891 , _frequency = 1000.00 542 | [PWM] setPWM_manual: DCValue = 4096 , _frequency = 1000.00 543 | [PWM] setPWM_manual: DCValue = 3891 , _frequency = 1000.00 544 | [PWM] setPWM_manual: DCValue = 3686 , _frequency = 1000.00 545 | [PWM] setPWM_manual: DCValue = 3481 , _frequency = 1000.00 546 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 547 | [PWM] setPWM_manual: DCValue = 3072 , _frequency = 1000.00 548 | [PWM] setPWM_manual: DCValue = 2867 , _frequency = 1000.00 549 | [PWM] setPWM_manual: DCValue = 2662 , _frequency = 1000.00 550 | [PWM] setPWM_manual: DCValue = 2457 , _frequency = 1000.00 551 | [PWM] setPWM_manual: DCValue = 2252 , _frequency = 1000.00 552 | [PWM] setPWM_manual: DCValue = 2048 , _frequency = 1000.00 553 | [PWM] setPWM_manual: DCValue = 1843 , _frequency = 1000.00 554 | [PWM] setPWM_manual: DCValue = 1638 , _frequency = 1000.00 555 | [PWM] setPWM_manual: DCValue = 1433 , _frequency = 1000.00 556 | [PWM] setPWM_manual: DCValue = 1228 , _frequency = 1000.00 557 | [PWM] setPWM_manual: DCValue = 1024 , _frequency = 1000.00 558 | [PWM] setPWM_manual: DCValue = 819 , _frequency = 1000.00 559 | [PWM] setPWM_manual: DCValue = 614 , _frequency = 1000.00 560 | [PWM] setPWM_manual: DCValue = 409 , _frequency = 1000.00 561 | [PWM] setPWM_manual: DCValue = 204 , _frequency = 1000.00 562 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 563 | ``` 564 | 565 | --- 566 | 567 | ### 5. PWM_Waveform on ESP32C3_DEV 568 | 569 | The following is the sample terminal output when running example [**PWM_Waveform**](examples/PWM_Waveform) on **ESP32C3_DEV**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation 570 | 571 | 572 | ```cpp 573 | Starting PWM_Waveform on ESP32C3_DEV 574 | ESP32_FastPWM v1.1.0 575 | [PWM] ESP32_FastPWM: new _channel = 0 576 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 6 , LEDC_CHANNELS = 6 , LEDC_MAX_BIT_WIDTH = 14 577 | [PWM] ESP32_FastPWM: _dutycycle = 0 578 | [PWM] setPWM: _dutycycle = 0 , frequency = 1000.00 579 | [PWM] setPWM_Int: _dutycycle = 0 , DC % = 0.00 580 | ============================================================================================ 581 | Actual data: pin = 9, PWM DutyCycle = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 582 | ============================================================================================ 583 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 584 | [PWM] setPWM_manual: DCValue = 204 , _frequency = 1000.00 585 | [PWM] setPWM_manual: DCValue = 409 , _frequency = 1000.00 586 | [PWM] setPWM_manual: DCValue = 614 , _frequency = 1000.00 587 | [PWM] setPWM_manual: DCValue = 819 , _frequency = 1000.00 588 | [PWM] setPWM_manual: DCValue = 1024 , _frequency = 1000.00 589 | [PWM] setPWM_manual: DCValue = 1228 , _frequency = 1000.00 590 | [PWM] setPWM_manual: DCValue = 1433 , _frequency = 1000.00 591 | [PWM] setPWM_manual: DCValue = 1638 , _frequency = 1000.00 592 | [PWM] setPWM_manual: DCValue = 1843 , _frequency = 1000.00 593 | [PWM] setPWM_manual: DCValue = 2048 , _frequency = 1000.00 594 | [PWM] setPWM_manual: DCValue = 2252 , _frequency = 1000.00 595 | [PWM] setPWM_manual: DCValue = 2457 , _frequency = 1000.00 596 | [PWM] setPWM_manual: DCValue = 2662 , _frequency = 1000.00 597 | [PWM] setPWM_manual: DCValue = 2867 , _frequency = 1000.00 598 | [PWM] setPWM_manual: DCValue = 3072 , _frequency = 1000.00 599 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 600 | [PWM] setPWM_manual: DCValue = 3481 , _frequency = 1000.00 601 | [PWM] setPWM_manual: DCValue = 3686 , _frequency = 1000.00 602 | [PWM] setPWM_manual: DCValue = 3891 , _frequency = 1000.00 603 | [PWM] setPWM_manual: DCValue = 4096 , _frequency = 1000.00 604 | [PWM] setPWM_manual: DCValue = 3891 , _frequency = 1000.00 605 | [PWM] setPWM_manual: DCValue = 3686 , _frequency = 1000.00 606 | [PWM] setPWM_manual: DCValue = 3481 , _frequency = 1000.00 607 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 608 | [PWM] setPWM_manual: DCValue = 3072 , _frequency = 1000.00 609 | [PWM] setPWM_manual: DCValue = 2867 , _frequency = 1000.00 610 | [PWM] setPWM_manual: DCValue = 2662 , _frequency = 1000.00 611 | [PWM] setPWM_manual: DCValue = 2457 , _frequency = 1000.00 612 | [PWM] setPWM_manual: DCValue = 2252 , _frequency = 1000.00 613 | [PWM] setPWM_manual: DCValue = 2048 , _frequency = 1000.00 614 | [PWM] setPWM_manual: DCValue = 1843 , _frequency = 1000.00 615 | [PWM] setPWM_manual: DCValue = 1638 , _frequency = 1000.00 616 | [PWM] setPWM_manual: DCValue = 1433 , _frequency = 1000.00 617 | [PWM] setPWM_manual: DCValue = 1228 , _frequency = 1000.00 618 | [PWM] setPWM_manual: DCValue = 1024 , _frequency = 1000.00 619 | [PWM] setPWM_manual: DCValue = 819 , _frequency = 1000.00 620 | [PWM] setPWM_manual: DCValue = 614 , _frequency = 1000.00 621 | [PWM] setPWM_manual: DCValue = 409 , _frequency = 1000.00 622 | [PWM] setPWM_manual: DCValue = 204 , _frequency = 1000.00 623 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 624 | ``` 625 | 626 | --- 627 | 628 | ### 6. PWM_Waveform on ESP32S3_DEV 629 | 630 | The following is the sample terminal output when running example [**PWM_Waveform**](examples/PWM_Waveform) on **ESP32S3_DEV**, to demonstrate how to use the `setPWM_manual()` function in wafeform creation 631 | 632 | 633 | ```cpp 634 | Starting PWM_Waveform on ESP32S3_DEV 635 | ESP32_FastPWM v1.1.0 636 | [PWM] ESP32_FastPWM: new _channel = 0 637 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 8 , LEDC_MAX_BIT_WIDTH = 14 638 | [PWM] ESP32_FastPWM: _dutycycle = 0 639 | [PWM] setPWM: _dutycycle = 0 , frequency = 1000.00 640 | [PWM] setPWM_Int: _dutycycle = 0 , DC % = 0.00 641 | ============================================================================================ 642 | Actual data: pin = 16, PWM DutyCycle = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 643 | ============================================================================================ 644 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 645 | [PWM] setPWM_manual: DCValue = 204 , _frequency = 1000.00 646 | [PWM] setPWM_manual: DCValue = 409 , _frequency = 1000.00 647 | [PWM] setPWM_manual: DCValue = 614 , _frequency = 1000.00 648 | [PWM] setPWM_manual: DCValue = 819 , _frequency = 1000.00 649 | [PWM] setPWM_manual: DCValue = 1024 , _frequency = 1000.00 650 | [PWM] setPWM_manual: DCValue = 1228 , _frequency = 1000.00 651 | [PWM] setPWM_manual: DCValue = 1433 , _frequency = 1000.00 652 | [PWM] setPWM_manual: DCValue = 1638 , _frequency = 1000.00 653 | [PWM] setPWM_manual: DCValue = 1843 , _frequency = 1000.00 654 | [PWM] setPWM_manual: DCValue = 2048 , _frequency = 1000.00 655 | [PWM] setPWM_manual: DCValue = 2252 , _frequency = 1000.00 656 | [PWM] setPWM_manual: DCValue = 2457 , _frequency = 1000.00 657 | [PWM] setPWM_manual: DCValue = 2662 , _frequency = 1000.00 658 | [PWM] setPWM_manual: DCValue = 2867 , _frequency = 1000.00 659 | [PWM] setPWM_manual: DCValue = 3072 , _frequency = 1000.00 660 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 661 | [PWM] setPWM_manual: DCValue = 3481 , _frequency = 1000.00 662 | [PWM] setPWM_manual: DCValue = 3686 , _frequency = 1000.00 663 | [PWM] setPWM_manual: DCValue = 3891 , _frequency = 1000.00 664 | [PWM] setPWM_manual: DCValue = 4096 , _frequency = 1000.00 665 | [PWM] setPWM_manual: DCValue = 3891 , _frequency = 1000.00 666 | [PWM] setPWM_manual: DCValue = 3686 , _frequency = 1000.00 667 | [PWM] setPWM_manual: DCValue = 3481 , _frequency = 1000.00 668 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 669 | [PWM] setPWM_manual: DCValue = 3072 , _frequency = 1000.00 670 | [PWM] setPWM_manual: DCValue = 2867 , _frequency = 1000.00 671 | [PWM] setPWM_manual: DCValue = 2662 , _frequency = 1000.00 672 | [PWM] setPWM_manual: DCValue = 2457 , _frequency = 1000.00 673 | [PWM] setPWM_manual: DCValue = 2252 , _frequency = 1000.00 674 | [PWM] setPWM_manual: DCValue = 2048 , _frequency = 1000.00 675 | [PWM] setPWM_manual: DCValue = 1843 , _frequency = 1000.00 676 | [PWM] setPWM_manual: DCValue = 1638 , _frequency = 1000.00 677 | [PWM] setPWM_manual: DCValue = 1433 , _frequency = 1000.00 678 | [PWM] setPWM_manual: DCValue = 1228 , _frequency = 1000.00 679 | [PWM] setPWM_manual: DCValue = 1024 , _frequency = 1000.00 680 | [PWM] setPWM_manual: DCValue = 819 , _frequency = 1000.00 681 | [PWM] setPWM_manual: DCValue = 614 , _frequency = 1000.00 682 | [PWM] setPWM_manual: DCValue = 409 , _frequency = 1000.00 683 | [PWM] setPWM_manual: DCValue = 204 , _frequency = 1000.00 684 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 685 | ``` 686 | 687 | 688 | --- 689 | 690 | ### 7. PWM_manual on ESP32_DEV 691 | 692 | The following is the sample terminal output when running example [**PWM_manual**](examples/PWM_manual) on **ESP32_DEV**, to demonstrate how to use the `setPWM_manual()` and `setPWM_DCPercentage_manual()` functions in wafeform creation 693 | 694 | 695 | ```cpp 696 | Starting PWM_manual on ESP32_DEV 697 | ESP32_FastPWM v1.1.0 698 | [PWM] ESP32_FastPWM: new _channel = 0 699 | [PWM] ESP32_FastPWM: SOC_LEDC_CHANNEL_NUM = 8 , LEDC_CHANNELS = 16 , LEDC_MAX_BIT_WIDTH = 20 700 | [PWM] ESP32_FastPWM: _dutycycle = 0 701 | [PWM] setPWM_Int: _dutycycle = 0 , DC % = 0.00 702 | ================================================================================================= 703 | Actual data: pin = 16, PWM DC = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 704 | ================================================================================================= 705 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 0.00 , new_dc = 0 706 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 707 | ================================================================================================= 708 | Actual data: pin = 16, PWM DC = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 709 | ================================================================================================= 710 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 5.00 , new_dc = 3276 711 | [PWM] setPWM_manual: DCValue = 3276 , _frequency = 1000.00 712 | ================================================================================================= 713 | Actual data: pin = 16, PWM DC = 5.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 714 | ================================================================================================= 715 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 10.00 , new_dc = 6553 716 | [PWM] setPWM_manual: DCValue = 6553 , _frequency = 1000.00 717 | ================================================================================================= 718 | Actual data: pin = 16, PWM DC = 10.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 719 | ================================================================================================= 720 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 15.00 , new_dc = 9830 721 | [PWM] setPWM_manual: DCValue = 9830 , _frequency = 1000.00 722 | ================================================================================================= 723 | Actual data: pin = 16, PWM DC = 15.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 724 | ================================================================================================= 725 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 20.00 , new_dc = 13107 726 | [PWM] setPWM_manual: DCValue = 13107 , _frequency = 1000.00 727 | ================================================================================================= 728 | Actual data: pin = 16, PWM DC = 20.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 729 | ================================================================================================= 730 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 25.00 , new_dc = 16384 731 | [PWM] setPWM_manual: DCValue = 16384 , _frequency = 1000.00 732 | ================================================================================================= 733 | Actual data: pin = 16, PWM DC = 25.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 734 | ================================================================================================= 735 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 30.00 , new_dc = 19660 736 | [PWM] setPWM_manual: DCValue = 19660 , _frequency = 1000.00 737 | ================================================================================================= 738 | Actual data: pin = 16, PWM DC = 30.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 739 | ================================================================================================= 740 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 35.00 , new_dc = 22937 741 | [PWM] setPWM_manual: DCValue = 22937 , _frequency = 1000.00 742 | ================================================================================================= 743 | Actual data: pin = 16, PWM DC = 35.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 744 | ================================================================================================= 745 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 40.00 , new_dc = 26214 746 | [PWM] setPWM_manual: DCValue = 26214 , _frequency = 1000.00 747 | ================================================================================================= 748 | Actual data: pin = 16, PWM DC = 40.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 749 | ================================================================================================= 750 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 45.00 , new_dc = 29491 751 | [PWM] setPWM_manual: DCValue = 29491 , _frequency = 1000.00 752 | ================================================================================================= 753 | Actual data: pin = 16, PWM DC = 45.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 754 | ================================================================================================= 755 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 50.00 , new_dc = 32768 756 | [PWM] setPWM_manual: DCValue = 32768 , _frequency = 1000.00 757 | ================================================================================================= 758 | Actual data: pin = 16, PWM DC = 50.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 759 | ================================================================================================= 760 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 55.00 , new_dc = 36044 761 | [PWM] setPWM_manual: DCValue = 36044 , _frequency = 1000.00 762 | ================================================================================================= 763 | Actual data: pin = 16, PWM DC = 55.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 764 | ================================================================================================= 765 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 60.00 , new_dc = 39321 766 | [PWM] setPWM_manual: DCValue = 39321 , _frequency = 1000.00 767 | ================================================================================================= 768 | Actual data: pin = 16, PWM DC = 60.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 769 | ================================================================================================= 770 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 65.00 , new_dc = 42598 771 | [PWM] setPWM_manual: DCValue = 42598 , _frequency = 1000.00 772 | ================================================================================================= 773 | Actual data: pin = 16, PWM DC = 65.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 774 | ================================================================================================= 775 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 70.00 , new_dc = 45875 776 | [PWM] setPWM_manual: DCValue = 45875 , _frequency = 1000.00 777 | ================================================================================================= 778 | Actual data: pin = 16, PWM DC = 70.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 779 | ================================================================================================= 780 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 75.00 , new_dc = 49152 781 | [PWM] setPWM_manual: DCValue = 49152 , _frequency = 1000.00 782 | ================================================================================================= 783 | Actual data: pin = 16, PWM DC = 75.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 784 | ================================================================================================= 785 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 80.00 , new_dc = 52428 786 | [PWM] setPWM_manual: DCValue = 52428 , _frequency = 1000.00 787 | ================================================================================================= 788 | Actual data: pin = 16, PWM DC = 80.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 789 | ================================================================================================= 790 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 85.00 , new_dc = 55705 791 | [PWM] setPWM_manual: DCValue = 55705 , _frequency = 1000.00 792 | ================================================================================================= 793 | Actual data: pin = 16, PWM DC = 85.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 794 | ================================================================================================= 795 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 90.00 , new_dc = 58982 796 | [PWM] setPWM_manual: DCValue = 58982 , _frequency = 1000.00 797 | ================================================================================================= 798 | Actual data: pin = 16, PWM DC = 90.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 799 | ================================================================================================= 800 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 95.00 , new_dc = 62259 801 | [PWM] setPWM_manual: DCValue = 62259 , _frequency = 1000.00 802 | ================================================================================================= 803 | Actual data: pin = 16, PWM DC = 95.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 804 | ================================================================================================= 805 | [PWM] setPWM_DCPercentage_manual: DCPercentage = 100.00 , new_dc = 0 806 | [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00 807 | ================================================================================================= 808 | Actual data: pin = 16, PWM DC = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000 809 | ================================================================================================= 810 | ``` 811 | 812 | --- 813 | --- 814 | 815 | ### Debug 816 | 817 | Debug is enabled by default on Serial. 818 | 819 | You can also change the debugging level `_PWM_LOGLEVEL_` from 0 to 4 820 | 821 | ```cpp 822 | // These define's must be placed at the beginning before #include "ESP32_FastPWM.h" 823 | // _PWM_LOGLEVEL_ from 0 to 4 824 | // Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. 825 | #define _PWM_LOGLEVEL_ 4 826 | ``` 827 | 828 | --- 829 | 830 | ### Troubleshooting 831 | 832 | If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards. 833 | 834 | Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions. 835 | 836 | 837 | --- 838 | --- 839 | 840 | ### Issues 841 | 842 | Submit issues to: [ESP32_FastPWM issues](https://github.com/khoih-prog/ESP32_FastPWM/issues) 843 | 844 | --- 845 | 846 | ## TO DO 847 | 848 | 1. Search for bug and improvement. 849 | 850 | --- 851 | 852 | ## DONE 853 | 854 | 1. Basic hardware PWM-channels for `ESP32, ESP32_S2, ESP32_S3 and ESP32_C3` using [ESP32 core](https://github.com/espressif/arduino-esp32) 855 | 2. Add example [PWM_StepperControl](https://github.com/khoih-prog/ESP32_FastPWM/tree/main/examples/PWM_StepperControl) to demo how to control Stepper Motor using PWM 856 | 3. Add example [PWM_manual](https://github.com/khoih-prog/ESP32_FastPWM/tree/main/examples/PWM_manual) to demo how to correctly use PWM to generate waveform 857 | 4. Add function `setPWM_DCPercentage_manual()` to facilitate the setting PWM DC manually by using DCPercentage, instead of absolute DCValue depending on varying PWMPeriod 858 | 5. Fix glitch when changing PWM frequency 859 | 860 | --- 861 | --- 862 | 863 | ### Contributions and Thanks 864 | 865 | Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library. 866 | 867 | 1. Thanks to [Paul van Dinther](https://github.com/dinther) for proposing new way to use PWM to drive Stepper-Motor in [Using PWM to step a stepper driver #16](https://github.com/khoih-prog/RP2040_PWM/issues/16), leading to v1.0.1 868 | 869 | 870 | 871 | 872 | 873 | 874 |
dinther
Paul van Dinther

875 | 876 | 877 | 878 | --- 879 | 880 | ## Contributing 881 | 882 | If you want to contribute to this project: 883 | 884 | - Report bugs and errors 885 | - Ask for enhancements 886 | - Create issues and pull requests 887 | - Tell other people about this library 888 | 889 | --- 890 | 891 | ### License 892 | 893 | - The library is licensed under [MIT](https://github.com/khoih-prog/ESP32_FastPWM/blob/main/LICENSE) 894 | 895 | --- 896 | 897 | ## Copyright 898 | 899 | Copyright (c) 2022- Khoi Hoang 900 | 901 | 902 | --------------------------------------------------------------------------------