diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 0000000..00fe362 --- /dev/null +++ b/.codespellrc @@ -0,0 +1,7 @@ +# See: https://github.com/codespell-project/codespell#using-a-config-file +[codespell] +# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: +ignore-words-list = , +check-filenames = +check-hidden = +skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b530079 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,79 @@ +## Contributing to ContinuousStepper_Generic + +### Reporting Bugs + +Please report bugs in [ContinuousStepper_Generic Issues](https://github.com/khoih-prog/ContinuousStepper_Generic/issues) if you find them. + +However, before reporting a bug please check through the following: + +* [Existing Open Issues](https://github.com/khoih-prog/ContinuousStepper_Generic/issues) - someone might have already encountered this. + +If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ContinuousStepper_Generic/issues/new). + +--- + +### How to submit a bug report + +Please ensure to specify the following: + +* Arduino IDE version (e.g. 1.8.19) or Platform.io version +* Board Core Version (e.g. Arduino SAMDUE core v1.6.12, ESP32 core v2.0.6, ESP8266 core v3.1.1, ArduinoCore-mbed v3.5.4, etc.) +* Contextual information (e.g. what you were trying to achieve) +* Simplest possible steps to reproduce +* Anything that might be relevant in your opinion, such as: + * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` + * Network configuration + +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. + +--- + +### Example + +``` +Arduino IDE version: 1.8.19 +Arduino-mbed mbed_nano v3.5.4 +NANO_RP2040_CONNECT Module +OS: Ubuntu 21.04 LTS +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 + +Context: +I encountered a crash while using this library + +Steps to reproduce: +1. ... +2. ... +3. ... +4. ... +``` + +--- + +### Sending Feature Requests + +Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. + +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ContinuousStepper_Generic/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. + +--- + +### Sending Pull Requests + +Pull Requests with changes and fixes are also welcome! + +Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) + +1. Change directory to the library GitHub + +``` +xy@xy-Inspiron-3593:~$ cd Arduino/xy/ContinuousStepper_Generic_GitHub/ +xy@xy-Inspiron-3593:~/Arduino/xy/ContinuousStepper_Generic_GitHub$ +``` + +2. Issue astyle command + +``` +xy@xy-Inspiron-3593:~/Arduino/xy/ContinuousStepper_Generic_GitHub$ bash utils/restyle.sh +``` + + diff --git a/LICENSE b/LICENSE index bb61c1b..a2577b7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Khoi Hoang +Copyright (c) 2021 Khoi Hoang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..8170175 --- /dev/null +++ b/README.md @@ -0,0 +1,339 @@ +# ContinuousStepper_Generic Library + +[![arduino-library-badge](https://www.ardu-badge.com/badge/ContinuousStepper_Generic.svg?)](https://www.ardu-badge.com/ContinuousStepper_Generic) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/ContinuousStepper_Generic.svg)](https://github.com/khoih-prog/ContinuousStepper_Generic/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/ContinuousStepper_Generic/blob/main/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/ContinuousStepper_Generic.svg)](http://github.com/khoih-prog/ContinuousStepper_Generic/issues) + + + +Donate to my libraries using BuyMeACoffee + + + +--- +--- + +## Table of Contents + +* [Why do we need this ContinuousStepper_Generic library](#why-do-we-need-this-ContinuousStepper_Generic-library) + * [Features](#features) + * [Why using hardware-based PWM is better](#why-using-hardware-based-pwm-is-better) + * [Currently supported Boards](#currently-supported-boards) +* [Changelog](changelog.md) +* [Prerequisites](#prerequisites) +* [Installation](#installation) + * [Use Arduino Library Manager](#use-arduino-library-manager) + * [Manual Install](#manual-install) + * [VS Code & PlatformIO](#vs-code--platformio) +* [More useful Information about RP2040 PWM](#more-useful-information-about-RP2040-PWM) + * [PWM overview](#PWM-overview) + * [Programmer’s Model](#Programmers-Model) +* [Usage](#usage) + * [1. Create PWM Instance with Pin, Frequency and dutycycle](#1-Create-PWM-Instance-with-Pin-Frequency-and-dutycycle) + * [2. Initialize PWM Instance](#2-Initialize-PWM-Instance) + * [3. Set or change PWM frequency or dutyCycle](#3-set-or-change-PWM-frequency-or-dutyCycle) + * [4. Set or change PWM frequency and dutyCycle manually and efficiently in waveform creation](#4-Set-or-change-PWM-frequency-and-dutyCycle-manually-and-efficiently-in-waveform-creation) + * [5. Important Notes](#5-Important-Notes) +* [Examples](#examples) + * [ 1. ATtiny_PWM_StepperControl](examples/ATtiny_PWM_StepperControl) + * [ 2. AVR_PWM_StepperControl](examples/AVR_PWM_StepperControl) + * [ 3. Dx_PWM_StepperControl](examples/Dx_PWM_StepperControl) + * [ 4. ESP32_PWM_StepperControl](examples/ESP32_PWM_StepperControl) + * [ 5. MBED_RP2040_PWM_StepperControl](examples/MBED_RP2040_PWM_StepperControl) + * [ 6. megaAVR_PWM_StepperControl](examples/megaAVR_PWM_StepperControl) + * [ 7. nRF52_MBED_PWM_StepperControl](examples/nRF52_MBED_PWM_StepperControl) + * [ 8. nRF52_PWM_StepperControl](examples/nRF52_PWM_StepperControl) + * [ 9. Portenta_H7_PWM_StepperControl](examples/Portenta_H7_PWM_StepperControl) + * [ 10. RP2040_PWM_StepperControl](examples/RP2040_PWM_StepperControl) + * [ 11. SAMD_PWM_StepperControl](examples/SAMD_PWM_StepperControl) + * [ 12. SAMDUE_PWM_StepperControl](examples/SAMDUE_PWM_StepperControl) + * [ 13. STM32_PWM_StepperControl](examples/STM32_PWM_StepperControl) + * [ 14. Teensy_PWM_StepperControl](examples/Teensy_PWM_StepperControl) +* [Example RP2040_PWM_StepperControl](#example-RP2040_PWM_StepperControl) +* [Debug Terminal Output Samples](#debug-terminal-output-samples) + * [1. PWM_Multi on MBED RaspberryPi Pico](#1-PWM_Multi-on-MBED-RaspberryPi-Pico) + * [2. PWM_Multi on RASPBERRY_PI_PICO](#2-PWM_Multi-on-RASPBERRY_PI_PICO) + * [3. PWM_DynamicFreq on Nano RP2040 Connect](#3-PWM_DynamicFreq-on-Nano-RP2040-Connect) + * [4. PWM_DynamicDutyCycle on RASPBERRY_PI_PICO](#4-PWM_DynamicDutyCycle-on-RASPBERRY_PI_PICO) + * [5. PWM_MultiChannel on RASPBERRY_PI_PICO](#5-PWM_MultiChannel-on-RASPBERRY_PI_PICO) + * [6. PWM_Waveform on RASPBERRY_PI_PICO](#6-PWM_Waveform-on-RASPBERRY_PI_PICO) + * [7. PWM_Waveform_Fast on RASPBERRY_PI_PICO](#7-PWM_Waveform_Fast-on-RASPBERRY_PI_PICO) +* [Debug](#debug) +* [Troubleshooting](#troubleshooting) +* [Issues](#issues) +* [TO DO](#to-do) +* [DONE](#done) +* [Contributions and Thanks](#contributions-and-thanks) +* [Contributing](#contributing) +* [License](#license) +* [Copyright](#copyright) + +--- +--- + +### Why do we need this [ContinuousStepper_Generic library](https://github.com/khoih-prog/ContinuousStepper_Generic) + +### Features + +This PWM-wrapper library enables you to use Hardware-PWM use PWM to control continuous Stepper Motor. + +This library is the wrapper of the following FastPWM libraries to enable you to **port your PWM code easily between platforms** + + 1. [**RP2040_PWM**](https://github.com/khoih-prog/RP2040_PWM) + 2. [**AVR_PWM**](https://github.com/khoih-prog/AVR_PWM) + 3. [**megaAVR_PWM**](https://github.com/khoih-prog/megaAVR_PWM) + 4. [**ESP32_FastPWM**](https://github.com/khoih-prog/ESP32_FastPWM) + 5. [**SAMD_PWM**](https://github.com/khoih-prog/SAMD_PWM) + 6. [**SAMDUE_PWM**](https://github.com/khoih-prog/SAMDUE_PWM) + 7. [**nRF52_PWM**](https://github.com/khoih-prog/nRF52_PWM) + 8. [**Teensy_PWM**](https://github.com/khoih-prog/Teensy_PWM) + 9. [**ATtiny_PWM**](https://github.com/khoih-prog/ATtiny_PWM) +10. [**Dx_PWM**](https://github.com/khoih-prog/Dx_PWM) +11. [**Portenta_H7_PWM**](https://github.com/khoih-prog/Portenta_H7_PWM) +12. [**MBED_ContinuousStepper_Generic**](https://github.com/khoih-prog/MBED_ContinuousStepper_Generic) +13. [**nRF52_MBED_PWM**](https://github.com/khoih-prog/nRF52_MBED_PWM) +14. [**STM32_PWM**](https://github.com/khoih-prog/STM32_PWM) + +--- + +The most important feature is they're purely hardware-based PWM channels. Therefore, their operations are **not blocked by bad-behaving software functions / tasks**. + +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. + +Being hardware-based PWM, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet or Blynk services. You can also have many `(up to 16)` PWM output signals to use. + +This non-being-blocked important feature is absolutely necessary for mission-critical tasks. + +--- + +#### Why using hardware-based PWM is better + +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(). + +So your function **might not be executed, and the result would be disastrous.** + +You'd prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.). + +The correct choice is to use a Hardware Timer with **Interrupt** to call your function. + +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(). That's necessary if you need to measure some data requiring better accuracy. + +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. + + +--- + +### Currently supported Boards + +This [**ContinuousStepper_Generic** library](https://github.com/khoih-prog/ContinuousStepper_Generic) currently supports these following boards: + + 1. **nRF52 boards**, such as **AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B302_ublox, NINA_B112_ublox, etc.** + 2. **SAM DUE** + 3. **SAMD21** + - Arduino SAMD21: ZERO, MKRs, NANO_33_IOT, etc. + - Adafruit SAMD21 (M0): ItsyBitsy M0, Feather M0, Feather M0 Express, Metro M0 Express, Circuit Playground Express, Trinket M0, PIRkey, Hallowing M0, Crickit M0, etc. + - Seeeduino: LoRaWAN, Zero, Femto M0, XIAO M0, Wio GPS Board, etc. + + 4. **SAMD51** + - Adafruit SAMD51 (M4): Metro M4, Grand Central M4, ItsyBitsy M4, Feather M4 Express, Trellis M4, Metro M4 AirLift Lite, MONSTER M4SK Express, Hallowing M4, etc. + - Seeeduino: Wio Terminal, Grove UI Wireless + + 5. **Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0, LC) with SPI, SPI1, SPI2** + 6. **AVR Mega1280, 2560, ADK.** + 7. ESP32 + 8. ESP8266 **To be addded** + + 9. RP2040-based boards, such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, using [**Arduino-mbed RP2040** core](https://github.com/arduino/ArduinoCore-mbed) or [**Earle Philhower's arduino-pico** core](https://github.com/earlephilhower/arduino-pico) with **SPI, SPI1** + + 10. **Portenta_H7** + + 11. **Arduino UNO WiFi Rev2, AVR_NANO_EVERY, etc.** + + 12. **Arduino AVR_Dx boards using DxCore** + +- **AVRDA-based boards (AVR128DA, AVR64DA, AVR32DA, etc.)** + +- **AVRDB-based boards (AVR128DB, AVR64DB, AVR32DB, etc.)** + + 13. **Seeeduino nRF52840-based boards such as XIAO_NRF52840 and XIAO_NRF52840_SENSE**, etc. using Seeed `mbed` or `nRF52` core + + +--- +--- + +## Prerequisites + + 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) + 2. [`Arduino AVR core 1.8.6+`](https://github.com/arduino/ArduinoCore-avr) for Arduino (Use Arduino Board Manager) AVR boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-avr.svg)](https://github.com/arduino/ArduinoCore-avr/releases/latest) + 3. [`Teensy core v1.57+`](https://www.pjrc.com/teensy/td_download.html) for Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0) boards. [![GitHub release](https://img.shields.io/github/release/PaulStoffregen/cores.svg)](https://github.com/PaulStoffregen/cores/releases/latest) + 4. [`Arduino SAM DUE core v1.6.12+`](https://github.com/arduino/ArduinoCore-sam) for SAM DUE ARM Cortex-M3 boards. + 5. [`Arduino SAMD core 1.8.13+`](https://github.com/arduino/ArduinoCore-samd) for SAMD ARM Cortex-M0+ boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-samd.svg)](https://github.com/arduino/ArduinoCore-samd/releases/latest) + 6. [`Adafruit SAMD core 1.7.11+`](https://github.com/adafruit/ArduinoCore-samd) for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). [![GitHub release](https://img.shields.io/github/release/adafruit/ArduinoCore-samd.svg)](https://github.com/adafruit/ArduinoCore-samd/releases/latest) + 7. [`Seeeduino SAMD core 1.8.3+`](https://github.com/Seeed-Studio/ArduinoCore-samd) for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). [![Latest release](https://img.shields.io/github/release/Seeed-Studio/ArduinoCore-samd.svg)](https://github.com/Seeed-Studio/ArduinoCore-samd/releases/latest/) + 8. [`Adafruit nRF52 v1.3.0+`](https://github.com/adafruit/Adafruit_nRF52_Arduino) for nRF52 boards such as Adafruit NRF52840_FEATHER, NRF52832_FEATHER, NRF52840_FEATHER_SENSE, NRF52840_ITSYBITSY, NRF52840_CIRCUITPLAY, NRF52840_CLUE, NRF52840_METRO, NRF52840_PCA10056, PARTICLE_XENON, **NINA_B302_ublox**, etc. [![GitHub release](https://img.shields.io/github/release/adafruit/Adafruit_nRF52_Arduino.svg)](https://github.com/adafruit/Adafruit_nRF52_Arduino/releases/latest) + 9. [`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/) +10. [`ESP8266 Core 3.1.1+`](https://github.com/esp8266/Arduino) for ESP8266-based boards. [![Latest release](https://img.shields.io/github/release/esp8266/Arduino.svg)](https://github.com/esp8266/Arduino/releases/latest/). To use ESP8266 core 2.7.1+ for LittleFS. +11. [`ArduinoCore-mbed mbed_rp2040, mbed_nano, mbed_portenta core 3.5.4+`](https://github.com/arduino/ArduinoCore-mbed) for Arduino (Use Arduino Board Manager) **Portenta_H7, RP2040-based boards, such as Nano_RP2040_Connect, RASPBERRY_PI_PICO**. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-mbed.svg)](https://github.com/arduino/ArduinoCore-mbed/releases/latest) +12. [`Earle Philhower's arduino-pico core v2.7.1+`](https://github.com/earlephilhower/arduino-pico) for RP2040-based boards such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, etc. [![GitHub release](https://img.shields.io/github/release/earlephilhower/arduino-pico.svg)](https://github.com/earlephilhower/arduino-pico/releases/latest) +13. [`Arduino megaAVR core 1.8.7+`](https://github.com/arduino/ArduinoCore-megaavr/releases) for Arduino megaAVR boards such as **Arduino UNO WiFi Rev2, AVR_NANO_EVERY, etc.**. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-megaavr.svg)](https://github.com/arduino/ArduinoCore-megaavr/releases/latest) +14. [`SpenceKonde DxCore core 1.5.3+`](https://github.com/SpenceKonde/DxCore) for Arduino AVRDx boards. [![GitHub release](https://img.shields.io/github/release/SpenceKonde/DxCore.svg)](https://github.com/SpenceKonde/DxCore/releases/latest). Follow [**DxCore Installation**](https://github.com/SpenceKonde/DxCore/blob/master/Installation.md). +15. [`Seeeduino nRF52 core 1.1.0+`](https://github.com/Seeed-Studio/Adafruit_nRF52_Arduino) for Seeed nRF52840-based boards such as **Seeed_XIAO_NRF52840 and Seeed_XIAO_NRF52840_SENSE**. [![GitHub release](https://img.shields.io/github/release/Seeed-Studio/Adafruit_nRF52_Arduino.svg)](https://github.com/Seeed-Studio/Adafruit_nRF52_Arduino/releases/latest) +16. [`Seeeduino mbed core 2.9.0+`](https://github.com/Seeed-Studio/ArduinoCore-mbed) for Seeed nRF52840-based boards such as **SEEED_XIAO_NRF52840 and SEEED_XIAO_NRF52840_SENSE**. [![GitHub release](https://img.shields.io/github/release/Seeed-Studio/ArduinoCore-mbed.svg)](https://github.com/Seeed-Studio/ArduinoCore-mbed/releases/latest) + +--- + +17. [`RP2040_PWM library v1.4.1+`](https://github.com/khoih-prog/RP2040_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/RP2040_PWM.svg?)](https://www.ardu-badge.com/RP2040_PWM) +18. [`AVR_PWM library v1.0.1+`](https://github.com/khoih-prog/AVR_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/AVR_PWM.svg?)](https://www.ardu-badge.com/AVR_PWM) +19. [`megaAVR_PWM library v1.0.1+`](https://github.com/khoih-prog/megaAVR_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/megaAVR_PWM.svg?)](https://www.ardu-badge.com/megaAVR_PWM) +20. [`ESP32_FastPWM library v1.0.1+`](https://github.com/khoih-prog/ESP32_FastPWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP32_FastPWM.svg?)](https://www.ardu-badge.com/ESP32_FastPWM) +21. [`SAMD_PWM library v1.0.1+`](https://github.com/khoih-prog/SAMD_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/SAMD_PWM.svg?)](https://www.ardu-badge.com/SAMD_PWM) +22. [`SAMDUE_PWM library v1.0.1+`](https://github.com/khoih-prog/SAMDUE_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/SAMDUE_PWM.svg?)](https://www.ardu-badge.com/SAMDUE_PWM) +23. [`nRF52_PWM library v1.0.1+`](https://github.com/khoih-prog/nRF52_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/nRF52_PWM.svg?)](https://www.ardu-badge.com/nRF52_PWM) +24. [`Teensy_PWM library v1.0.1+`](https://github.com/khoih-prog/Teensy_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/Teensy_PWM.svg?)](https://www.ardu-badge.com/Teensy_PWM) +25. [`ATtiny_PWM library v1.0.1+`](https://github.com/khoih-prog/ATtiny_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/ATtiny_PWM.svg?)](https://www.ardu-badge.com/ATtiny_PWM) +26. [`Dx_PWM library v1.0.1+`](https://github.com/khoih-prog/Dx_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/Dx_PWM.svg?)](https://www.ardu-badge.com/Dx_PWM) +27. [`Portenta_H7_PWM library v2.0.3+`](https://github.com/khoih-prog/Portenta_H7_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/Portenta_H7_PWM.svg?)](https://www.ardu-badge.com/Portenta_H7_PWM) +28. [`MBED_RP2040_PWM library v1.0.1+`](https://github.com/khoih-prog/MBED_RP2040_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/MBED_RP2040_PWM.svg?)](https://www.ardu-badge.com/MBED_RP2040_PWM) +29. [`nRF52_MBED_PWM library v1.0.3+`](https://github.com/khoih-prog/nRF52_MBED_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/nRF52_MBED_PWM.svg?)](https://www.ardu-badge.com/nRF52_MBED_PWM) +30. [`STM32_PWM library v1.0.1+`](https://github.com/khoih-prog/STM32_PWM). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/STM32_PWM.svg?)](https://www.ardu-badge.com/STM32_PWM) + +--- +--- + +## Installation + +### Use Arduino Library Manager + +The best and easiest way is to use `Arduino Library Manager`. Search for [**ContinuousStepper_Generic**](https://github.com/khoih-prog/ContinuousStepper_Generic), then select / install the latest version. +You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/ContinuousStepper_Generic.svg?)](https://www.ardu-badge.com/ContinuousStepper_Generic) for more detailed instructions. + +### Manual Install + +Another way to install is to: + +1. Navigate to [**ContinuousStepper_Generic**](https://github.com/khoih-prog/ContinuousStepper_Generic) page. +2. Download the latest release `ContinuousStepper_Generic-main.zip`. +3. Extract the zip file to `ContinuousStepper_Generic-main` directory +4. Copy whole `ContinuousStepper_Generic-main` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. + +### VS Code & PlatformIO + +1. Install [VS Code](https://code.visualstudio.com/) +2. Install [PlatformIO](https://platformio.org/platformio-ide) +3. Install [**ContinuousStepper_Generic** library](https://registry.platformio.org/libraries/khoih-prog/ContinuousStepper_Generic) by using [Library Manager](https://registry.platformio.org/libraries/khoih-prog/ContinuousStepper_Generic/installation). Search for **ContinuousStepper_Generic** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) +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) + +--- +--- + +### Examples: + + 1. [ATtiny_PWM_StepperControl](examples/ATtiny_PWM_StepperControl) + 2. [AVR_PWM_StepperControl](examples/AVR_PWM_StepperControl) + 3. [Dx_PWM_StepperControl](examples/Dx_PWM_StepperControl) + 4. [ESP32_PWM_StepperControl](examples/ESP32_PWM_StepperControl) + 5. [MBED_RP2040_PWM_StepperControl](examples/MBED_RP2040_PWM_StepperControl) + 6. [megaAVR_PWM_StepperControl](examples/megaAVR_PWM_StepperControl) + 7. [nRF52_MBED_PWM_StepperControl](examples/nRF52_MBED_PWM_StepperControl) + 8. [nRF52_PWM_StepperControl](examples/nRF52_PWM_StepperControl) + 9. [Portenta_H7_PWM_StepperControl](examples/Portenta_H7_PWM_StepperControl) +10. [RP2040_PWM_StepperControl](examples/RP2040_PWM_StepperControl) +11. [SAMD_PWM_StepperControl](examples/SAMD_PWM_StepperControl) +12. [SAMDUE_PWM_StepperControl](examples/SAMDUE_PWM_StepperControl) +13. [STM32_PWM_StepperControl](examples/STM32_PWM_StepperControl) +14. [Teensy_PWM_StepperControl](examples/Teensy_PWM_StepperControl) + + +--- +--- + +### Example [RP2040_PWM_StepperControl](examples/RP2040_PWM_StepperControl) + +https://github.com/khoih-prog/ContinuousStepper_Generic/blob/9d4196bb4dbe699f32f5b92159ffa0235d86397b/examples/RP2040_PWM_StepperControl/RP2040_PWM_StepperControl.ino#L16-L92 + + +--- +--- + +### Debug + +Debug is enabled by default on Serial. + +You can also change the debugging level `_PWM_LOGLEVEL_` from 0 to 4 + +```cpp +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. +#define _PWM_LOGLEVEL_ 0 +``` + +--- + +### Troubleshooting + +If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards. + +Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions. + + +--- +--- + +### Issues + +Submit issues to: [ContinuousStepper_Generic issues](https://github.com/khoih-prog/ContinuousStepper_Generic/issues) + +--- + +## TO DO + +1. Search for bug and improvement +2. Similar features for remaining or new Arduino boards + +--- + +## DONE + + 1. Initial coding to use PWM to control continuous Stepper Motor. Check [Using PWM to step a stepper driver #16](https://github.com/khoih-prog/ContinuousStepper_Generic/issues/16) + 2. Use `allman astyle` and add `utils` + +--- +--- + +### Contributions and Thanks + +Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library. + +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 this library + + + + + + +
dinther
Paul van Dinther

+ +--- + +## Contributing + +If you want to contribute to this project: +- Report bugs and errors +- Ask for enhancements +- Create issues and pull requests +- Tell other people about this library + +--- + +### License + +- The library is licensed under [MIT](https://github.com/khoih-prog/ContinuousStepper_Generic/blob/main/LICENSE) + +--- + +## Copyright + +Copyright 2023- Khoi Hoang + + diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..eea426a --- /dev/null +++ b/changelog.md @@ -0,0 +1,32 @@ +# ContinuousStepper_Generic Library + +[![arduino-library-badge](https://www.ardu-badge.com/badge/ContinuousStepper_Generic.svg?)](https://www.ardu-badge.com/ContinuousStepper_Generic) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/ContinuousStepper_Generic.svg)](https://github.com/khoih-prog/ContinuousStepper_Generic/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/ContinuousStepper_Generic/blob/main/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/ContinuousStepper_Generic.svg)](http://github.com/khoih-prog/ContinuousStepper_Generic/issues) + + + +Donate to my libraries using BuyMeACoffee + + + +--- +--- + +## Table of Contents + +* [Changelog](#changelog) + * [Initial Releases v1.0.0](#Initial-Releases-v100) + +--- +--- + +## Changelog + +### Initial Releases v1.0.0 + +1. Initial coding to use PWM to control continuous Stepper Motor. Check [Using PWM to step a stepper driver #16](https://github.com/khoih-prog/ContinuousStepper_Generic/issues/16) +2. Use `allman astyle` and add `utils` + diff --git a/examples/ATtiny_PWM_StepperControl/ATtiny_PWM_StepperControl.ino b/examples/ATtiny_PWM_StepperControl/ATtiny_PWM_StepperControl.ino new file mode 100644 index 0000000..ee7b68e --- /dev/null +++ b/examples/ATtiny_PWM_StepperControl/ATtiny_PWM_StepperControl.ino @@ -0,0 +1,128 @@ +/**************************************************************************************************************************** + ATtiny_PWM_StepperControl.ino + For Arduino AVR ATtiny-based boards (ATtiny3217, etc.) using megaTinyCore + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !defined(MEGATINYCORE) + #error This is designed only for AVR_ATtiny boards using megaTinyCore +#endif + +#define _PWM_LOGLEVEL_ 4 + +// Select false to use PWM +#define USING_TIMER false //true + +#include "ContinuousStepper_Generic.h" + +/* + const uint8_t digital_pin_to_timer[] = { + // Left side, top to bottom + TIMERA0, // 0 PA4 WO4 WOA + TIMERA0, // 1 PA5 WO5 WOB + #if defined(DAC0) + DACOUT, // 2 PA6 + #else + NOT_ON_TIMER, // 2 PA6 + #endif + NOT_ON_TIMER, // 3 PA7 + NOT_ON_TIMER, // 4 PB7 + NOT_ON_TIMER, // 5 PB6 + NOT_ON_TIMER, // 6 PB5 WO2 Alt + NOT_ON_TIMER, // 7 PB4 WO1 Alt + NOT_ON_TIMER, // 8 PB3 WO0 Alt + TIMERA0, // 9 PB2 WO2 + TIMERA0, // 10 PB1 WO1 + // Right side, bottom to top + TIMERA0, // 11 PB0 WO0 + #if (defined(TCD0) && defined(USE_TIMERD0_PWM)) + TIMERD0, // 12 PC0 WOC + TIMERD0, // 13 PC1 WOD + #else + NOT_ON_TIMER, // 12 PC0 + NOT_ON_TIMER, // 13 PC1 + #endif + NOT_ON_TIMER, // 14 PC2 + NOT_ON_TIMER, // 15 PC3 WO3 Alt + NOT_ON_TIMER, // 16 PC4 WO4 Alt + NOT_ON_TIMER, // 17 PC5 WO5 Alt + NOT_ON_TIMER, // 18 PA1 + NOT_ON_TIMER, // 19 PA2 + TIMERA0, // 20 PA3 WO3 + NOT_ON_TIMER // 21 PA0 + }; +*/ + +// OK, only PIN_PA4-5:TCA0 +// PIN_PC0-1: TCD0 => not OK yet for frequency +// Not OK, PIN_PA6, 7, PIN_PB0-2:TCA0 + +#define STEP_PIN PIN_PA5 //PIN_PB4 + +#define DIR_PIN PIN_PA6 + +ATtiny_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting ATtiny_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(AT_TINY_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new ATtiny_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/AVR_PWM_StepperControl/AVR_PWM_StepperControl.ino b/examples/AVR_PWM_StepperControl/AVR_PWM_StepperControl.ino new file mode 100644 index 0000000..762d578 --- /dev/null +++ b/examples/AVR_PWM_StepperControl/AVR_PWM_StepperControl.ino @@ -0,0 +1,155 @@ +/**************************************************************************************************************************** + AVR_PWM_StepperControl.ino + For AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. ) + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + This is pure hardware-based PWM +*****************************************************************************************************************************/ +/****************************************************************************************************************************** + // For UNO / Nano + Timer0 ( 8-bit) used by delay(), millis() and micros(), and PWM generation on pins 5 (6 not usable) + Timer1 (16-bit) used by the Servo.h library and PWM generation on pins 9 and 10 + Timer2 ( 8-bit) used by Tone() and PWM generation on pins 3 and 11 + // For Mega + Timer0 ( 8-bit) used by delay(), millis() and micros(), and PWM generation on pins 4 (13 not usable) + Timer1 (16-bit) used by the Servo.h library and PWM generation on pins 11, 12 + Timer2 ( 8-bit) used by Tone() and PWM generation on pins 9 and 10 + Timer3 (16-bit) used by PWM generation on pins 2, 3 and 5 + Timer4 (16-bit) used by PWM generation on pins 6, 7 and 8 + Timer5 (16-bit) used by PWM generation on pins 44, 45 and 46 + + //////////////////////////////////////////// + // For Mega (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 44, 45, 46) + Pin 2 => TIMER3B // PE 4 ** 2 ** PWM2 + Pin 3 => TIMER3C // PE 5 ** 3 ** PWM3 + Pin 4 => TIMER0B // PG 5 ** 4 ** PWM4 + Pin 5 => TIMER3A // PE 3 ** 5 ** PWM5 + Pin 6 => TIMER4A // PH 3 ** 6 ** PWM6 + Pin 7 => TIMER4B // PH 4 ** 7 ** PWM7 + Pin 8 => TIMER4C // PH 5 ** 8 ** PWM8 + Pin 9 => TIMER2B // PH 6 ** 9 ** PWM9 + Pin 10 => TIMER2A // PB 4 ** 10 ** PWM10 + Pin 11 => TIMER1A // PB 5 ** 11 ** PWM11 + Pin 12 => TIMER1B // PB 6 ** 12 ** PWM12 + Pin 13 => TIMER0A // PB 7 ** 13 ** PWM13 + Pin 44 => TIMER5C // PL 5 ** 44 ** D44 + Pin 45 => TIMER5B // PL 4 ** 45 ** D45 + Pin 46 => TIMER5A // PL 3 ** 46 ** D46 + //////////////////////////////////////////// + // For 32u4 (3, 5, 6, 9, 10, 11, 13) + Pin 3 => TIMER0B + Pin 5 => TIMER3A + Pin 6 => TIMER4D + Pin 9 => TIMER1A + Pin 10 => TIMER1B + Pin 11 => TIMER0A + Pin 13 => TIMER4A + //////////////////////////////////////////// + // For UNO, Nano (3, 5, 6, 9, 10, 11) + Pin 3 => TIMER2B, + Pin 5 => TIMER0B + Pin 6 => TIMER0A + Pin 9 => TIMER1A + Pin 10 => TIMER1B + Pin 11 => TIMER2(A) +******************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#define _PWM_LOGLEVEL_ 4 + +#include "ContinuousStepper_Generic.h" + +#if ( PWM_USING_ATMEGA2560 ) +// Pins tested OK in Mega +//#define STEP_PIN 12 // Timer1B on Mega +//#define STEP_PIN 11 // Timer1A on Mega +//#define STEP_PIN 9 // Timer2B on Mega +//#define STEP_PIN 2 // Timer3B on Mega +//#define STEP_PIN 3 // Timer3C on Mega +//#define STEP_PIN 5 // Timer3A on Mega +//#define STEP_PIN 6 // Timer4A on Mega +//#define STEP_PIN 7 // Timer4B on Mega +#define STEP_PIN 8 // Timer4C on Mega +//#define STEP_PIN 46 // Timer5A on Mega +//#define STEP_PIN 45 // Timer5B on Mega +//#define STEP_PIN 44 // Timer5C on Mega + +#elif ( PWM_USING_ATMEGA_32U4 ) +// Pins tested OK on 32u4 +//#define STEP_PIN 5 // Timer3A on 32u4 +#define STEP_PIN 9 // Timer1A on 32u4 +//#define STEP_PIN 10 // Timer1B on 32u4 + +#else + +// Pins tested OK on Nano / UNO +//#define STEP_PIN 9 // Timer1A on UNO, Nano, etc +#define STEP_PIN 10 // Timer1B on UNO, Nano, etc +//#define STEP_PIN 5 // Timer0B on UNO, Nano, e +//#define STEP_PIN 3 // Timer2B on UNO, Nano, etc +#endif + +#define DIR_PIN 12 + +AVR_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting AVR_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(AVR_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new AVR_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/Dx_PWM_StepperControl/Dx_PWM_StepperControl.ino b/examples/Dx_PWM_StepperControl/Dx_PWM_StepperControl.ino new file mode 100644 index 0000000..8d1a866 --- /dev/null +++ b/examples/Dx_PWM_StepperControl/Dx_PWM_StepperControl.ino @@ -0,0 +1,109 @@ +/**************************************************************************************************************************** + Dx_PWM_StepperControl.ino + For Arduino AVRDx-based boards (AVR128Dx, AVR64Dx, AVR32Dx, etc.) using DxCore + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !defined(DXCORE) + #error This is designed only for AVRDx boards using DXCORE +#endif + +#define _PWM_LOGLEVEL_ 4 + +#if defined(__AVR_AVR128DA48__) + #define SerialDebug Serial1 +#elif defined(__AVR_AVR128DB48__) + #define SerialDebug Serial3 +#else + // standard Serial + #define SerialDebug Serial +#endif + +#define PWM_GENERIC_DEBUG_PORT SerialDebug + +#include "ContinuousStepper_Generic.h" + +// On DX AVR128DB48 +// PA0-3: Not PWM +// PA4-7: TD0 => not supported yet +// PB0-5: TCA1 +// PC0-5: TCA0 +// PC6-7: Not PWM +// PD0-7: Not PWM +// PE0-3: Not PWM +// PF0-3: Not PWM +// PF4-5: TCB + +#if defined(PIN_PF5) + #define STEP_PIN PIN_PF5 +#else + #define STEP_PIN PIN_PC0 +#endif + +#define DIR_PIN PIN_PA0 + +Dx_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + SerialDebug.begin(115200); + + while (!SerialDebug && millis() < 5000); + + delay(100); + + SerialDebug.print(F("\nStarting Dx_PWM_StepperControl on ")); + SerialDebug.println(BOARD_NAME); + SerialDebug.println(DX_PWM_VERSION); + SerialDebug.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new Dx_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/ESP32_PWM_StepperControl/ESP32_PWM_StepperControl.ino b/examples/ESP32_PWM_StepperControl/ESP32_PWM_StepperControl.ino new file mode 100644 index 0000000..6db9eed --- /dev/null +++ b/examples/ESP32_PWM_StepperControl/ESP32_PWM_StepperControl.ino @@ -0,0 +1,104 @@ +/**************************************************************************************************************************** + ESP32_PWM_StepperControl.ino + For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.0+ + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + This is pure hardware-based PWM + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ +/****************************************************************************************************************************** + // All GPIO pins (but GPIO34-39) can be used to generate PWM + // For ESP32, number of channels is 16, max 20-bit resolution + // For ESP32_S2, ESP32_S3, number of channels is 8 + // For ESP32_C3, number of channels is 6 +******************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !defined(ESP32) + #error This is designed only for ESP32 boards +#endif + +#define _PWM_LOGLEVEL_ 4 + +#include "ContinuousStepper_Generic.h" + +#if ARDUINO_ESP32C3_DEV + #define STEP_PIN 9 +#else + #define STEP_PIN 16 +#endif + +#define DIR_PIN 4 + +// Max resolution is 20-bit +// Resolution 65536 (16-bit) for lower frequencies, OK @ 1K +// Resolution 4096 (12-bit) for lower frequencies, OK @ 10K +// Resolution 1024 (10-bit) for higher frequencies, OK @ 50K +// Resolution 256 ( 8-bit)for higher frequencies, OK @ 100K, 200K +// Resolution 128 ( 7-bit) for higher frequencies, OK @ 500K +int PWM_resolution = 10; + +//creates pwm instance +ESP32_FAST_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting ESP32_PWM_StepperControl on ")); + Serial.println(ARDUINO_BOARD); + Serial.println(ESP32_FAST_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new ESP32_FAST_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/MBED_RP2040_PWM_StepperControl/MBED_RP2040_PWM_StepperControl.ino b/examples/MBED_RP2040_PWM_StepperControl/MBED_RP2040_PWM_StepperControl.ino new file mode 100644 index 0000000..aed08b8 --- /dev/null +++ b/examples/MBED_RP2040_PWM_StepperControl/MBED_RP2040_PWM_StepperControl.ino @@ -0,0 +1,81 @@ +/**************************************************************************************************************************** + MBED_RP2040_PWM_StepperControl.ino + For MBED RP2040 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \ + defined(ARDUINO_GENERIC_RP2040) ) && defined(ARDUINO_ARCH_MBED) + #error This code is intended to run on the MBED RP2040 platform! Please check your Tools->Board setting. +#endif + +#define _PWM_LOGLEVEL_ 1 + +#include "ContinuousStepper_Generic.h" + +mbed::PwmOut* stepper = nullptr; + +#define STEP_PIN 8 +#define DIR_PIN 9 + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + setPWM(stepper, STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + setPWM(stepper, STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting MBED_RP2040_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(MBED_RP2040_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + //setSpeed(0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/Portenta_H7_PWM_StepperControl/Portenta_H7_PWM_StepperControl.ino b/examples/Portenta_H7_PWM_StepperControl/Portenta_H7_PWM_StepperControl.ino new file mode 100644 index 0000000..7444ca2 --- /dev/null +++ b/examples/Portenta_H7_PWM_StepperControl/Portenta_H7_PWM_StepperControl.ino @@ -0,0 +1,104 @@ +/**************************************************************************************************************************** + Portenta_H7_PWM_StepperControlerControl.ino + + For Portenta_H7 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) ) + #error For Portenta_H7 only +#endif + +#define _PWM_LOGLEVEL_ 4 + +// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error +#include "ContinuousStepper_Generic.h" + +// Can't use same TimerIndex again, e.g., the D1 and D2, using TIM1, can't be use concurrently +// That's why D0, D1, D3, D4 and D6 (using TimerIndex 8, 1, HRTIM and 3) are OK together + +// Only OK for D0, D1, D2, D4 and D5, PA_0C(D15/A0), PA_1C(D16/A1), +// D3, D6, D7, D8, D9, D10, D11, D12, D13, D14, D17(PC_2C/A2), D18(PC_3C/3), PC2(D19/A4) LEDG, LEDB not OK +#define pinD0 D0 // PH15 / TIM8_CH3N +#define pinD1 D1 // PK1 / TIM1_CH1, TIM8_CH3 +#define pinD2 D2 // PJ11 / TIM1_CH2, TIM8_CH2N +#define pinD3 D3 // PG7 / HRTIM_CHE2 +#define pinD4 D4 // PC7 / TIM3_CH2, TIM8_CH2, HRTIM_CHA2 +#define pinD5 D5 // PC6 / TIM3_CH1, TIM8_CH1, HRTIM_CHA1, LPTIM3_OUT +#define pinD6 D6 // PA8 / HRTIM_CHB2 (TIM1_CH1, TIM8_BKIN2) + +// See https://www.st.com/resource/en/datasheet/stm32h747xi.pdf, Table 7, page 53 +// Can't use pins with same TIMx. For example, +// pinD1 and pinD2, using same TIM1, can't be used at the same time +// pinD4 and pinD5, using same TIM3, can't be used at the same time +// pinD3 and pinD6 are using HRTIM, can't be used at the same time and the minimum freq must be ~770Hz + +#define STEP_PIN pinD5 + +#define DIR_PIN D9 + +mbed::PwmOut* stepper = nullptr; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + setPWM(stepper, STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + setPWM(stepper, STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting Portenta_H7_PWM_StepperControlerControl on ")); + Serial.println(BOARD_NAME); + Serial.println(PORTENTA_H7_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // SetPWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + setPWM(stepper, STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/RP2040_PWM_StepperControl/RP2040_PWM_StepperControl.ino b/examples/RP2040_PWM_StepperControl/RP2040_PWM_StepperControl.ino new file mode 100644 index 0000000..6474860 --- /dev/null +++ b/examples/RP2040_PWM_StepperControl/RP2040_PWM_StepperControl.ino @@ -0,0 +1,92 @@ +/**************************************************************************************************************************** + RP2040_PWM_StepperControl.ino + For RP2040 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + The RP2040 PWM block has 8 identical slices. Each slice can drive two PWM output signals, or measure the frequency + or duty cycle of an input signal. This gives a total of up to 16 controllable PWM outputs. All 30 GPIO pins can be driven + by the PWM block + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#define _PWM_LOGLEVEL_ 1 + +#if ( defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \ + defined(ARDUINO_GENERIC_RP2040) ) && !defined(ARDUINO_ARCH_MBED) + + #if(_PWM_LOGLEVEL_>3) + #warning USING_RP2040_PWM + #endif +#else + #error This code is intended to run on the RP2040 arduino-pico platform! Please check your Tools->Board setting. +#endif + +#include "ContinuousStepper_Generic.h" + +RP2040_PWM* stepper; + +#define STEP_PIN 8 +#define DIR_PIN 9 + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting RP2040_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(RP2040_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 in it + // The duty cycle is how you turn the motor on and off + stepper = new RP2040_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/SAMDUE_PWM_StepperControl/SAMDUE_PWM_StepperControl.ino b/examples/SAMDUE_PWM_StepperControl/SAMDUE_PWM_StepperControl.ino new file mode 100644 index 0000000..bce4c96 --- /dev/null +++ b/examples/SAMDUE_PWM_StepperControl/SAMDUE_PWM_StepperControl.ino @@ -0,0 +1,92 @@ +/**************************************************************************************************************************** + SAMDUE_PWM_StepperControl.ino + For SAM_DUE boards using hardware-based PWM + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#define _PWM_LOGLEVEL_ 4 + +// Select false to use PWM +#define USING_TIMER true + +#include "ContinuousStepper_Generic.h" + +// SAM_DUE: +// PWM pins: 6, 7, 8, 9 +// Timer pins: 2-5, 10-13. +// pin2: TC0_CHA0, pin3: TC2_CHA7, pin4: TC2_CHB6, pin5: TC2_CHA6 +// pin 10: TC2_CHB7, pin11: TC2_CHA8, pin12: TC2_CHB8, pin13: TC0_CHB0 + +#if USING_TIMER + #define STEP_PIN 5 +#else + #define STEP_PIN 6 +#endif + +SAMDUE_PWM* stepper; + +#define DIR_PIN 9 + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting SAMDUE_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(SAMDUE_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new SAMDUE_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/SAMD_PWM_StepperControl/SAMD_PWM_StepperControl.ino b/examples/SAMD_PWM_StepperControl/SAMD_PWM_StepperControl.ino new file mode 100644 index 0000000..2787a0e --- /dev/null +++ b/examples/SAMD_PWM_StepperControl/SAMD_PWM_StepperControl.ino @@ -0,0 +1,86 @@ +/**************************************************************************************************************************** + SAMD_PWM_StepperControl.ino + For SAMD21/SAMD51 boards using hardware-based PWM + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#define _PWM_LOGLEVEL_ 4 + +#include "ContinuousStepper_Generic.h" + +// Not OK for Nano_33_IoT (0, 1, 7, 8, 13, 14, 15 ) +// OK for Nano_33_IoT (2, 3, 4, 5, 6, 9, 10, 11, 12, 16, 17) +// TCC OK => pin 4, 5, 6, 8, 9, 10, 11, 16/A2, 17/A3 +// TC OK => pin 12 +// For ITSYBITSY_M4 +// 16-bit Higher accuracy, Lower Frequency, PWM Pin OK: TCCx: 0-2, 4, 5, 7, 9-13 +// 8-bit Lower accuracy, Hi Frequency, PWM Pin OK: TCx: 18-20, 24-25 + +SAMD_PWM* stepper; + +#define STEP_PIN 9 +#define DIR_PIN 8 + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting SAMD_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(SAMD_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new SAMD_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/STM32_PWM_StepperControl/STM32_PWM_StepperControl.ino b/examples/STM32_PWM_StepperControl/STM32_PWM_StepperControl.ino new file mode 100644 index 0000000..7d5ec28 --- /dev/null +++ b/examples/STM32_PWM_StepperControl/STM32_PWM_StepperControl.ino @@ -0,0 +1,215 @@ +/**************************************************************************************************************************** + STM32_PWM_StepperControl.ino + + For STM32F/L/H/G/WB/MP1 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Hardware-based multi-channel PWM wrapper library for STM32F/L/H/G/WB/MP1 boards + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \ + defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \ + defined(STM32WB) || defined(STM32MP1) || defined(STM32L5)) + #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting. +#endif + +// These define's must be placed at the beginning before #include "ESP32_PWM.h" +// _PWM_LOGLEVEL_ from 0 to 4 +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. +#define _PWM_LOGLEVEL_ 4 + +#define USING_MICROS_RESOLUTION true //false + +#include "ContinuousStepper_Generic.h" + +///////////////////////////////////////////////// + +// Change the pin according to your STM32 board. There is no single definition for all boards. +#define pin0 PA0 +#define pin1 D1 +#define pin2 D2 +#define pin3 D3 +#define pin4 D4 +#define pin5 D5 +#define pin6 D6 +#define pin7 D7 + +#define pin8 D8 +#define pin9 D9 +#define pin10 D10 +#define pin11 D11 +#define pin12 D12 +#define pin13 D13 +#define pin14 D14 +#define pin15 D15 +#define pin16 D16 + +////////////////////////////////////////////////////// + +// Change the pin according to your STM32 board. There is no single definition for all boards. + +#if ( defined(STM32F1) && ( defined(ARDUINO_BLUEPILL_F103CB) || defined(ARDUINO_BLUEPILL_F103C8) ) ) + + #warning Using BLUEPILL_F103CB / BLUEPILL_F103C8 pins + + // For F103CB => pin0, pin4, pin10 ============>> TimerIndex = 1, 2, 0 + #define STEP_PIN pin3 + +#elif ( defined(STM32F7) && defined(ARDUINO_NUCLEO_F767ZI) ) + + #warning Using NUCLEO_F767ZI pins + + // For F767ZI => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 + #define STEP_PIN pin3 + +#elif ( defined(STM32L5) && defined(ARDUINO_NUCLEO_L552ZE_Q) ) + + #warning Using NUCLEO_L552ZE_Q pins + + // For NUCLEO_L552ZE_Q => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 + #define STEP_PIN pin3 + +#elif ( defined(STM32H7) && defined(ARDUINO_NUCLEO_H743ZI2) ) + + #warning Using NUCLEO_H743ZI2 pins + + // For NUCLEO_L552ZE_Q => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 + #define STEP_PIN pin3 + +#else + + // For ??? => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 + #define STEP_PIN pin3 + +#endif + +////////////////////////////////////////////////////// + +#define DIR_PIN pin1 + +TIM_TypeDef *stepperTimer; + +HardwareTimer *stepper; + +uint32_t channel; + +int previousSpeed = 0; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + // Do nothing if same speed + if (speed == previousSpeed) + return; + + Serial.print(F("setSpeed = ")); + Serial.println(speed); + + // Create new instance for new speed + if (stepper) + delete stepper; + + stepper = new HardwareTimer(stepperTimer); + + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(channel, STEP_PIN, 500, 0, nullptr); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(channel, STEP_PIN, abs(speed), 50, nullptr); + } + + previousSpeed = speed; +} + +void initPWM(uint32_t step_pin) +{ + // Using pin = PA0, PA1, etc. + PinName pinNameToUse = digitalPinToPinName(step_pin); + + // Automatically retrieve TIM instance and channel associated to pin + // This is used to be compatible with all STM32 series automatically. + stepperTimer = (TIM_TypeDef *) pinmap_peripheral(pinNameToUse, PinMap_PWM); + + if (stepperTimer != nullptr) + { + uint8_t timerIndex = get_timer_index(stepperTimer); + + // pin => 0, 1, etc + channel = STM_PIN_CHANNEL(pinmap_function( pinNameToUse, PinMap_PWM)); + + Serial.print("stepperTimer = 0x"); + Serial.print( (uint32_t) stepperTimer, HEX); + Serial.print(", channel = "); + Serial.print(channel); + Serial.print(", TimerIndex = "); + Serial.print(get_timer_index(stepperTimer)); + Serial.print(", PinName = "); + Serial.println( pinNameToUse ); + + stepper = new HardwareTimer(stepperTimer); + + // SetPWM object and passed just a random frequency of 500 steps/s + // The Stepper RPM will be ( speed * 60 ) / steps-per-revolution + // The duty cycle is how you turn the motor on and off + previousSpeed = 500; + stepper->setPWM(channel, step_pin, previousSpeed, 0, nullptr); + } + else + { + Serial.println("ERROR => Wrong pin, You have to select another one. Skip NULL stepperTimer"); + } +} + +void setup() +{ + pinMode(STEP_PIN, OUTPUT); + digitalWrite(STEP_PIN, LOW); + pinMode(DIR_PIN, OUTPUT); + digitalWrite(DIR_PIN, LOW); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting STM32_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(STM32_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + initPWM(STEP_PIN); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(2000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/Teensy_PWM_StepperControl/Teensy_PWM_StepperControl.ino b/examples/Teensy_PWM_StepperControl/Teensy_PWM_StepperControl.ino new file mode 100644 index 0000000..05060eb --- /dev/null +++ b/examples/Teensy_PWM_StepperControl/Teensy_PWM_StepperControl.ino @@ -0,0 +1,99 @@ +/**************************************************************************************************************************** + Teensy_PWM_StepperControl.ino + + For Teensy boards (Teensy 2.x, Teensy LC, Teensy 3.x, Teensy 4.x, etc.) + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !( defined(CORE_TEENSY) || defined(__IMXRT1062__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) || \ + defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK20DX128__) ) + #error This is designed only for Teensy boards using Teensy Core +#endif + +#define _PWM_LOGLEVEL_ 4 + +#include "ContinuousStepper_Generic.h" + +#define USING_FLEX_TIMERS true + +#if USING_FLEX_TIMERS + #define STEP_PIN 5 +#else + #define STEP_PIN 15 +#endif + +#define DIR_PIN 9 + +float frequency; +float dutyCycle; + +Teensy_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + +#if USING_FLEX_TIMERS + Serial.print(F("\nStarting Teensy_PWM_StepperControl using FlexTimers on ")); +#else + Serial.print(F("\nStarting Teensy_PWM_StepperControl using QuadTimers on ")); +#endif + + Serial.println(BOARD_NAME); + Serial.println(TEENSY_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 in it + // The duty cycle is how you turn the motor on and off + stepper = new Teensy_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/megaAVR_PWM_StepperControl/megaAVR_PWM_StepperControl.ino b/examples/megaAVR_PWM_StepperControl/megaAVR_PWM_StepperControl.ino new file mode 100644 index 0000000..dd319eb --- /dev/null +++ b/examples/megaAVR_PWM_StepperControl/megaAVR_PWM_StepperControl.ino @@ -0,0 +1,119 @@ +/**************************************************************************************************************************** + megaAVR_PWM_StepperControl.ino + For Arduino megaAVR ATMEGA4809-based boards (UNO WiFi Rev2, NANO_EVERY, etc. ) + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + This is pure hardware-based PWM +*****************************************************************************************************************************/ +/****************************************************************************************************************************** + Pins can be used for hardware-PWM + // For ATmega4809 (Nano Every, Uno WiFi Rev2, etc.) + TCA0 (16-bit) used by PWM generation on pins 5, 9 and 10 + TCB0 (16-bit) used by PWM generation on pin 6 + TCB1 (16-bit) used by PWM generation on pin 3 + TCB2 (16-bit) + TCB3 (16-bit) + //////////////////////////////////////////// + // For ATmega4809 (Nano Every, Uno WiFi Rev2, etc.) + Pin 3 => TIMERB1, // 3 PF5, 8-bit PWM, 16-bit counter + Pin 5 => TIMERA0, // 5 PB2, 16-bit PWM, 16-bit counter + Pin 6 => TIMERB0, // 6 PF4, 8-bit PWM, 16-bit counter + Pin 9 => TIMERA0, // 9 PB0, 16-bit PWM, 16-bit counter + Pin 10 => TIMERA0, // 10 PB1, 16-bit PWM, 16-bit counter + //////////////////////////////////////////// +******************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !( defined(__AVR_ATmega4809__) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || \ + defined(ARDUINO_AVR_ATmega4809) || defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \ + defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || defined(ARDUINO_AVR_ATmega1608) || \ + defined(ARDUINO_AVR_ATmega809) || defined(ARDUINO_AVR_ATmega808) ) + #error This code is intended to run on the megaAVR platform! Please check your Tools->Board setting. +#endif + +#define _PWM_LOGLEVEL_ 4 + +#include "ContinuousStepper_Generic.h" + +#define USING_TIMERB true + +#if USING_TIMERB + // Pins tested OK in Nano Every ATmega4809 + #define STEP_PIN 3 // TimerB1, for higher frequencies, up to 100KHz + //#define STEP_PIN 6 // TimerB0, for higher frequencies, up to 100KHz +#elif USING_ARDUINO_MEGA_AVR_CORE + // Pins tested OK in Nano Every ATmega4809 using Arduino megaAVR core + // TimerA0 somehow can't be used with MegaCoreX + #define STEP_PIN 5 // TimerA0, only accurate @ low frequencies (< 1KHz) because of low 250KHz clock + //#define STEP_PIN 9 // TimerA0, only accurate @ low frequencies (< 1KHz) because of low 250KHz clock + //#define STEP_PIN 10 // TimerA0, only accurate @ low frequencies (< 1KHz) because of low 250KHz clock +#else + #error TimerA0 to be used with Arduino megaAVR Core +#endif + +#define DIR_PIN 4 + +//////////////////////////////////////////// + +megaAVR_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting megaAVR_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(MEGA_AVR_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new megaAVR_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/nRF52_MBED_PWM_StepperControl/nRF52_MBED_PWM_StepperControl.ino b/examples/nRF52_MBED_PWM_StepperControl/nRF52_MBED_PWM_StepperControl.ino new file mode 100644 index 0000000..f4da984 --- /dev/null +++ b/examples/nRF52_MBED_PWM_StepperControl/nRF52_MBED_PWM_StepperControl.ino @@ -0,0 +1,81 @@ +/**************************************************************************************************************************** + nRF52_MBED_PWM_StepperControl.ino + For Nano_33_BLE or Nano_33_BLE_Sense boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !( ARDUINO_ARCH_NRF52840 && TARGET_NAME == ARDUINO_NANO33BLE ) + #error This code is designed to run on nRF52-based Nano-33-BLE boards using mbed-RTOS platform! Please check your Tools->Board setting. +#endif + +#define _PWM_LOGLEVEL_ 1 + +// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error +#include "ContinuousStepper_Generic.h" + +// All the digital pins on Arduino Nano 33 BLE sense are PWM-enabled pins which are numbered from D0 to D13 + +#define STEP_PIN D2 +#define DIR_PIN D9 + +mbed::PwmOut* stepper = nullptr; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + setPWM(stepper, STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + setPWM(stepper, STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting nRF52_MBED_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(nRF52_MBED_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/examples/nRF52_PWM_StepperControl/nRF52_PWM_StepperControl.ino b/examples/nRF52_PWM_StepperControl/nRF52_PWM_StepperControl.ino new file mode 100644 index 0000000..b80a193 --- /dev/null +++ b/examples/nRF52_PWM_StepperControl/nRF52_PWM_StepperControl.ino @@ -0,0 +1,92 @@ +/**************************************************************************************************************************** + nRF52_PWM_StepperControl.ino + For nRF52-based boards usinghardware-based PWM with Adafruit_nRF52_Arduino core + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 +*****************************************************************************************************************************/ + +// Use with Stepper-Motor driver, such as TMC2209 + +#if !(defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || \ + defined(MDBT50Q_RX) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #error This code is designed to run on nRF52-based platform! Please check your Tools->Board setting. +#endif + + +#define _PWM_LOGLEVEL_ 4 + +// Select false to use PWM +#define USING_TIMER false //true + +#include "ContinuousStepper_Generic.h" + +// OK for Feather_nRF52840_Express (5, 6, 9-13, 14-21/A0-A7, etc.) +// OK for ItsyBitsy_nRF52840_Express (5, 7, 9-13, 14-20/A0-A6, etc.) + +#define STEP_PIN 5 +#define DIR_PIN 9 + +nRF52_PWM* stepper; + +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM +void setSpeed(int speed) +{ + if (speed == 0) + { + // Use DC = 0 to stop stepper + stepper->setPWM(STEP_PIN, 500, 0); + } + else + { + // Set the frequency of the PWM output and a duty cycle of 50% + digitalWrite(DIR_PIN, (speed < 0)); + stepper->setPWM(STEP_PIN, abs(speed), 50); + } +} + +void setup() +{ + pinMode(DIR_PIN, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(100); + + Serial.print(F("\nStarting nRF52_PWM_StepperControl on ")); + Serial.println(BOARD_NAME); + Serial.println(NRF52_PWM_VERSION); + Serial.println(CONTINUOUS_STEPPER_GENERIC_VERSION); + + // Create PWM object and passed just a random frequency of 500 + // The duty cycle is how you turn the motor on and off + stepper = new nRF52_PWM(STEP_PIN, 500, 0); +} + +void loop() +{ + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev + setSpeed(1000); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); + + // Reversing + setSpeed(-500); + delay(3000); + + // Stop before reversing + setSpeed(0); + delay(3000); +} diff --git a/library.json b/library.json new file mode 100644 index 0000000..2442b92 --- /dev/null +++ b/library.json @@ -0,0 +1,117 @@ +{ + "name": "ContinuousStepper_Generic", + "version": "1.0.0", + "keywords": "timing, device, control, timer, pwm, pwm-slice, hardware-based-pwm, high-frequency-pwm, hardware-pwm, mission-critical, accuracy, non-blocking, mbed, mbed-nano, mbed-rp2040, rpi-pico, rp2040, nano-rp2040-connect, duty-cycle, hardware", + "description": "This library enables you to use Hardware-based PWM channels on Generic boards to use PWM to control continuous Stepper Motor. 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", + "authors": + { + "name": "Khoi Hoang", + "url": "https://github.com/khoih-prog", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "https://github.com/khoih-prog/ContinuousStepper_Generic" + }, + "homepage": "https://github.com/khoih-prog/ContinuousStepper_Generic", + "export": { + "exclude": [ + "linux", + "extras", + "tests" + ] + }, + "dependencies": + [ + { + "owner": "khoih-prog", + "name": "RP2040_PWM", + "version": "^1.4.1", + "platforms": ["raspberrypi"] + }, + { + "owner": "khoih-prog", + "name": "AVR_PWM", + "version": "^1.0.1", + "platforms": ["avr"] + }, + { + "owner": "khoih-prog", + "name": "megaAVR_PWM", + "version": "^1.0.1", + "platforms": ["megaavr"] + }, + { + "owner": "khoih-prog", + "name": "ESP32_FastPWM", + "version": "^1.0.1", + "platforms": ["espressif32"] + }, + { + "owner": "khoih-prog", + "name": "SAMD_PWM", + "version": "^1.0.1", + "platforms": ["samd"] + }, + { + "owner": "khoih-prog", + "name": "SAMDUE_PWM", + "version": "^1.0.1", + "platforms": ["atmelsam"] + }, + { + "owner": "khoih-prog", + "name": "nRF52_PWM", + "version": "^1.0.1", + "platforms": ["nordicnrf52", "nrf52"] + }, + { + "owner": "khoih-prog", + "name": "Teensy_PWM", + "version": "^1.1.1", + "platforms": ["avr"] + }, + { + "owner": "khoih-prog", + "name": "ATtiny_PWM", + "version": "^1.0.1", + "platforms": ["megaavr"] + }, + { + "owner": "khoih-prog", + "name": "Dx_PWM", + "version": "^1.1.1", + "platforms": ["megaavr"] + }, + { + "owner": "khoih-prog", + "name": "Portenta_H7_PWM", + "version": "^2.0.3", + "platforms": ["mbed_portenta"] + }, + { + "owner": "khoih-prog", + "name": "MBED_RP2040_PWM", + "version": "^1.0.1", + "platforms": ["mbed", "mbed_nano", "mbed_rp2040"] + }, + { + "owner": "khoih-prog", + "name": "nRF52_MBED_PWM", + "version": "^1.0.3", + "platforms": ["mbed", "nrf52"] + }, + { + "owner": "khoih-prog", + "name": "STM32_PWM", + "version": "^1.0.1", + "platforms": ["ststm32"] + } + ], + "license": "MIT", + "frameworks": "*", + "platforms": "*", + "examples": "examples/*/*/*.ino", + "headers": ["ContinuousStepper_Generic.h"] +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..6dee0c3 --- /dev/null +++ b/library.properties @@ -0,0 +1,13 @@ +name=ContinuousStepper_Generic +version=1.0.0 +author=Khoi Hoang +maintainer=Khoi Hoang +sentence=This library enables you to use Hardware-based PWM channels on Generic boards to use PWM to control continuous Stepper Motor +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 +category=Device Control +url=https://github.com/khoih-prog/ContinuousStepper_Generic +architectures=* +repository=https://github.com/khoih-prog/ContinuousStepper_Generic +license=MIT +depends=RP2040_PWM, AVR_PWM, megaAVR_PWM, ESP32_FastPWM, SAMD_PWM, SAMDUE_PWM, nRF52_PWM, Teensy_PWM, ATtiny_PWM, Dx_PWM, Portenta_H7_PWM, MBED_RP2040_PWM, nRF52_MBED_PWM, STM32_PWM +includes=ContinuousStepper_Generic.h diff --git a/platformio/platformio.ini b/platformio/platformio.ini new file mode 100644 index 0000000..e089f6d --- /dev/null +++ b/platformio/platformio.ini @@ -0,0 +1,429 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +; ============================================================ +; ============================================================ +[platformio] +; ============================================================ +; chose environment: +; ESP8266 +; ESP32 +; SAMD +; NRF52 +; STM32 +; pico +; ============================================================ +;default_envs = ESP8266 +;default_envs = ESP32 +;default_envs = SAMD +default_envs = pico +;default_envs = mbed_pico +;default_envs = NRF52 +;default_envs = STM32 +;default_envs = portenta_h7_m7 +;default_envs = portenta_h7_m4 + +; ============================================================ +; ============================================================ +[env] +; ============================================================ +; Serial configuration +; choose upload speed, serial-monitor speed +; ============================================================ +upload_speed = 921600 +;upload_port = COM11 +;monitor_speed = 9600 +;monitor_port = COM11 + +; ============================================================ +; Checks for the compatibility with frameworks and dev/platforms +lib_compat_mode = strict +lib_ldf_mode = chain+ +;lib_ldf_mode = deep+ + +; ============================================================ +lib_deps = +; PlatformIO 4.x +; RP2040_PWM@~1.4.1 +; AVR_PWM@>=1.0.1 +; megaAVR_PWM@>=1.0.1 +; ESP32_FastPWM@>=1.0.1 +; SAMD_PWM@>=1.0.1 +; SAMDUE_PWM@>=1.0.1 +; nRF52_PWM@>=1.0.1 +; Teensy_PWM@>=1.1.1 +; ATtiny_PWM@>=1.0.1 +; Dx_PWM@>=1.1.1 +; Portenta_H7_PWM@>=2.0.3 +; MBED_RP2040_PWM@>=1.0.1 +; nRF52_MBED_PWM@>=1.0.3 +; STM32_PWM@>=1.0.1 +; ============================================================ +; PlatformIO 5.x + khoih-prog/RP2040_PWM@~1.4.1 + khoih-prog/AVR_PWM@>=1.0.1 + khoih-prog/megaAVR_PWM@>=1.0.1 + khoih-prog/ESP32_FastPWM@>=1.0.1 + khoih-prog/SAMD_PWM@>=1.0.1 + khoih-prog/SAMDUE_PWM@>=1.0.1 + khoih-prog/nRF52_PWM@>=1.0.1 + khoih-prog/Teensy_PWM@>=1.1.1 + khoih-prog/ATtiny_PWM@>=1.0.1 + khoih-prog/Dx_PWM@>=1.1.1 + khoih-prog/Portenta_H7_PWM@>=2.0.3 + khoih-prog/MBED_RP2040_PWM@>=1.0.1 + khoih-prog/nRF52_MBED_PWM@>=1.0.3 + khoih-prog/STM32_PWM@>=1.0.1 + +; ============================================================ +build_flags = +; set your debug output (default=Serial) +; -D DEBUG_ESP_PORT=Serial +; comment the following line to enable WiFi debugging +; -D NDEBUG + +; ============================================================ +; ============================================================ +[env:portenta_h7_m7] +platform = ststm32 +board = portenta_h7_m7 +framework = arduino + +; ============================================================ +; ============================================================ +[env:portenta_h7_m4] +platform = ststm32 +board = portenta_h7_m4 +framework = arduino + +; ============================================================ +; ============================================================ +[env:pico] +; ============================================================ +; Just a sample for arduino-pice core +; You have to research and fix if there is issue +; ============================================================ +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = pico +framework = arduino +board_build.core = earlephilhower + +; ============================================================ +; ============================================================ +[env:mbed_pico] +; ============================================================ +; Just a sample for mbed_rp2040 and mbed_nano cores +; You have to research and fix if there is issue +; ============================================================ +platform = raspberrypi +board = pico +framework = arduino +upload_protocol = picotool + +; ============================================================ +; ============================================================ +[env:ESP8266] +platform = espressif8266 +framework = arduino +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = gen4iod +;board = huzzah +;board = oak +;board = esp_wroom_02 +;board = espduino +;board = espectro +;board = espino +;board = espresso_lite_v1 +;board = espresso_lite_v2 +;board = esp12e +;board = esp01_1m +;board = esp01 +;board = esp07 +;board = esp8285 +;board = heltec_wifi_kit_8 +;board = inventone +;board = nodemcu +board = nodemcuv2 +;board = modwifi +;board = phoenix_v1 +;board = phoenix_v2 +;board = sparkfunBlynk +;board = thing +;board = thingdev +;board = esp210 +;board = espinotee +;board = d1 +;board = d1_mini +;board = d1_mini_lite +;board = d1_mini_pro +;board = wifi_slot +;board = wifiduino +;board = wifinfo +;board = wio_link +;board = wio_node +;board = xinabox_cw01 +;board = esp32doit-devkit-v1 + +; ============================================================ +; ============================================================ +[env:ESP32] +platform = espressif32 +framework = arduino +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = esp32cam +;board = alksesp32 +;board = featheresp32 +;board = espea32 +;board = bpi-bit +;board = d-duino-32 +board = esp32doit-devkit-v1 +;board = pocket_32 +;board = fm-devkit +;board = pico32 +;board = esp32-evb +;board = esp32-gateway +;board = esp32-pro +;board = esp32-poe +;board = oroca_edubot +;board = onehorse32dev +;board = lopy +;board = lopy4 +;board = wesp32 +;board = esp32thing +;board = sparkfun_lora_gateway_1-channel +;board = ttgo-lora32-v1 +;board = ttgo-t-beam +;board = turta_iot_node +;board = lolin_d32 +;board = lolin_d32_pro +;board = lolin32 +;board = wemosbat +;board = widora-air +;board = xinabox_cw02 +;board = iotbusio +;board = iotbusproteus +;board = nina_w10 + +; ============================================================ +; ============================================================ +[env:SAMD] +platform = atmelsam +framework = arduino +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ +; ============================================================ +; Board configuration Adafruit SAMD +; ============================================================ + +;board = adafruit_feather_m0 +;board = adafruit_feather_m0_express +;board = adafruit_metro_m0 +;board = adafruit_circuitplayground_m0 +;board = adafruit_gemma_m0 +;board = adafruit_trinket_m0 +;board = adafruit_itsybitsy_m0 +;board = adafruit_pirkey +;board = adafruit_hallowing +;board = adafruit_crickit_m0 +;board = adafruit_metro_m4 +;board = adafruit_grandcentral_m4 +board = adafruit_itsybitsy_m4 +;board = adafruit_feather_m4 +;board = adafruit_trellis_m4 +;board = adafruit_pyportal_m4 +;board = adafruit_pyportal_m4_titano +;board = adafruit_pybadge_m4 +;board = adafruit_metro_m4_airliftlite +;board = adafruit_pygamer_m4 +;board = adafruit_pygamer_advance_m4 +;board = adafruit_pybadge_airlift_m4 +;board = adafruit_monster_m4sk +;board = adafruit_hallowing_m4 + +; ============================================================ +; Board configuration Arduino SAMD and SAM +; ============================================================ + +;board = arduino_zero_edbg +;board = arduino_zero_native +;board = mkr1000 +;board = mkrzero +;board = mkrwifi1010 +;board = nano_33_iot +;board = mkrfox1200 +;board = mkrwan1300 +;board = mkrwan1310 +;board = mkrgsm1400 +;board = mkrnb1500 +;board = mkrvidor4000 +;board = adafruit_circuitplayground_m0 +;board = mzero_pro_bl_dbg +;board = mzero_pro_bl +;board = mzero_bl +;board = tian +;board = tian_cons +;board = arduino_due_x_dbg +;board = arduino_due_x + +; ============================================================ +; Board configuration Seeeduino SAMD +; ============================================================ + +;board = seeed_wio_terminal +;board = Seeed_femto_m0 +;board = seeed_XIAO_m0 +;board = Wio_Lite_MG126 +;board = WioGPS +;board = zero +;board = rolawan +;board = seeed_grove_ui_wireless + +; ============================================================ +; ============================================================ +[env:NRF52] +platform = nordicnrf52 +framework = arduino +; ============================================================ +; Board configuration Adafruit nRF52 +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = feather52832 +board = feather52840 +;board = feather52840sense +;board = itsybitsy52840 +;board = cplaynrf52840 +;board = cluenrf52840 +;board = metro52840 +;board = pca10056 +;board = particle_xenon +;board = mdbt50qrx +;board = ninab302 +;board = ninab112 + +; ============================================================ +; ============================================================ +[env:STM32] +platform = ststm32 +framework = arduino + +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ + +; ============================================================ +; Board configuration Nucleo-144 +; ============================================================ + +;board = nucleo_f207zg +;board = nucleo_f429zi +;board = nucleo_f746zg +;board = nucleo_f756zg +;board = nucleo_f767zi +;board = nucleo_h743zi +;board = nucleo_l496zg +;board = nucleo_l496zg-p +;board = nucleo_l4r5zi +;board = nucleo_l4r5zi-p + +; ============================================================ +; Board configuration Nucleo-64 +; ============================================================ + +;board = nucleo_f030r8 +;board = nucleo_f072rb + +;board = nucleo_f091rc +;board = nucleo_f103rb +;board = nucleo_f302r8 +;board = nucleo_f303re +;board = nucleo_f401re +;board = nucleo_f411re +;board = nucleo_f446re +;board = nucleo_g071rb +;board = nucleo_g431rb +;board = nucleo_g474re +;board = nucleo_l053r8 +;board = nucleo_l073rz +;board = nucleo_l152re +;board = nucleo_l433rc_p +;board = nucleo_l452re +;board = nucleo_l452re-p +;board = nucleo_l476rg +;board = pnucleo_wb55rg + +; ============================================================ +; Board configuration Nucleo-32 +; ============================================================ + +;board = nucleo_f031k6 +;board = nucleo_l031k6 +;board = nucleo_l412kb +;board = nucleo_l432lc +;board = nucleo_f303k8 +;board = nucleo_g431kb + +; ============================================================ +; Board configuration Discovery Boards +; ============================================================ + +;board = disco_f030r8 +;board = disco_f072rb +;board = disco_f030r8 +;board = disco_f100rb +;board = disco_f407vg +;board = disco_f413zh +;board = disco_f746ng +;board = disco_g0316 +;board = disco_l475vg_iot +;board = disco_f072cz-lrwan1 + +; ============================================================ +; Board configuration STM32MP1 Boards +; ============================================================ + +;board = stm32mp157a-dk1 +;board = stm32mp157c-dk2 + +; ============================================================ +; Board configuration Generic Boards +; ============================================================ + +;board = bluepill_f103c6 +;board = bluepill_f103c8 +;board = blackpill_f103c8 +;board = stm32f103cx +;board = stm32f103rx +;board = stm32f103tx +;board = stm32f103vx +;board = stm32f103zx +;board = stm32f103zet6 +;board = maplemini_f103cb +;board = blackpill_f303cc +;board = black_f407ve +;board = black_f407vg +;board = black_f407ze +;board = black_f407zg +;board = blue_f407ve_mini +;board = blackpill_f401cc +;board = blackpill_f411ce +;board = coreboard_f401rc +;board = feather_f405 + +; ============================================================ +; Board configuration Many more Boards to be filled +; ============================================================ + diff --git a/src/ContinuousStepper_Generic.h b/src/ContinuousStepper_Generic.h new file mode 100644 index 0000000..a4a2887 --- /dev/null +++ b/src/ContinuousStepper_Generic.h @@ -0,0 +1,285 @@ +/**************************************************************************************************************************** + ContinuousStepper_Generic.h + For Generic boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K.Hoang 23/01/2023 Initial coding to use PWM to control continuous Stepper Motor +*****************************************************************************************************************************/ + +#pragma once + +#ifndef CONTINUOUS_STEPPER_GENERIC_H +#define CONTINUOUS_STEPPER_GENERIC_H + +#ifndef CONTINUOUS_STEPPER_GENERIC_VERSION + #define CONTINUOUS_STEPPER_GENERIC_VERSION "ContinuousStepper_Generic v1.0.0" + + #define CONTINUOUS_STEPPER_GENERIC_VERSION_MAJOR 1 + #define CONTINUOUS_STEPPER_GENERIC_VERSION_MINOR 0 + #define CONTINUOUS_STEPPER_GENERIC_VERSION_PATCH 0 + + #define CONTINUOUS_STEPPER_GENERIC_VERSION_INT 1000000 +#endif + +#include "PWM_Generic_Debug.h" + +/////////////////////////////// AVR /////////////////////////////// + +#if ( defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || \ + defined(__AVR_ATmega640__) || defined(__AVR_ATmega641__)) + #if defined(CONTINUOUS_STEPPER_USING_ATMEGA2560) + #undef CONTINUOUS_STEPPER_USING_ATMEGA2560 + #endif + #define CONTINUOUS_STEPPER_USING_ATMEGA2560 true + + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Arduino AVR Mega2560/ADK" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Arduino AVR Mega, Mega640(P), Mega2560/ADK. Timer1-5 available + #endif + +#elif ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \ + defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) || defined(ARDUINO_AVR_ETHERNET) || \ + defined(ARDUINO_AVR_FIO) || defined(ARDUINO_AVR_BT) || defined(ARDUINO_AVR_LILYPAD) || defined(ARDUINO_AVR_PRO) || \ + defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) ) + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Arduino AVR UNO, Nano, etc." + + #if(_PWM_LOGLEVEL_>3) + #warning Using Aduino AVR ATMega644(P), ATMega328(P) such as UNO, Nano. Only Timer1,2 available + #endif + +#elif ( defined(ARDUINO_AVR_FEATHER328P) || defined(ARDUINO_AVR_METRO) || defined(ARDUINO_AVR_PROTRINKET5) || defined(ARDUINO_AVR_PROTRINKET3) || \ + defined(ARDUINO_AVR_PROTRINKET5FTDI) || defined(ARDUINO_AVR_PROTRINKET3FTDI) ) + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Adafruit AVR ATMega328(P)" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Adafruit ATMega328(P), such as AVR_FEATHER328P or AVR_METRO. Only Timer1,2 available + #endif + +#elif ( defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_LEONARDO_ETH) || defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_MICRO) || \ + defined(ARDUINO_AVR_ESPLORA) || defined(ARDUINO_AVR_LILYPAD_USB) || defined(ARDUINO_AVR_ROBOT_CONTROL) || defined(ARDUINO_AVR_ROBOT_MOTOR) || \ + defined(ARDUINO_AVR_CIRCUITPLAY) || defined(ARDUINO_AVR_YUNMINI) || defined(ARDUINO_AVR_INDUSTRIAL101) || defined(ARDUINO_AVR_LININO_ONE) ) + #if defined(CONTINUOUS_STEPPER_USING_ATMEGA_32U4) + #undef CONTINUOUS_STEPPER_USING_ATMEGA_32U4 + #endif + #define CONTINUOUS_STEPPER_USING_ATMEGA_32U4 true + + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Arduino AVR ATMega32U4" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Arduino ATMega32U4, such as Leonardo or Leonardo ETH. Only Timer1,3,4 available + #endif + +#elif ( defined(ARDUINO_AVR_FLORA8 ) || defined(ARDUINO_AVR_FEATHER32U4) || defined(ARDUINO_AVR_CIRCUITPLAY) || defined(ARDUINO_AVR_ITSYBITSY32U4_5V) || \ + defined(ARDUINO_AVR_ITSYBITSY32U4_3V) || defined(ARDUINO_AVR_BLUEFRUITMICRO) || defined(ARDUINO_AVR_ADAFRUIT32U4) ) + #if defined(CONTINUOUS_STEPPER_USING_ATMEGA_32U4) + #undef CONTINUOUS_STEPPER_USING_ATMEGA_32U4 + #endif + #define CONTINUOUS_STEPPER_USING_ATMEGA_32U4 true + + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Adafruit AVR ATMega32U4" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Adafruit ATMega32U4, such as Feather_32u4, AVR_CIRCUITPLAY, etc.. Only Timer1,3,4 available + #endif + +#elif ( defined(__AVR_ATmega32U4__) || defined(ARDUINO_AVR_MAKEYMAKEY ) || defined(ARDUINO_AVR_PROMICRO) || defined(ARDUINO_AVR_FIOV3) || \ + defined(ARDUINO_AVR_QDUINOMINI) || defined(ARDUINO_AVR_LILYPAD_ARDUINO_USB_PLUS_BOARD ) ) && !defined(TEENSYDUINO) + #if defined(CONTINUOUS_STEPPER_USING_ATMEGA_32U4) + #undef CONTINUOUS_STEPPER_USING_ATMEGA_32U4 + #endif + #define CONTINUOUS_STEPPER_USING_ATMEGA_32U4 true + + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Generic or Sparkfun AVR ATMega32U4" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Generic ATMega32U4, such as Sparkfun AVR_MAKEYMAKEY, AVR_PROMICRO, etc. Only Timer1,3,4 available + #endif + +#elif ( defined(__AVR_ATmega328P__) || defined(ARDUINO_AVR_DIGITAL_SANDBOX ) || defined(ARDUINO_REDBOT) || defined(ARDUINO_AVR_SERIAL_7_SEGMENT) ) + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Generic or Sparkfun AVR ATMega328P" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Generic ATMega328P, such as Sparkfun AVR_DIGITAL_SANDBOX, REDBOT, etc. + #endif + +#elif ( defined(__AVR_ATmega128RFA1__) || defined(ARDUINO_ATMEGA128RFA1_DEV_BOARD) ) + #define CONTINUOUS_STEPPER_USING_AVR true + + #define BOARD_TYPE "Generic or Sparkfun AVR ATMega128RFA1" + + #if(_PWM_LOGLEVEL_>3) + #warning Using Generic ATMega128RFA1, such as Sparkfun ATMEGA128RFA1_DEV_BOARD, etc. + #endif + +#elif ( defined(ARDUINO_AVR_GEMMA) || defined(ARDUINO_AVR_TRINKET3) || defined(ARDUINO_AVR_TRINKET5) ) + #error These AVR boards are not supported! Please check your Tools->Board setting. + +/////////////////////////////// ESP8266 /////////////////////////////// + +#elif ( defined(ESP8266) || ESP8266 ) + + #define CONTINUOUS_STEPPER_USING_ESP8266 true + #error Not supported yet + +/////////////////////////////// ESP32 /////////////////////////////// + +#elif ( defined(ESP32) || ESP32 ) + + #define CONTINUOUS_STEPPER_USING_ESP32 true + +/////////////////////////////// Nano-33-BLE /////////////////////////////// + +#elif ( ARDUINO_ARCH_NRF52840 && TARGET_NAME == ARDUINO_NANO33BLE ) + #if(_PWM_LOGLEVEL_>3) + #warning Using ARDUINO_NANO33BLE + #endif + + #define CONTINUOUS_STEPPER_USING_NANO33BLE true + +/////////////////////////////// SAMD /////////////////////////////// + +#elif ( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \ + || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \ + || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(__SAMD21G18A__) \ + || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD21E18A__) || defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) \ + || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) || defined(__SAMD21G18A__) ) + + #define CONTINUOUS_STEPPER_USING_SAMD true + +/////////////////////////////// NRF52 /////////////////////////////// + +#elif (defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || \ + defined(MDBT50Q_RX) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + + #define CONTINUOUS_STEPPER_USING_NRF52 true + +/////////////////////////////// SAM DUE /////////////////////////////// + +#elif ( defined(ARDUINO_SAM_DUE) || defined(__SAM3X8E__) ) + + #define CONTINUOUS_STEPPER_USING_SAMDUE true + +/////////////////////////////// TEENSY /////////////////////////////// + +#elif ( defined(CORE_TEENSY) || defined(__IMXRT1062__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) || \ + defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK20DX128__) ) + + #define CONTINUOUS_STEPPER_USING_TEENSY true + +/////////////////////////////// PORTENTA_H7 /////////////////////////////// + +#elif ( ( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) ) && defined(ARDUINO_ARCH_MBED) ) + + #define CONTINUOUS_STEPPER_USING_PORTENTA_H7 true + +/////////////////////////////// STM32 /////////////////////////////// + +#elif ( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \ + defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \ + defined(STM32WB) || defined(STM32MP1) || defined(STM32L5) ) + + #define CONTINUOUS_STEPPER_USING_STM32 true + +/////////////////////////////// megaAVR /////////////////////////////// + +#elif ( defined(__AVR_ATmega4809__) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || \ + defined(ARDUINO_AVR_ATmega4809) || defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \ + defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || defined(ARDUINO_AVR_ATmega1608) || \ + defined(ARDUINO_AVR_ATmega809) || defined(ARDUINO_AVR_ATmega808) ) + + #define CONTINUOUS_STEPPER_USING_MEGA_AVR true + +/////////////////////////////// RP2040 /////////////////////////////// + +#elif ( defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) ) && !defined(ARDUINO_ARCH_MBED) + + #define CONTINUOUS_STEPPER_USING_RPI_PICO true + +/////////////////////////////// MBED_RP2040 /////////////////////////////// + +#elif ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \ + defined(ARDUINO_GENERIC_RP2040) ) && defined(ARDUINO_ARCH_MBED) + + #define CONTINUOUS_STEPPER_USING_MBED_RPI_PICO true + +/////////////////////////////// ATTiny /////////////////////////////// + +#elif defined(MEGATINYCORE) + + #define CONTINUOUS_STEPPER_USING_ATTINY true + +/////////////////////////////// DxCore /////////////////////////////// + +#elif defined(DXCORE) + + #define CONTINUOUS_STEPPER_USING_DX true + +#else + + #error Unsupported Board! Please check your Tools->Board setting. + +#endif + +//////////////////////////////////////////////////// + +#if CONTINUOUS_STEPPER_USING_AVR + #include +#elif CONTINUOUS_STEPPER_USING_ESP8266 + #include +#elif CONTINUOUS_STEPPER_USING_ESP32 + #include +#elif CONTINUOUS_STEPPER_USING_NANO33BLE + #include +#elif CONTINUOUS_STEPPER_USING_SAMD + #include +#elif CONTINUOUS_STEPPER_USING_NRF52 + #include +#elif CONTINUOUS_STEPPER_USING_SAMDUE + #include +#elif CONTINUOUS_STEPPER_USING_TEENSY + #include +#elif CONTINUOUS_STEPPER_USING_PORTENTA_H7 + #include +#elif CONTINUOUS_STEPPER_USING_STM32 + #include +#elif CONTINUOUS_STEPPER_USING_MEGA_AVR + #include +#elif CONTINUOUS_STEPPER_USING_RPI_PICO + #include +#elif CONTINUOUS_STEPPER_USING_MBED_RPI_PICO + #include +#elif CONTINUOUS_STEPPER_USING_DX + #include +#elif CONTINUOUS_STEPPER_USING_ATTINY + #include +#endif + +//////////////////////////////////////////////////// + + +#endif // CONTINUOUS_STEPPER_GENERIC_H + diff --git a/src/PWM_Generic_Debug.h b/src/PWM_Generic_Debug.h new file mode 100644 index 0000000..29ab160 --- /dev/null +++ b/src/PWM_Generic_Debug.h @@ -0,0 +1,96 @@ +/**************************************************************************************************************************** + PWM_Generic_Debug.h + For Generic boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/ContinuousStepper_Generic + Licensed under MIT license + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K.Hoang 23/01/2023 Initial coding to use PWM to control continuous Stepper Motor + *****************************************************************************************************************************/ + +#pragma once + +#ifndef PWM_GENERIC_DEBUG_H +#define PWM_GENERIC_DEBUG_H + +#ifdef PWM_GENERIC_DEBUG_PORT + #define PWM_DBG_PORT PWM_GENERIC_DEBUG_PORT +#else + #define PWM_DBG_PORT Serial +#endif + +// Change _PWM_LOGLEVEL_ to set tracing and logging verbosity +// 0: DISABLED: no logging +// 1: ERROR: errors +// 2: WARN: errors and warnings +// 3: INFO: errors, warnings and informational (default) +// 4: DEBUG: errors, warnings, informational and debug + +#ifndef _PWM_LOGLEVEL_ + #define _PWM_LOGLEVEL_ 1 +#endif + +////////////////////////////////////////// + +const char PWM_MARK[] = "[PWM] "; +const char PWM_SP[] = " "; + +#define PWM_PRINT PWM_DBG_PORT.print +#define PWM_PRINTLN PWM_DBG_PORT.println + +#define PWM_PRINT_MARK PWM_PRINT(PWM_MARK) +#define PWM_PRINT_SP PWM_PRINT(PWM_SP) + +////////////////////////////////////////// + +#define PWM_LOGERROR0(x) if(_PWM_LOGLEVEL_>0) { PWM_PRINT(x); } +#define PWM_LOGERROR(x) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINTLN(x); } +#define PWM_LOGERROR1(x,y) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINTLN(y); } +#define PWM_HEXLOGERROR1(x,y) if(_PWM_LOGLEVEL_>0) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } +#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); } +#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); } +#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); } +#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); } + +////////////////////////////////////////// + +#define PWM_LOGWARN0(x) if(_PWM_LOGLEVEL_>1) { PWM_PRINT(x); } +#define PWM_LOGWARN(x) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINTLN(x); } +#define PWM_LOGWARN1(x,y) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINTLN(y); } +#define PWM_HEXLOGWARN1(x,y) if(_PWM_LOGLEVEL_>1) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } +#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); } +#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); } +#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); } +#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); } + +////////////////////////////////////////// + +#define PWM_LOGINFO0(x) if(_PWM_LOGLEVEL_>2) { PWM_PRINT(x); } +#define PWM_LOGINFO(x) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINTLN(x); } +#define PWM_LOGINFO1(x,y) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINTLN(y); } +#define PWM_HEXLOGINFO1(x,y) if(_PWM_LOGLEVEL_>2) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } +#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); } +#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); } +#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); } +#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); } + +////////////////////////////////////////// + +#define PWM_LOGDEBUG0(x) if(_PWM_LOGLEVEL_>3) { PWM_PRINT(x); } +#define PWM_LOGDEBUG(x) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINTLN(x); } +#define PWM_LOGDEBUG1(x,y) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT_SP; PWM_PRINTLN(y); } +#define PWM_HEXLOGDEBUG1(x,y) if(_PWM_LOGLEVEL_>3) { PWM_PRINT_MARK; PWM_PRINT(x); PWM_PRINT(" 0x"); PWM_PRINTLN(y, HEX); } +#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); } +#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); } +#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); } +#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); } + +////////////////////////////////////////// + + +#endif //PWM_GENERIC_DEBUG_H diff --git a/src/RP2040_PWM.h b/src/RP2040_PWM.h new file mode 100644 index 0000000..81e51e7 --- /dev/null +++ b/src/RP2040_PWM.h @@ -0,0 +1,590 @@ +/**************************************************************************************************************************** + RP2040_PWM.h + For RP2040 boards + Written by Khoi Hoang + + Built by Khoi Hoang https://github.com/khoih-prog/RP2040_PWM + Licensed under MIT license + + Version: 1.4.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K.Hoang 21/09/2021 Initial coding for RP2040 using ArduinoCore-mbed or arduino-pico core + 1.0.1 K.Hoang 24/09/2021 Fix bug generating wrong frequency + 1.0.2 K.Hoang 04/10/2021 Fix bug not changing frequency dynamically + 1.0.3 K.Hoang 05/10/2021 Not reprogram if same PWM frequency. Add PIO strict `lib_compat_mode` + 1.0.4 K Hoang 22/10/2021 Fix platform in library.json for PIO + 1.0.5 K Hoang 06/01/2022 Permit changing dutyCycle and keep same frequency on-the-fly + 1.1.0 K Hoang 24/02/2022 Permit PWM output for both channels of PWM slice. Use float instead of double + 1.1.1 K Hoang 06/03/2022 Fix compiler warnings. Display informational warning when debug level > 3 + 1.2.0 K Hoang 16/04/2022 Add manual setPWM function to use in wafeform creation + 1.3.0 K Hoang 16/04/2022 Add setPWM_Int function for optional uint32_t dutycycle = real_dutycycle * 1000 + 1.3.1 K Hoang 11/09/2022 Add minimal example `PWM_Basic` + 1.4.0 K Hoang 15/10/2022 Fix glitch when changing dutycycle. Adjust MIN_PWM_FREQUENCY/MAX_PWM_FREQUENCY dynamically + 1.4.1 K Hoang 21/01/2023 Add `PWM_StepperControl` example +*****************************************************************************************************************************/ + +#pragma once + +#ifndef RP2040_PWM_H +#define RP2040_PWM_H + +#if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \ + defined(ARDUINO_GENERIC_RP2040) ) && defined(ARDUINO_ARCH_MBED) + #if defined(USING_MBED_RP2040_PWM) + #undef USING_MBED_RP2040_PWM + #endif + #define USING_MBED_RP2040_PWM true + + #if(_PWM_LOGLEVEL_>3) + #warning USING_MBED_RP2040_PWM in RP2040_PWM.h + #endif + +#elif ( defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \ + defined(ARDUINO_ADAFRUIT_ITSYBITSY_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_ADAFRUIT_STEMMAFRIEND_RP2040) || \ + defined(ARDUINO_ADAFRUIT_STEMMAFRIEND_RP2040) || defined(ARDUINO_ADAFRUIT_TRINKEYQT_RP2040) || defined(ARDUINO_ADAFRUIT_MACROPAD_RP2040) || \ + defined(ARDUINO_ADAFRUIT_KB2040_RP2040) || defined(ARDUINO_ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_CYTRON_MAKER_NANO_RP2040) || \ + defined(ARDUINO_CYTRON_MAKER_PI_RP2040) || defined(ARDUINO_SPARKFUN_PROMICRO_RP2040) || defined(ARDUINO_CHALLENGER_2040_WIFI_RP2040) || \ + defined(ARDUINO_CHALLENGER_2040_LTE_RP2040) || defined(ARDUINO_CHALLENGER_NB_2040_WIFI_RP2040) || defined(ARDUINO_ILABS_2040_RPICO32_RP2040) || \ + defined(ARDUINO_MELOPERO_SHAKE_RP2040) || defined(ARDUINO_SOLDERPARTY_RP2040_STAMP) || defined(ARDUINO_UPESY_RP2040_DEVKIT) || \ + defined(ARDUINO_WIZNET_5100S_EVB_PICO) || defined(ARDUINO_GENERIC_RP2040) ) && !defined(ARDUINO_ARCH_MBED) + #if defined(USING_RP2040_PWM) + #undef USING_RP2040_PWM + #endif + #define USING_RP2040_PWM true + + #if(_PWM_LOGLEVEL_>3) + #warning USING_RP2040_PWM in RP2040_PWM.h + #endif +#else + #error This code is intended to run on the RP2040 mbed_nano, mbed_rp2040 or arduino-pico platform! Please check your Tools->Board setting. +#endif + +#ifndef RP2040_PWM_VERSION + #define RP2040_PWM_VERSION "RP2040_PWM v1.4.1" + + #define RP2040_PWM_VERSION_MAJOR 1 + #define RP2040_PWM_VERSION_MINOR 4 + #define RP2040_PWM_VERSION_PATCH 1 + + #define RP2040_PWM_VERSION_INT 1004001 +#endif + +#include +#include +#include "hardware/pwm.h" + +#include "PWM_Generic_Debug.h" + +#define MAX_PWM_FREQUENCY (62500000.0f) + +// For 125MHz CPU. To adjust according to actual CPU Frequency +#define MIN_PWM_FREQUENCY (7.5f) + +// New from v1.1.0 +/////////////////////// + +#if !defined(NUM_PWM_SLICES) + #define NUM_PWM_SLICES 8 +#endif + +typedef struct +{ + float freq; + float channelA_div; + float channelB_div; + bool channelA_Active; + bool channelB_Active; +} PWM_slice; + +static PWM_slice PWM_slice_data[NUM_PWM_SLICES] = +{ + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false }, + { 0, 0, 0, false, false } +}; + +// Not using float for waveform creating +typedef struct +{ + uint16_t channelA_div; + uint16_t channelB_div; + bool channelA_Active; + bool channelB_Active; + bool initialized; +} PWM_slice_manual; + +// Default to 0% PWM +static PWM_slice_manual PWM_slice_manual_data[NUM_PWM_SLICES] = +{ + { 0, 0, false, false, false }, + { 0, 0, false, false, false }, + { 0, 0, false, false, false }, + { 0, 0, false, false, false }, + { 0, 0, false, false, false }, + { 0, 0, false, false, false }, + { 0, 0, false, false, false }, + { 0, 0, false, false, false } +}; +/////////////////////// + +/////////////////////////////////////////////////////////////////// + +class RP2040_PWM +{ + public: + + RP2040_PWM(const uint8_t& pin, const float& frequency, const float& dutycycle, bool phaseCorrect = false) + { +#if defined(F_CPU) + freq_CPU = F_CPU; +#else + freq_CPU = 125000000; +#endif + + _pin = pin; + _frequency = frequency; + _dutycycle = dutycycle * 1000; + + _phaseCorrect = phaseCorrect; + + if (!calc_TOP_and_DIV(frequency)) + { + _frequency = 0; + } + else + { + _frequency = frequency; + } + + _enabled = false; + } + + /////////////////////////////////////////// + + ~RP2040_PWM(); + + /////////////////////////////////////////// + + bool setPWM() + { + return setPWM_Int(_pin, _frequency, _dutycycle, _phaseCorrect); + } + + /////////////////////////////////////////// + + // To be called only after previous complete setPWM_manual with top and div params + // by checking PWM_slice_manual_data[_slice_num].initialized == true; + bool setPWM_manual(const uint8_t& pin, uint16_t& level) + { + _pin = pin; + + // Limit level <= _PWM_config.top + if (level > _PWM_config.top) + level = _PWM_config.top; + + gpio_set_function(_pin, GPIO_FUNC_PWM); + + _slice_num = pwm_gpio_to_slice_num(_pin); + + if (!PWM_slice_manual_data[_slice_num].initialized) + { + PWM_LOGERROR1("Error, not initialized for PWM pin = ", _pin); + + return false; + } + + pwm_set_gpio_level(_pin, level); + + // From v1.1.0 + //////////////////////////////// + + if ( (pwm_gpio_to_channel(_pin)) == PWM_CHAN_A) + { + PWM_slice_manual_data[_slice_num].channelA_div = level; + PWM_slice_manual_data[_slice_num].channelA_Active = true; + + // If B is active, set the data now + if (PWM_slice_manual_data[_slice_num].channelB_Active) + { + pwm_set_chan_level(_slice_num, PWM_CHAN_B, PWM_slice_manual_data[_slice_num].channelB_div); + } + } + else if ( (pwm_gpio_to_channel(_pin)) == PWM_CHAN_B) + { + PWM_slice_manual_data[_slice_num].channelB_div = level; + PWM_slice_manual_data[_slice_num].channelB_Active = true; + + // If A is active, set the data now + if (PWM_slice_manual_data[_slice_num].channelA_Active) + { + pwm_set_chan_level(_slice_num, PWM_CHAN_A, PWM_slice_manual_data[_slice_num].channelA_div); + } + } + else + { + PWM_LOGERROR1("Error, not correct PWM pin = ", _pin); + + return false; + } + + pwm_set_enabled(_slice_num, true); + + PWM_LOGINFO3("pin = ", _pin, ", PWM_CHAN =", pwm_gpio_to_channel(_pin)); + + //////////////////////////////// + + _enabled = true; + + PWM_LOGINFO7("PWM enabled, slice =", _slice_num, ", top =", _PWM_config.top, + ", div =", _PWM_config.div, ", level =", level); + + return true; + } + + /////////////////////////////////////////// + + bool setPWM_manual(const uint8_t& pin, const uint16_t& top, const uint8_t& div, + uint16_t& level, bool phaseCorrect = false) + { + _pin = pin; + + _PWM_config.top = top; + _PWM_config.div = div; + + // Limit level <= top + if (level > top) + level = top; + + gpio_set_function(_pin, GPIO_FUNC_PWM); + + _slice_num = pwm_gpio_to_slice_num(_pin); + + pwm_config config = pwm_get_default_config(); + + // Set phaseCorrect + pwm_set_phase_correct(_slice_num, phaseCorrect); + + pwm_config_set_clkdiv_int(&config, _PWM_config.div); + pwm_config_set_wrap(&config, _PWM_config.top); + + // auto start running once configured + pwm_init(_slice_num, &config, true); + pwm_set_gpio_level(_pin, level); + + // Store and flag so that simpler setPWM_manual() can be called without top and div + PWM_slice_manual_data[_slice_num].initialized = true; + + // From v1.1.0 + //////////////////////////////// + // Update PWM_slice_manual_data[] + + if ( (pwm_gpio_to_channel(_pin)) == PWM_CHAN_A) + { + PWM_slice_manual_data[_slice_num].channelA_div = level; + PWM_slice_manual_data[_slice_num].channelA_Active = true; + + // If B is active, set the data now + if (PWM_slice_manual_data[_slice_num].channelB_Active) + { + pwm_set_chan_level(_slice_num, PWM_CHAN_B, PWM_slice_manual_data[_slice_num].channelB_div); + } + } + else if ( (pwm_gpio_to_channel(_pin)) == PWM_CHAN_B) + { + PWM_slice_manual_data[_slice_num].channelB_div = level; + PWM_slice_manual_data[_slice_num].channelB_Active = true; + + // If A is active, set the data now + if (PWM_slice_manual_data[_slice_num].channelA_Active) + { + pwm_set_chan_level(_slice_num, PWM_CHAN_A, PWM_slice_manual_data[_slice_num].channelA_div); + } + } + else + { + PWM_LOGERROR1("Error, not correct PWM pin = ", _pin); + + return false; + } + + pwm_set_enabled(_slice_num, true); + + PWM_LOGINFO3("pin = ", _pin, ", PWM_CHAN =", pwm_gpio_to_channel(_pin)); + + //////////////////////////////// + + _enabled = true; + + PWM_LOGINFO7("PWM enabled, slice =", _slice_num, ", top =", _PWM_config.top, + ", div =", _PWM_config.div, ", level =", level); + + return true; + } + + /////////////////////////////////////////// + +// dutycycle from 0-100,000 for 0%-100% to make use of 16-bit top register + // dutycycle = real_dutycycle * 1000 for better accuracy + bool setPWM_Int(const uint8_t& pin, const float& frequency, const uint32_t& dutycycle, bool phaseCorrect = false) + { + bool newFreq = false; + bool newDutyCycle = false; + + if ( (frequency <= ( (float) MAX_PWM_FREQUENCY * freq_CPU / 125000000)) + && (frequency >= ( (float) MIN_PWM_FREQUENCY * freq_CPU / 125000000) ) ) + { + _pin = pin; + + if (_frequency != frequency) + { + if (!calc_TOP_and_DIV(frequency)) + { + _frequency = 0; + } + else + { + _frequency = frequency; + _dutycycle = dutycycle; + + newFreq = true; + + PWM_LOGINFO3("Changing PWM frequency to", frequency, "and dutyCycle =", (float) _dutycycle / 1000); + } + } + else if (_enabled) + { + if (_dutycycle != dutycycle) + { + _dutycycle = dutycycle; + newDutyCycle = true; + + PWM_LOGINFO3("Changing PWM DutyCycle to", (float) _dutycycle / 1000, "and keeping frequency =", _frequency); + + } + else + { + PWM_LOGINFO3("No change, same PWM frequency =", frequency, "and dutyCycle =", (float) _dutycycle / 1000); + } + } + + if ( (!_enabled) || newFreq || newDutyCycle ) + { + gpio_set_function(_pin, GPIO_FUNC_PWM); + + _slice_num = pwm_gpio_to_slice_num(_pin); + + pwm_config config = pwm_get_default_config(); + + // Set phaseCorrect + pwm_set_phase_correct(_slice_num, phaseCorrect); + + pwm_config_set_clkdiv_int(&config, _PWM_config.div); + pwm_config_set_wrap(&config, _PWM_config.top); + + if ( newDutyCycle ) + { + // KH, to fix glitch when changing dutycycle from v1.4.0 + // Check https://github.com/khoih-prog/RP2040_PWM/issues/10 + // From pico-sdk/src/rp2_common/hardware_pwm/include/hardware/pwm.h + // Only take effect after the next time the PWM slice wraps + // (or, in phase-correct mode, the next time the slice reaches 0). + // If the PWM is not running, the write is latched in immediately + //pwm_set_wrap(uint slice_num, uint16_t wrap) + pwm_set_wrap(_slice_num, _PWM_config.top); + } + else + { + // auto start running once configured + pwm_init(_slice_num, &config, true); + } + + // To avoid uint32_t overflow and still keep accuracy as _dutycycle max = 100,000 > 65536 of uint16_t + pwm_set_gpio_level(_pin, ( _PWM_config.top * (_dutycycle / 2) ) / 50000 ); + + // From v1.1.0 + //////////////////////////////// + // Update PWM_slice_data[] + PWM_slice_data[_slice_num].freq = _frequency; + + if ( (pwm_gpio_to_channel(_pin)) == PWM_CHAN_A) + { + PWM_slice_data[_slice_num].channelA_div = ( _PWM_config.top * (_dutycycle / 2) ) / 50000; + PWM_slice_data[_slice_num].channelA_Active = true; + + // If B is active, set the data now + if (PWM_slice_data[_slice_num].channelB_Active) + { + pwm_set_chan_level(_slice_num, PWM_CHAN_B, PWM_slice_data[_slice_num].channelB_div); + } + } + else if ( (pwm_gpio_to_channel(_pin)) == PWM_CHAN_B) + { + PWM_slice_data[_slice_num].channelB_div = ( _PWM_config.top * (_dutycycle / 2) ) / 50000; + PWM_slice_data[_slice_num].channelB_Active = true; + + // If A is active, set the data now + if (PWM_slice_data[_slice_num].channelA_Active) + { + pwm_set_chan_level(_slice_num, PWM_CHAN_A, PWM_slice_data[_slice_num].channelA_div); + } + } + else + { + PWM_LOGERROR1("Error, not correct PWM pin = ", _pin); + + return false; + } + + pwm_set_enabled(_slice_num, true); + + PWM_LOGINFO3("pin = ", _pin, ", PWM_CHAN =", pwm_gpio_to_channel(_pin)); + + //////////////////////////////// + + _enabled = true; + + PWM_LOGINFO3("PWM enabled, slice = ", _slice_num, ", _frequency = ", _frequency); + } + + return true; + } + else + return false; + } + + /////////////////////////////////////////// + + bool setPWM(const uint8_t& pin, const float& frequency, const float& dutycycle, bool phaseCorrect = false) + { + return setPWM_Int(pin, frequency, dutycycle * 1000, phaseCorrect); + } + + /////////////////////////////////////////// + + bool setPWM_Period(const uint8_t& pin, const float& period_us, const float& dutycycle, bool phaseCorrect = false) + { + return setPWM_Int(pin, 1000000.0f / period_us, dutycycle * 1000, phaseCorrect); + } + + /////////////////////////////////////////// + + void enablePWM() + { + pwm_set_enabled(_slice_num, true); + _enabled = true; + } + + /////////////////////////////////////////// + + void disablePWM() + { + pwm_set_enabled(_slice_num, false); + _enabled = false; + } + + /////////////////////////////////////////// + + inline uint32_t get_TOP() + { + return _PWM_config.top; + } + + /////////////////////////////////////////// + + inline uint32_t get_DIV() + { + return _PWM_config.div; + } + + /////////////////////////////////////////// + + inline float getActualFreq() + { + return _actualFrequency; + } + + /////////////////////////////////////////// + + inline uint32_t get_freq_CPU() + { + return freq_CPU; + } + + /////////////////////////////////////////////////////////////////// + + private: + + pwm_config _PWM_config; + uint32_t freq_CPU; + + float _actualFrequency; + float _frequency; + + // dutycycle from 0-100,000 for 0%-100% to make use of 16-bit top register + // dutycycle = real_dutycycle * 1000 for better accuracy + uint32_t _dutycycle; + ////////// + + uint8_t _pin; + uint8_t _slice_num; + bool _phaseCorrect; + bool _enabled; + + /////////////////////////////////////////// + + // https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf, page 549 + // https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__pwm.html + + /////////////////////////////////////////// + + bool calc_TOP_and_DIV(const float& freq) + { + if (freq > 2000.0) + { + _PWM_config.div = 1; + } + else if (freq >= 200.0) + { + _PWM_config.div = 10; + } + else if (freq >= 20.0) + { + _PWM_config.div = 100; + } + else if (freq >= 10.0) + { + _PWM_config.div = 200; + } + else if (freq >= ( (float) MIN_PWM_FREQUENCY * freq_CPU / 125000000)) + { + _PWM_config.div = 255; + } + else + { + PWM_LOGERROR1("Error, freq must be >=", ( (float) MIN_PWM_FREQUENCY * freq_CPU / 125000000)); + + return false; + } + + // Formula => PWM_Freq = ( F_CPU ) / [ ( TOP + 1 ) * ( DIV + DIV_FRAC/16) ] + _PWM_config.top = ( freq_CPU / freq / _PWM_config.div ) - 1; + + _actualFrequency = ( freq_CPU ) / ( (_PWM_config.top + 1) * _PWM_config.div ); + + PWM_LOGINFO3("_PWM_config.top =", _PWM_config.top, ", _actualFrequency =", _actualFrequency); + + return true; + } +}; + +/////////////////////////////////////////// + +#endif // RP2040_PWM_H + diff --git a/utils/astyle_library.conf b/utils/astyle_library.conf new file mode 100644 index 0000000..8a73bc2 --- /dev/null +++ b/utils/astyle_library.conf @@ -0,0 +1,70 @@ +# Code formatting rules for Arduino libraries, modified from for KH libraries: +# +# https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf +# + +# astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino + +--mode=c +--lineend=linux +--style=allman + +# -r or -R +#--recursive + +# -c => Converts tabs into spaces +convert-tabs + +# -s2 => 2 spaces indentation +--indent=spaces=2 + +# -t2 => tab =2 spaces +#--indent=tab=2 + +# -C +--indent-classes + +# -S +--indent-switches + +# -xW +--indent-preproc-block + +# -Y => indent classes, switches (and cases), comments starting at column 1 +--indent-col1-comments + +# -M120 => maximum of 120 spaces to indent a continuation line +--max-continuation-indent=120 + +# -xC120 => max‑code‑length will break a line if the code exceeds # characters +--max-code-length=120 + +# -f => +--break-blocks + +# -p => put a space around operators +--pad-oper + +# -xg => Insert space padding after commas +--pad-comma + +# -H => put a space after if/for/while +pad-header + +# -xb => Break one line headers (e.g. if/for/while) +--break-one-line-headers + +# -c => Converts tabs into spaces +#--convert-tabs + +# if you like one-liners, keep them +#keep-one-line-statements + +# -xV +--attach-closing-while + +#unpad-paren + +# -xp +remove-comment-prefix + diff --git a/utils/restyle.sh b/utils/restyle.sh new file mode 100644 index 0000000..bcd846f --- /dev/null +++ b/utils/restyle.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for dir in . ; do + find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \; +done +