This PWM-wrapper library enables you to use Hardware-PWM blocks on RP2040-based boards to create and output PWM any GPIO pin. These purely hardware-based PWM channels can generate from very low (lowest is *7.5Hz (F_CPU/125)) to very high PWM frequencies (in the MHz range, up to (F_CPU/2) or 62.5MHz**).
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
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.
The PWM_Multi example will demonstrate the usage of multichannel PWM using multiple Hardware-PWM blocks (slices). The 8 independent Hardware-PWM slices are used to control 8 different PWM outputs, with totally independent frequencies and dutycycles.
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.
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
This non-being-blocked important feature is absolutely necessary for mission-critical tasks.
You'll see software-based
SimpleTimer is blocked while system is connecting to WiFi / Internet / Blynk, as well as by blocking task
in loop()
, using delay()
function as an example. The elapsed time then is very unaccurate
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.
Arduino IDE 1.8.19+
for Arduino. Using Arduino IDE 2.0.0+
at your own risk.ArduinoCore-mbed mbed_nano or mbed_rp2040 core 3.5.4+
for Arduino NANO_RP2040_CONNECT, RASPBERRY_PI_PICO boards. Earle Philhower's arduino-pico core v2.7.1+
for RP2040-based boards such as RASPBERRY_PI_PICO, RASPBERRY_PI_PICO_W, ADAFRUIT_FEATHER_RP2040, ADAFRUIT_ITSYBITSY_RP2040, CYTRON_MAKER_NANO_RP2040, SPARKFUN_PROMICRO_RP2040, CHALLENGER_2040_WIFI_RP2040, ILABS_2040_RPICO32_RP2040, MELOPERO_SHAKE_RP2040, SOLDERPARTY_RP2040_STAMP, UPESY_RP2040_DEVKIT, WIZNET_5100S_EVB_PICO, GENERIC_RP2040, etc. The best and easiest way is to use Arduino Library Manager
. Search for RP2040_PWM, then select / install the latest version.
You can also use this link for more detailed instructions.
Another way to install is to:
RP2040_PWM-main.zip
.RP2040_PWM-main
directory RP2040_PWM-main
folder to Arduino libraries' directory such as ~/Arduino/libraries/
.From rp2040-datasheet.pdf, page 543
Pulse width modulation (PWM) is a scheme where a digital signal provides a smoothly varying average voltage. This is achieved with positive pulses of some controlled width, at regular intervals. The fraction of time spent high is known as the duty cycle. This may be used to approximate an analog output, or control switchmode power electronics.
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.
Each PWM slice is equipped with the following:
Slices can be enabled or disabled simultaneously via a single, global control register. The slices then run in perfect lockstep, so that more complex power circuitry can be switched by the outputs of multiple slices.
All 30 GPIO pins on RP2040 can be used for PWM:
2-channel slices
) appear on GPIO0
to GPIO15
, in the order PWM0_A
, PWM0_B
, PWM1_A
, etc.GPIO16
to GPIO29
. GPIO16
is PWM0 A
, GPIO17
is PWM0 B
, so on, up to PWM6 B
on GPIO29
Before using any PWM slice
, you have to make sure the slice
has not been used by any other purpose.
RP2040_PWM* PWM_Instance;
PWM_Instance = new RP2040_PWM(PWM_Pins, freq, dutyCycle);
if (PWM_Instance)
{
PWM_Instance->setPWM();
}
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 * 1000
PWM_Instance->setPWM_Int(PWM_Pins, new_frequency, new_dutyCycle);
such as for real_dutyCycle = 20%
// dutyCycle = real_dutyCycle * 1000
dutyCycle = 20000;
Serial.print(F("Change PWM DutyCycle to ")); Serial.println((float) dutyCycle / 1000);
PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);
Need to call only once for each pin
PWM_Instance->setPWM_manual(PWM_Pins, new_top, new_div, new_level);
bool setPWM_DCPercentage_manual(const uint8_t& pin, float& DCPercentage)
after that, if just changing dutyCycle
/ level
, use
// For 50.0f dutycycle
new_level = 50.0f * PWM_Instance->get_TOP() / 100.0f;
PWM_Instance->setPWM_manual(PWM_Pins, new_level);
or better and much easier to use
new_DCPercentage = 50.0f;
PWM_Instance->setPWM_DCPercentage_manual(PWM_Pins, new_DCPercentage);
and the fastest
// For 50.0f dutycycle
new_level = 50.0f * PWM_Instance->get_TOP() / 100.0f;
PWM_Instance->setPWM_manual_Fast(pinToUse, dutycycle);
To use a pair of pins of the same channel / slice. Check Programmer’s Model
Need to call only once for each pair of pins
float frequency = 2000.0f;
float dutyCycle = 30.0f;
// Pins have to be in pairs of the same PWM slice / channel
// Check https://github.com/khoih-prog/RP2040_PWM#programmers-model
// For example: pins 0/1, 2/3, 4/5, 6/7, 8/9, 10/11, 12/13, 14/15, 16/17, 18/19, 20/21, 22/23, 24/25, 26/27, 28/29
#define pinToUseA 18 // PWM1A
#define pinToUseB 19 // PWM1A
// Use just one of these 2 for a pair
// assigns pinToUseA, with frequency of 200 Hz and a duty cycle of 0%
PWM_Instance = new RP2040_PWM(pinToUseA, frequency, 0);
// assigns pinToUseB, with frequency of 200 Hz and a duty cycle of 0%
//PWM_Instance = new RP2040_PWM(pinToUseB, frequency, 0);
after that, if just changing dutyCycle
/ level
, use
// For 50.0f dutycycle
new_dutyCycle = 50.0f;
PWM_Instance->setPWMPushPull(pinToUseA, pinToUseB, frequency, new_dutyCycle);
or if just changing frequency
, use
// For 50.0f dutycycle
new_frequency = 1000.0f;
PWM_Instance->setPWMPushPull(pinToUseA, pinToUseB, new_frequency, dutyCycle);
phaseCorrect == true
freq
phaseCorrect == true
RP2040_PWM* PWM_Instance;
PWM_Instance = new RP2040_PWM(PWM_Pins, freq, dutyCycle, true);
...
PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle, true);
phaseCorrect == false
freq
phaseCorrect == false
RP2040_PWM* PWM_Instance;
PWM_Instance = new RP2040_PWM(PWM_Pins, freq, dutyCycle);
...
PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);
The following is the sample terminal output when running example PWM_Multi on RaspberryPi Pico, running ArduinoCore-mbed mbed_rp2040 core
, to demonstrate the ability to provide high PWM frequencies and the accuracy of Hardware-based PWM, especially when system is very busy.
Starting PWM_Multi on RaspberryPi Pico
RP2040_PWM v1.7.0
=============================================================
Index Pin PWM_freq DutyCycle Actual Freq
=============================================================
0 25 20.00 10.00 20.00
1 2 30.00 50.00 30.00
2 4 40.00 30.00 40.00
3 6 1000.00 40.00 1000.00
4 0 2000.00 50.00 2000.00
5 10 3000.00 60.00 3000.00
6 12 8000.00 70.00 8000.00
7 14 9999.00 80.00 9999.00
=============================================================
The following is the sample terminal output when running example PWM_Multi on RASPBERRY_PI_PICO, running Earle Philhower's arduino-pico core
, to demonstrate the ability to provide high PWM frequencies and the accuracy of Hardware-based PWM, especially when system is very busy.
Starting PWM_Multi on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
=============================================================
Index Pin PWM_freq DutyCycle Actual Freq
=============================================================
0 25 20.00 10.00 20.00
1 2 30.00 50.00 30.00
2 4 40.00 30.00 40.00
3 6 1000.00 40.00 1000.00
4 0 2000.00 50.00 2000.00
5 10 3000.00 60.00 3000.00
6 12 8000.00 70.00 8000.00
7 14 9999.00 80.00 9999.00
=============================================================
The following is the sample terminal output when running example PWM_DynamicFreq on Nano RP2040 Connect, running ArduinoCore-mbed mbed_rp2040 core
, to demonstrate the ability to change dynamically PWM frequencies and the accuracy of Hardware-based PWM.
Starting PWM_DynamicFreq on Nano RP2040 Connect
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 12499 , _actualFrequency = 1000.00
[PWM] PWM enabled, frequency = 1000.00
=============================================================
Change PWM Freq to 2000.00
[PWM] _PWM_config.top = 62499 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00
[PWM] PWM enabled, frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 62499 , DIV = 1 , CPU_freq = 125000000
Change PWM Freq to 1000.00
[PWM] _PWM_config.top = 12499 , _actualFrequency = 1000.00
[PWM] Changing PWM frequency to 1000.00
[PWM] PWM enabled, frequency = 1000.00
Actual PWM Frequency = 1000.00
[PWM] TOP = 12499 , DIV = 10 , CPU_freq = 125000000
Change PWM Freq to 2000.00
[PWM] _PWM_config.top = 62499 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00
[PWM] PWM enabled, frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 62499 , DIV = 1 , CPU_freq = 125000000
Change PWM Freq to 1000.00
[PWM] _PWM_config.top = 12499 , _actualFrequency = 1000.00
[PWM] Changing PWM frequency to 1000.00
[PWM] PWM enabled, frequency = 1000.00
Actual PWM Frequency = 1000.00
[PWM] TOP = 12499 , DIV = 10 , CPU_freq = 125000000
Change PWM Freq to 2000.00
[PWM] _PWM_config.top = 62499 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00
[PWM] PWM enabled, frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 62499 , DIV = 1 , CPU_freq = 125000000
The following is the sample terminal output when running example PWM_DynamicDutyCycle on RASPBERRY_PI_PICO, running Earle Philhower's arduino-pico core
, to demonstrate the ability to change dynamically PWM dutyCycle and the accuracy of Hardware-based PWM.
Starting PWM_DynamicDutyCycle on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 13299 , _actualFrequency = 1000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 1000.00
=============================================================
Change PWM DutyCycle to 50.00
[PWM] _PWM_config.top = 6649 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00 and dutyCycle = 50.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 10.00
[PWM] Changing PWM DutyCycle to 10.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 50.00
[PWM] Changing PWM DutyCycle to 50.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 10.00
[PWM] Changing PWM DutyCycle to 10.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 50.00
[PWM] Changing PWM DutyCycle to 50.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 10.00
[PWM] Changing PWM DutyCycle to 10.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 50.00
[PWM] Changing PWM DutyCycle to 50.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
Change PWM DutyCycle to 10.00
[PWM] Changing PWM DutyCycle to 10.00 and keeping frequency = 2000.00
[PWM] pin = 25 , PWM_CHAN = 1
[PWM] PWM enabled, slice = 4 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
The following is the sample terminal output when running example PWM_MultiChannel on RASPBERRY_PI_PICO, running Earle Philhower's arduino-pico core
, to demonstrate the ability to output for both channels of a PWM slice
Starting PWM_MultiChannel on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
=============================================================
Index Pin PWM_freq DutyCycle Actual Freq
=============================================================
0 10 1000.00 10.00 1000.00
1 11 1000.00 50.00 1000.00
=============================================================
The following is the sample terminal output when running example PWM_Waveform on RASPBERRY_PI_PICO, running Earle Philhower's arduino-pico core
, to demonstrate how to use new setPWM_manual()
function in wafeform creation
Starting PWM_Waveform on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 12499 , _actualFrequency = 1000.00
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
=============================================================
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
...
The following is the sample terminal output when running example PWM_Waveform_Fast on RASPBERRY_PI_PICO, running arduino-pico core
, to demonstrate how to use new setPWM_manual()
function in wafeform creation
Starting PWM_Waveform_Fast on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 12499 , _actualFrequency = 1000.00
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
=============================================================
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 1000
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 900
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 800
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 700
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 600
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 500
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 400
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 300
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 200
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 100
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 50
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
[PWM] pin = 10 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 5 , top = 1000 , div = 10 , level = 0
...
The following is the sample terminal output when running example PWM_manual on RASPBERRY_PI_PICO, running arduino-pico core
, to demonstrate how to use new setPWM_DCPercentage_manual()
function in wafeform creation
Starting PWM_manual on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 0.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 5.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 10.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 15.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 20.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 25.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 30.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 35.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 40.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 45.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 50.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
...
The following is the sample terminal output when running example PWM_SpeedTest on RASPBERRY_PI_PICO, running arduino-pico core
, to demonstrate how to use new faster setPWM_manual_Fast()
function in wafeform creation, The time is 1597ns
compared to 2889ns
when using setPWM_manual()
function
Starting PWM_SpeedTest on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
=================================================================================================
Actual data: pin = 10, PWM DutyCycle % = 0.00, PWMPeriod = 13299, PWM Freq (Hz) = 1000.0000
=================================================================================================
Average time of setPWM function
ns=1598
ns=1597
ns=1597
ns=1597
ns=1597
ns=1597
ns=1597
ns=1597
ns=1597
ns=1597
...
The following is the sample terminal output when running example PWM_PushPull on RASPBERRY_PI_PICO, running arduino-pico core
, to demo the new PushPull
mode
Starting PWM_PushPull on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 6249 , _actualFrequency = 2000.00
[PWM] _PWM_config.top = 3124 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00 and dutyCycle = 30.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 3124 , DIV = 10 , CPU_freq = 125000000
The following is the sample terminal output when running example PWM_PushPull_DynamicDC on RASPBERRY_PI_PICO, running arduino-pico core
, to demo the new PushPull
mode
Starting PWM_PushPull_DynamicDC on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 6249 , _actualFrequency = 2000.00
[PWM] _PWM_config.top = 3124 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00 and dutyCycle = 0.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Change PWM DutyCycle to 50.00
[PWM] Changing PWM DutyCycle to 50.00 and keeping frequency = 2000.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 3124 , DIV = 10 , CPU_freq = 125000000
Change PWM DutyCycle to 10.00
[PWM] Changing PWM DutyCycle to 10.00 and keeping frequency = 2000.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 3124 , DIV = 10 , CPU_freq = 125000000
Change PWM DutyCycle to 50.00
[PWM] Changing PWM DutyCycle to 50.00 and keeping frequency = 2000.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 3124 , DIV = 10 , CPU_freq = 125000000
...
The following is the sample terminal output when running example PWM_PushPull_DynamicFreq on RASPBERRY_PI_PICO, running arduino-pico core
, to demo the new PushPull
mode
Starting PWM_PushPull_DynamicFreq on RASPBERRY_PI_PICO
RP2040_PWM v1.7.0
[PWM] _PWM_config.top = 6249 , _actualFrequency = 2000.00
[PWM] _PWM_config.top = 3124 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00 and dutyCycle = 0.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Change PWM Freq to 2000.00
[PWM] Changing PWM DutyCycle to 30.00 and keeping frequency = 2000.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 3124 , DIV = 10 , CPU_freq = 125000000
Change PWM Freq to 1000.00
[PWM] _PWM_config.top = 6249 , _actualFrequency = 1000.00
[PWM] Changing PWM frequency to 1000.00 and dutyCycle = 30.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 1000.00
Actual PWM Frequency = 1000.00
[PWM] TOP = 6249 , DIV = 10 , CPU_freq = 125000000
Change PWM Freq to 2000.00
[PWM] _PWM_config.top = 3124 , _actualFrequency = 2000.00
[PWM] Changing PWM frequency to 2000.00 and dutyCycle = 30.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 2000.00
Actual PWM Frequency = 2000.00
[PWM] TOP = 3124 , DIV = 10 , CPU_freq = 125000000
Change PWM Freq to 1000.00
[PWM] _PWM_config.top = 6249 , _actualFrequency = 1000.00
[PWM] Changing PWM frequency to 1000.00 and dutyCycle = 30.00
[PWM] pinA = 18 , pinB = 19 , PWM_CHAN = 0
[PWM] PWM enabled, slice = 1 , _frequency = 1000.00
Actual PWM Frequency = 1000.00
[PWM] TOP = 6249 , DIV = 10 , CPU_freq = 125000000
...
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
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.
Submit issues to: RP2040_PWM issues
changelog.md
instead
of double
for frequency and duty-cyclesetPWM_manual()
function to use in wafeform creation using PWMsetPWM_manual()
function in wafeform creationsetPWM_manual(pin, level)
function for efficiency in wafeform creation using PWMsetPWM_manual(pin, level)
functionsetPWM_Int()
function for optional uint32_t dutycycle = real_dutycycle * 1000
setPWM_Int()
functionminimal
example PWM_BasicMIN_PWM_FREQUENCY
and MAX_PWM_FREQUENCY
dynamically according to actual F_CPU
setPWM_DCPercentage_manual()
to facilitate the setting PWM DC manually by using DCPercentage
, instead of absolute DCValue
depending on varying TOP
getPin()
and getActualDutyCycle()
setPWM_manual_Fast
function to improve almost 50% compared to setPWM_manual
. Check setPWM_manual_Fast
functionsetPWMPushPull_Int
, setPWMPushPull
and setPWMPushPull_Period
for the new PushPull
modePushPull
mode
phaseCorrect
modeREADME.md
so that links can be used in other sites, such as PIO
Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library.
Stepper-Motor
in Using PWM to step a stepper driver #16, leading to v1.4.1setPWM_manual()
speed in setPWM latency #19, leading to v1.6.0pwm_set_output_polarity()
function in pwm_set_output_polarity #21, leading to v1.7.0⭐️ Américo Dias |
⭐️ Austin K. Litman |
⭐️ Joerg Starkmuth |
⭐️ Dr. Benjamin Bird |
Rocking Y Productions |
Paul van Dinther |
jmdodd95682 |
tinkerbug |
If you want to contribute to this project:
Copyright 2021- Khoi Hoang