Skip to content
This repository has been archived by the owner on Feb 4, 2023. It is now read-only.
/ Teensy_PWM Public archive

This library enables you to use Hardware-based PWM channels on Teensy boards, such as Teensy 2.x, Teensy LC, Teensy 3.x, Teensy 4.x, Teensy MicroMod, etc., to create and output PWM to pins. Using the same functions as other FastPWM libraries to enable you to port PWM code easily between platforms.

License

Notifications You must be signed in to change notification settings

khoih-prog/Teensy_PWM

Repository files navigation

Teensy_PWM Library

arduino-library-badge GitHub release GitHub contributions welcome GitHub issues

Donate to my libraries using BuyMeACoffee



Table of Contents



Why do we need this Teensy_PWM library

Features

This hardware-based PWM library, a wrapper and enhancement around Teensy PWM code, enables you to use Hardware-PWM on Teensy boards, such as Teensy 2.x, Teensy LC, Teensy 3.x, Teensy 4.x, Teensy MicroMod, etc., etc. using Teensyduno core, to create and output PWM. These purely hardware-based PWM channels can generate very high PWM frequencies, depending on CPU clock and acceptable accuracy. The maximum and default resolution is 16-bit resolution.

This library is using the same or similar functions as other FastPWM libraries, as follows, to enable you to port your PWM code easily between platforms

  1. RP2040_PWM
  2. AVR_PWM
  3. megaAVR_PWM
  4. ESP32_FastPWM
  5. SAMD_PWM
  6. SAMDUE_PWM
  7. nRF52_PWM
  8. Teensy_PWM
  9. ATtiny_PWM
  10. Dx_PWM
  11. Portenta_H7_PWM
  12. MBED_RP2040_PWM
  13. nRF52_MBED_PWM
  14. 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.

New efficient setPWM_manual() function enables waveform creation using PWM.

The PWM_Multi example will demonstrate the usage of multichannel PWM using multiple Hardware-PWM blocks (Timer & Channel). The 4 independent Hardware-PWM channels are used to control 4 different PWM outputs, with totally independent frequencies and dutycycles on Teensy.

Being hardware-based PWM, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet or Blynk services.

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 hardware-based PWM.

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().

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

  1. Teensy boards such as :
  • Teensy 4.1, Teensy MicroMod, Teensy 4.0
  • Teensy 3.6, 3.5, 3.2/3.1, 3.0
  • Teensy LC

To be supported Boards

  • Teensy++ 2.0 and Teensy 2.0


Prerequisites

  1. Arduino IDE 1.8.19+ for Arduino. GitHub release
  2. Teensy core v1.57+ for Teensy 4.1. GitHub release


Installation

Use Arduino Library Manager

The best and easiest way is to use Arduino Library Manager. Search for Teensy_PWM, then select / install the latest version. You can also use this link arduino-library-badge for more detailed instructions.

Manual Install

Another way to install is to:

  1. Navigate to Teensy_PWM page.
  2. Download the latest release Teensy_PWM-main.zip.
  3. Extract the zip file to Teensy_PWM-main directory
  4. Copy whole Teensy_PWM-main folder to Arduino libraries' directory such as ~/Arduino/libraries/.

VS Code & PlatformIO

  1. Install VS Code
  2. Install PlatformIO
  3. Install Teensy_PWM library by using Library Manager. Search for Teensy_PWM in Platform.io Author's Libraries
  4. Use included 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


Packages' Patches

1. For Teensy boards

To be able to compile and run on Teensy boards, you have to copy the file Teensy boards.txt into Teensy hardware directory (./arduino-1.8.19/hardware/teensy/avr/boards.txt).

Supposing the Arduino version is 1.8.19. These files must be copied into the directory:

  • ./arduino-1.8.19/hardware/teensy/avr/boards.txt
  • ./arduino-1.8.19/hardware/teensy/avr/cores/teensy/Stream.h
  • ./arduino-1.8.19/hardware/teensy/avr/cores/teensy3/Stream.h
  • ./arduino-1.8.19/hardware/teensy/avr/cores/teensy4/Stream.h

Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

  • ./arduino-x.yy.zz/hardware/teensy/avr/boards.txt
  • ./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy/Stream.h
  • ./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy3/Stream.h
  • ./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy4/Stream.h


Usage

Before using any PWM Timer and channel, you have to make sure the Timer and channel has not been used by any other purpose.

1. Create PWM Instance with Pin, Frequency, dutycycle

Teensy_PWM* PWM_Instance;

PWM_Instance = new Teensy_PWM(pinToUse, frequency, dutyCycle, channel, PWM_resolution);

2. Initialize PWM Instance

if (PWM_Instance)
{
  PWM_Instance->setPWM();
}

3. Set or change PWM frequency or dutyCycle

To use float new_dutyCycle

PWM_Instance->setPWM(PWM_Pins, new_frequency, new_dutyCycle);

such as

dutyCycle = 10.0f;
  
Serial.print(F("Change PWM DutyCycle to ")); Serial.println(dutyCycle);
PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

To use uint32_t new_dutyCycle = (real_dutyCycle * 65536) / 100

PWM_Instance->setPWM_Int(PWM_Pins, new_frequency, new_dutyCycle);

such as for real_dutyCycle = 50%

// 50% dutyCycle = (real_dutyCycle * 65536) / 100
dutyCycle = 32768;

Serial.print(F("Change PWM DutyCycle to (%) "));
Serial.println((float) dutyCycle * 100 / 65536);
PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);

for real_dutyCycle = 50%

// 20% dutyCycle = (real_dutyCycle * 65536) / 100
dutyCycle = 13107;

Serial.print(F("Change PWM DutyCycle to (%) "));
Serial.println((float) dutyCycle * 100 / 65536);
PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);

4. Set or change PWM frequency and dutyCycle manually and efficiently in waveform creation

Function prototype

bool setPWM_manual(const uint8_t& pin, const uint16_t& DCValue);

Need to call only once for each pin

PWM_Instance->setPWM(PWM_Pins, frequency, dutyCycle);

after that, if just changing dutyCycle / level, use

PWM_Instance->setPWM_manual(PWM_Pins, new_level);


Examples:

  1. PWM_Basic
  2. PWM_DynamicDutyCycle
  3. PWM_DynamicDutyCycle_Int
  4. PWM_DynamicFreq
  5. PWM_Multi
  6. PWM_MultiChannel
  7. PWM_Waveform
  8. PWM_StepperControl


Example PWM_Multi

#define _PWM_LOGLEVEL_ 4
#include "Teensy_PWM.h"
#define USING_FLEX_TIMERS true
// To select correct pins from different timers for different frequencies
// For example, pin 7/FlexPWM1_3_B and pin8/FlexPWM1_3_A will have same frequency, etc.
// For the whole list, check Teensy_PWM.h or README.md
#if USING_FLEX_TIMERS
// Using FlexTimers
uint32_t PWM_Pins[] = { 4, 5, 6, 7 };
#else
// Using QuadTimers
uint32_t PWM_Pins[] = { 10, 11, 14, 15 };
#endif
float frequency[] = { 2000.0f, 3000.0f, 4000.0f, 8000.0f };
float dutyCycle[] = { 10.0f, 30.0f, 50.0f, 90.0f };
#define NUM_OF_PINS ( sizeof(PWM_Pins) / sizeof(uint32_t) )
Teensy_PWM* PWM_Instance[NUM_OF_PINS];
char dashLine[] = "=====================================================================================";
void printPWMInfo(Teensy_PWM* PWM_Instance)
{
Serial.println(dashLine);
Serial.print("Actual data: pin = ");
Serial.print(PWM_Instance->getPin());
Serial.print(", PWM DC = ");
Serial.print(PWM_Instance->getActualDutyCycle());
Serial.print(", PWMPeriod = ");
Serial.print(PWM_Instance->getPWMPeriod());
Serial.print(", PWM Freq (Hz) = ");
Serial.println(PWM_Instance->getActualFreq(), 4);
Serial.println(dashLine);
}
void setup()
{
Serial.begin(115200);
while (!Serial && millis() < 5000);
delay(500);
#if USING_FLEX_TIMERS
Serial.print(F("\nStarting PWM_Multi using FlexTimers on "));
#else
Serial.print(F("\nStarting PWM_Multi using QuadTimers on "));
#endif
Serial.println(BOARD_NAME);
Serial.println(TEENSY_PWM_VERSION);
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
PWM_Instance[index] = new Teensy_PWM(PWM_Pins[index], frequency[index], dutyCycle[index]);
if (PWM_Instance[index])
{
PWM_Instance[index]->setPWM();
}
}
Serial.println(dashLine);
Serial.println("Index\tPin\tPWM_freq\tDutyCycle\tActual Freq");
Serial.println(dashLine);
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
if (PWM_Instance[index])
{
Serial.print(index);
Serial.print("\t");
Serial.print(PWM_Pins[index]);
Serial.print("\t");
Serial.print(frequency[index]);
Serial.print("\t\t");
Serial.print(dutyCycle[index]);
Serial.print("\t\t");
Serial.println(PWM_Instance[index]->getActualFreq(), 4);
}
else
{
Serial.println();
}
}
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
printPWMInfo(PWM_Instance[index]);
}
}
void loop()
{
//Long delay has no effect on the operation of hardware-based PWM channels
delay(1000000);
}



Debug Terminal Output Samples

1. PWM_DynamicDutyCycle using FlexTimers on Teensy 4.0

The following is the sample terminal output when running example PWM_DynamicDutyCycle using FlexTimers on Teensy 4.0, to demonstrate the ability to provide high PWM frequencies and ability to change DutyCycle on-the-fly

Starting PWM_DynamicDutyCycle using FlexTimers on Teensy 4.0
Teensy_PWM v1.1.1
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
[PWM] setupPWM: Using FlexTimer2 moduleIndex = 1 for PWM pin = 5
=====================================================================================
Change PWM DutyCycle to 90.00
[PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
[PWM] setPWM_Int: dutycycle = 58982 , frequency = 5000.00
[PWM] setupPWM: Mapping dutycycle = 58982 to newDC = 58982 for _resolution = 16
=====================================================================================
Actual data: pin = 5, PWM DC = 90.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
=====================================================================================
Change PWM DutyCycle to 20.00
[PWM] setPWM: _dutycycle = 13107 , frequency = 5000.00
[PWM] setPWM_Int: dutycycle = 13107 , frequency = 5000.00
[PWM] setupPWM: Mapping dutycycle = 13107 to newDC = 13107 for _resolution = 16
=====================================================================================
Actual data: pin = 5, PWM DC = 20.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
=====================================================================================
Change PWM DutyCycle to 90.00
[PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
[PWM] setPWM_Int: dutycycle = 58982 , frequency = 5000.00
[PWM] setupPWM: Mapping dutycycle = 58982 to newDC = 58982 for _resolution = 16
=====================================================================================
Actual data: pin = 5, PWM DC = 90.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
=====================================================================================
Change PWM DutyCycle to 20.00
[PWM] setPWM: _dutycycle = 13107 , frequency = 5000.00
[PWM] setPWM_Int: dutycycle = 13107 , frequency = 5000.00
[PWM] setupPWM: Mapping dutycycle = 13107 to newDC = 13107 for _resolution = 16
=====================================================================================
Actual data: pin = 5, PWM DC = 20.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
=====================================================================================

2. PWM_Multi using QuadTimers on Teensy 4.0

The following is the sample terminal output when running example PWM_Multi using QuadTimers on Teensy 4.0, to demonstrate the ability to provide high PWM frequencies on multiple PWM-capable pins

Starting PWM_Multi using QuadTimers on Teensy 4.0
Teensy_PWM v1.1.1
[PWM] setupPWM: Mapping dutycycle = 6554 to newDC = 6554 for _resolution = 16
[PWM] setupPWM: Using QuadTimer1 moduleIndex = 0 for PWM pin = 10
[PWM] setPWM_Int: dutycycle = 6554 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 6554 to newDC = 6554 for _resolution = 16
[PWM] setupPWM: Mapping dutycycle = 19661 to newDC = 19661 for _resolution = 16
[PWM] setupPWM: Using QuadTimer1 moduleIndex = 2 for PWM pin = 11
[PWM] setPWM_Int: dutycycle = 19661 , frequency = 3000.00
[PWM] setupPWM: Mapping dutycycle = 19661 to newDC = 19661 for _resolution = 16
[PWM] setupPWM: Mapping dutycycle = 32768 to newDC = 32768 for _resolution = 16
[PWM] setupPWM: Using QuadTimer3 moduleIndex = 2 for PWM pin = 14
[PWM] setPWM_Int: dutycycle = 32768 , frequency = 4000.00
[PWM] setupPWM: Mapping dutycycle = 32768 to newDC = 32768 for _resolution = 16
[PWM] setupPWM: Mapping dutycycle = 58982 to newDC = 58982 for _resolution = 16
[PWM] setupPWM: Using QuadTimer3 moduleIndex = 3 for PWM pin = 15
[PWM] setPWM_Int: dutycycle = 58982 , frequency = 8000.00
[PWM] setupPWM: Mapping dutycycle = 58982 to newDC = 58982 for _resolution = 16
=====================================================================================
Index	Pin	PWM_freq	DutyCycle	Actual Freq
=====================================================================================
0	10	2000.00		10.00		2000.0000
1	11	3000.00		30.00		3000.0000
2	14	4000.00		50.00		4000.0000
3	15	8000.00		90.00		8000.0000
=====================================================================================
Actual data: pin = 10, PWM DC = 10.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
=====================================================================================
=====================================================================================
Actual data: pin = 11, PWM DC = 30.00, PWMPeriod = 333.33, PWM Freq (Hz) = 3000.0000
=====================================================================================
=====================================================================================
Actual data: pin = 14, PWM DC = 50.00, PWMPeriod = 250.00, PWM Freq (Hz) = 4000.0000
=====================================================================================
=====================================================================================
Actual data: pin = 15, PWM DC = 90.00, PWMPeriod = 125.00, PWM Freq (Hz) = 8000.0000
=====================================================================================

3. PWM_DynamicFreq using FlexTimers on Teensy 4.0

The following is the sample terminal output when running example PWM_DynamicFreq using FlexTimers on Teensy 4.0, to demonstrate the ability to change dynamically PWM frequencies

Starting PWM_DynamicFreq using FlexTimers on Teensy 4.0
Teensy_PWM v1.1.1
[PWM] setupPWM: Mapping dutycycle = 32768 to newDC = 32768 for _resolution = 16
[PWM] setupPWM: Using FlexTimer2 moduleIndex = 1 for PWM pin = 5
=====================================================================================
Change PWM Freq to 20000.00
[PWM] setPWM: _dutycycle = 32768 , frequency = 20000.00
[PWM] setPWM_Int: dutycycle = 32768 , frequency = 20000.00
[PWM] setupPWM: Mapping dutycycle = 32768 to newDC = 32768 for _resolution = 16
=====================================================================================
Actual data: pin = 5, PWM DC = 50.00, PWMPeriod = 50.00, PWM Freq (Hz) = 20000.0000
=====================================================================================
Change PWM Freq to 10000.00
[PWM] setPWM: _dutycycle = 32768 , frequency = 10000.00
[PWM] setPWM_Int: dutycycle = 32768 , frequency = 10000.00
[PWM] setupPWM: Mapping dutycycle = 32768 to newDC = 32768 for _resolution = 16
=====================================================================================
Actual data: pin = 5, PWM DC = 50.00, PWMPeriod = 100.00, PWM Freq (Hz) = 10000.0000
=====================================================================================

4. PWM_Waveform using FlexTimers on Teensy 4.0

The following is the sample terminal output when running example PWM_Waveform using FlexTimers on Teensy 4.0, to demonstrate how to use the setPWM_manual() function in wafeform creation

Starting PWM_Waveform using FlexTimers on Teensy 4.0
Teensy_PWM v1.1.1
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
[PWM] setupPWM: Using FlexTimer2 moduleIndex = 1 for PWM pin = 5
[PWM] setPWM: _dutycycle = 0 , frequency = 2000.00
[PWM] setPWM_Int: dutycycle = 0 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
============================================================================================
Actual data: pin = 5, PWM DutyCycle = 0.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
============================================================================================
[PWM] setPWM_manual: _dutycycle = 0 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 3276 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 3276 to newDC = 3276 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 6553 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 6553 to newDC = 6553 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 9830 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 9830 to newDC = 9830 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 13107 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 13107 to newDC = 13107 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 16383 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 16383 to newDC = 16383 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 19660 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 19660 to newDC = 19660 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 22937 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 22937 to newDC = 22937 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 26214 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 26214 to newDC = 26214 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 29490 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 29490 to newDC = 29490 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 32767 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 32767 to newDC = 32767 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 36044 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 36044 to newDC = 36044 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 39321 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 39321 to newDC = 39321 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 42597 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 42597 to newDC = 42597 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 45874 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 45874 to newDC = 45874 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 49151 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 49151 to newDC = 49151 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 52428 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 52428 to newDC = 52428 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 55704 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 55704 to newDC = 55704 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 58981 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 58981 to newDC = 58981 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 62258 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 62258 to newDC = 62258 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 65535 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 65535 to newDC = 65535 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 62258 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 62258 to newDC = 62258 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 58981 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 58981 to newDC = 58981 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 55704 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 55704 to newDC = 55704 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 52428 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 52428 to newDC = 52428 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 49151 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 49151 to newDC = 49151 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 45874 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 45874 to newDC = 45874 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 42597 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 42597 to newDC = 42597 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 39321 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 39321 to newDC = 39321 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 36044 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 36044 to newDC = 36044 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 32767 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 32767 to newDC = 32767 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 29490 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 29490 to newDC = 29490 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 26214 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 26214 to newDC = 26214 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 22937 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 22937 to newDC = 22937 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 19660 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 19660 to newDC = 19660 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 16383 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 16383 to newDC = 16383 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 13107 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 13107 to newDC = 13107 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 9830 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 9830 to newDC = 9830 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 6553 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 6553 to newDC = 6553 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 3276 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 3276 to newDC = 3276 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 0 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16

5. PWM_Waveform using QuadTimers on Teensy 4.0

The following is the sample terminal output when running example PWM_Waveform using QuadTimers on Teensy 4.0, to demonstrate how to use the setPWM_manual() function in wafeform creation

Starting PWM_Waveform using QuadTimers on Teensy 4.0
Teensy_PWM v1.1.1
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
[PWM] setupPWM: Using QuadTimer3 moduleIndex = 3 for PWM pin = 15
[PWM] setPWM: _dutycycle = 0 , frequency = 2000.00
[PWM] setPWM_Int: dutycycle = 0 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
============================================================================================
Actual data: pin = 15, PWM DutyCycle = 0.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
============================================================================================
[PWM] setPWM_manual: _dutycycle = 0 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 3276 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 3276 to newDC = 3276 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 6553 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 6553 to newDC = 6553 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 9830 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 9830 to newDC = 9830 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 13107 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 13107 to newDC = 13107 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 16383 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 16383 to newDC = 16383 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 19660 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 19660 to newDC = 19660 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 22937 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 22937 to newDC = 22937 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 26214 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 26214 to newDC = 26214 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 29490 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 29490 to newDC = 29490 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 32767 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 32767 to newDC = 32767 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 36044 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 36044 to newDC = 36044 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 39321 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 39321 to newDC = 39321 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 42597 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 42597 to newDC = 42597 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 45874 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 45874 to newDC = 45874 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 49151 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 49151 to newDC = 49151 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 52428 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 52428 to newDC = 52428 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 55704 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 55704 to newDC = 55704 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 58981 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 58981 to newDC = 58981 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 62258 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 62258 to newDC = 62258 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 65535 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 65535 to newDC = 65535 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 62258 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 62258 to newDC = 62258 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 58981 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 58981 to newDC = 58981 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 55704 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 55704 to newDC = 55704 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 52428 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 52428 to newDC = 52428 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 49151 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 49151 to newDC = 49151 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 45874 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 45874 to newDC = 45874 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 42597 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 42597 to newDC = 42597 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 39321 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 39321 to newDC = 39321 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 36044 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 36044 to newDC = 36044 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 32767 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 32767 to newDC = 32767 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 29490 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 29490 to newDC = 29490 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 26214 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 26214 to newDC = 26214 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 22937 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 22937 to newDC = 22937 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 19660 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 19660 to newDC = 19660 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 16383 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 16383 to newDC = 16383 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 13107 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 13107 to newDC = 13107 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 9830 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 9830 to newDC = 9830 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 6553 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 6553 to newDC = 6553 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 3276 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 3276 to newDC = 3276 for _resolution = 16
[PWM] setPWM_manual: _dutycycle = 0 , frequency = 2000.00
[PWM] setupPWM: Mapping dutycycle = 0 to newDC = 0 for _resolution = 16


Debug

Debug is enabled by default on Serial.

You can also change the debugging level _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_     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: Teensy_PWM issues



TO DO

  1. Search for bug and improvement.
  2. Support to Teensy 2.x

DONE

  1. Basic hardware PWM-channels for Teensy 4.x boards, such as Teensy 4.0, Teensy 4.1, Teensy MicroMod, etc., using Teensyduno core.
  2. Add support to Teensy 3.x and Teensy LC
  3. Add example PWM_StepperControl to demo how to control Stepper Motor using PWM


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 for proposing new way to use PWM to drive Stepper-Motor in Using PWM to step a stepper driver #16, leading to v2.0.3
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

Copyright

Copyright (c) 2022- Khoi Hoang