hardware_pwm

Enumerations

enum  pwm_clkdiv_mode { PWM_DIV_FREE_RUNNING = 0 , PWM_DIV_B_HIGH = 1 , PWM_DIV_B_RISING = 2 , PWM_DIV_B_FALLING = 3 }
 PWM Divider mode settings. More...
 

Functions

static uint pwm_gpio_to_slice_num (uint gpio)
 Determine the PWM slice that is attached to the specified GPIO. More...
 
static uint pwm_gpio_to_channel (uint gpio)
 Determine the PWM channel that is attached to the specified GPIO. More...
 
static void pwm_config_set_phase_correct (pwm_config *c, bool phase_correct)
 Set phase correction in a PWM configuration. More...
 
static void pwm_config_set_clkdiv (pwm_config *c, float div)
 Set PWM clock divider in a PWM configuration. More...
 
static void pwm_config_set_clkdiv_int_frac (pwm_config *c, uint8_t integer, uint8_t fract)
 Set PWM clock divider in a PWM configuration using an 8:4 fractional value. More...
 
static void pwm_config_set_clkdiv_int (pwm_config *c, uint div)
 Set PWM clock divider in a PWM configuration. More...
 
static void pwm_config_set_clkdiv_mode (pwm_config *c, enum pwm_clkdiv_mode mode)
 Set PWM counting mode in a PWM configuration. More...
 
static void pwm_config_set_output_polarity (pwm_config *c, bool a, bool b)
 Set output polarity in a PWM configuration. More...
 
static void pwm_config_set_wrap (pwm_config *c, uint16_t wrap)
 Set PWM counter wrap value in a PWM configuration. More...
 
static void pwm_init (uint slice_num, pwm_config *c, bool start)
 Initialise a PWM with settings from a configuration object. More...
 
static pwm_config pwm_get_default_config (void)
 Get a set of default values for PWM configuration. More...
 
static void pwm_set_wrap (uint slice_num, uint16_t wrap)
 Set the current PWM counter wrap value. More...
 
static void pwm_set_chan_level (uint slice_num, uint chan, uint16_t level)
 Set the current PWM counter compare value for one channel. More...
 
static void pwm_set_both_levels (uint slice_num, uint16_t level_a, uint16_t level_b)
 Set PWM counter compare values. More...
 
static void pwm_set_gpio_level (uint gpio, uint16_t level)
 Helper function to set the PWM level for the slice and channel associated with a GPIO. More...
 
static uint16_t pwm_get_counter (uint slice_num)
 Get PWM counter. More...
 
static void pwm_set_counter (uint slice_num, uint16_t c)
 Set PWM counter. More...
 
static void pwm_advance_count (uint slice_num)
 Advance PWM count. More...
 
static void pwm_retard_count (uint slice_num)
 Retard PWM count. More...
 
static void pwm_set_clkdiv_int_frac (uint slice_num, uint8_t integer, uint8_t fract)
 Set PWM clock divider using an 8:4 fractional value. More...
 
static void pwm_set_clkdiv (uint slice_num, float divider)
 Set PWM clock divider. More...
 
static void pwm_set_output_polarity (uint slice_num, bool a, bool b)
 Set PWM output polarity. More...
 
static void pwm_set_clkdiv_mode (uint slice_num, enum pwm_clkdiv_mode mode)
 Set PWM divider mode. More...
 
static void pwm_set_phase_correct (uint slice_num, bool phase_correct)
 Set PWM phase correct on/off. More...
 
static void pwm_set_enabled (uint slice_num, bool enabled)
 Enable/Disable PWM. More...
 
static void pwm_set_mask_enabled (uint32_t mask)
 Enable/Disable multiple PWM slices simultaneously. More...
 
static void pwm_set_irq_enabled (uint slice_num, bool enabled)
 Enable PWM instance interrupt. More...
 
static void pwm_set_irq_mask_enabled (uint32_t slice_mask, bool enabled)
 Enable multiple PWM instance interrupts. More...
 
static void pwm_clear_irq (uint slice_num)
 Clear a single PWM channel interrupt. More...
 
static uint32_t pwm_get_irq_status_mask (void)
 Get PWM interrupt status, raw. More...
 
static void pwm_force_irq (uint slice_num)
 Force PWM interrupt. More...
 
static uint pwm_get_dreq (uint slice_num)
 Return the DREQ to use for pacing transfers to a particular PWM slice. More...
 

Detailed Description

Hardware Pulse Width Modulation (PWM) API

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 GPIOs can be driven by the PWM block.

The PWM hardware functions by continuously comparing the input value to a free-running counter. This produces a toggling output where the amount of time spent at the high output level is proportional to the input value. The fraction of time spent at the high signal level is known as the duty cycle of the signal.

The default behaviour of a PWM slice is to count upward until the wrap value (pwm_config_set_wrap) is reached, and then immediately wrap to 0. PWM slices also offer a phase-correct mode, where the counter starts to count downward after reaching TOP, until it reaches 0 again.

Example

// Output PWM signals on pins 0 and 1
#include "pico/stdlib.h"
#include "hardware/pwm.h"
int main() {
// Tell GPIO 0 and 1 they are allocated to the PWM
gpio_set_function(0, GPIO_FUNC_PWM);
gpio_set_function(1, GPIO_FUNC_PWM);
// Find out which PWM slice is connected to GPIO 0 (it's slice 0)
uint slice_num = pwm_gpio_to_slice_num(0);
// Set period of 4 cycles (0 to 3 inclusive)
pwm_set_wrap(slice_num, 3);
// Set channel A output high for one cycle before dropping
pwm_set_chan_level(slice_num, PWM_CHAN_A, 1);
// Set initial B output high for three cycles before dropping
pwm_set_chan_level(slice_num, PWM_CHAN_B, 3);
// Set the PWM running
pwm_set_enabled(slice_num, true);
// Note we could also use pwm_set_gpio_level(gpio, x) which looks up the
// correct slice and channel for a given GPIO.
}
void gpio_set_function(uint gpio, enum gpio_function fn)
Select GPIO function.
Definition: gpio.c:32
static void pwm_set_chan_level(uint slice_num, uint chan, uint16_t level)
Set the current PWM counter compare value for one channel.
Definition: pwm.h:274
static void pwm_set_enabled(uint slice_num, bool enabled)
Enable/Disable PWM.
Definition: pwm.h:488
static void pwm_set_wrap(uint slice_num, uint16_t wrap)
Set the current PWM counter wrap value.
Definition: pwm.h:254
static uint pwm_gpio_to_slice_num(uint gpio)
Determine the PWM slice that is attached to the specified GPIO.
Definition: pwm.h:78

Enumeration Type Documentation

◆ pwm_clkdiv_mode

PWM Divider mode settings.

Enumerator
PWM_DIV_FREE_RUNNING 

Free-running counting at rate dictated by fractional divider.

PWM_DIV_B_HIGH 

Fractional divider is gated by the PWM B pin.

PWM_DIV_B_RISING 

Fractional divider advances with each rising edge of the PWM B pin.

PWM_DIV_B_FALLING 

Fractional divider advances with each falling edge of the PWM B pin.

Function Documentation

◆ pwm_advance_count()

static void pwm_advance_count ( uint  slice_num)
inlinestatic

Advance PWM count.

Advance the phase of a running the counter by 1 count.

This function will return once the increment is complete.

Parameters
slice_numPWM slice number

◆ pwm_clear_irq()

static void pwm_clear_irq ( uint  slice_num)
inlinestatic

Clear a single PWM channel interrupt.

Parameters
slice_numPWM slice number

◆ pwm_config_set_clkdiv()

static void pwm_config_set_clkdiv ( pwm_config c,
float  div 
)
inlinestatic

Set PWM clock divider in a PWM configuration.

Parameters
cPWM configuration struct to modify
divValue to divide counting rate by. Must be greater than or equal to 1.

If the divide mode is free-running, the PWM counter runs at clk_sys / div. Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge) before passing them on to the PWM counter.

◆ pwm_config_set_clkdiv_int()

static void pwm_config_set_clkdiv_int ( pwm_config c,
uint  div 
)
inlinestatic

Set PWM clock divider in a PWM configuration.

Parameters
cPWM configuration struct to modify
divInteger value to reduce counting rate by. Must be greater than or equal to 1.

If the divide mode is free-running, the PWM counter runs at clk_sys / div. Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge) before passing them on to the PWM counter.

◆ pwm_config_set_clkdiv_int_frac()

static void pwm_config_set_clkdiv_int_frac ( pwm_config c,
uint8_t  integer,
uint8_t  fract 
)
inlinestatic

Set PWM clock divider in a PWM configuration using an 8:4 fractional value.

Parameters
cPWM configuration struct to modify
integer8 bit integer part of the clock divider. Must be greater than or equal to 1.
fract4 bit fractional part of the clock divider

If the divide mode is free-running, the PWM counter runs at clk_sys / div. Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge) before passing them on to the PWM counter.

◆ pwm_config_set_clkdiv_mode()

static void pwm_config_set_clkdiv_mode ( pwm_config c,
enum pwm_clkdiv_mode  mode 
)
inlinestatic

Set PWM counting mode in a PWM configuration.

Parameters
cPWM configuration struct to modify
modePWM divide/count mode

Configure which event gates the operation of the fractional divider. The default is always-on (free-running PWM). Can also be configured to count on high level, rising edge or falling edge of the B pin input.

◆ pwm_config_set_output_polarity()

static void pwm_config_set_output_polarity ( pwm_config c,
bool  a,
bool  b 
)
inlinestatic

Set output polarity in a PWM configuration.

Parameters
cPWM configuration struct to modify
atrue to invert output A
btrue to invert output B

◆ pwm_config_set_phase_correct()

static void pwm_config_set_phase_correct ( pwm_config c,
bool  phase_correct 
)
inlinestatic

Set phase correction in a PWM configuration.

Parameters
cPWM configuration struct to modify
phase_correcttrue to set phase correct modulation, false to set trailing edge

Setting phase control to true means that instead of wrapping back to zero when the wrap point is reached, the PWM starts counting back down. The output frequency is halved when phase-correct mode is enabled.

◆ pwm_config_set_wrap()

static void pwm_config_set_wrap ( pwm_config c,
uint16_t  wrap 
)
inlinestatic

Set PWM counter wrap value in a PWM configuration.

Set the highest value the counter will reach before returning to 0. Also known as TOP.

Parameters
cPWM configuration struct to modify
wrapValue to set wrap to

◆ pwm_force_irq()

static void pwm_force_irq ( uint  slice_num)
inlinestatic

Force PWM interrupt.

Parameters
slice_numPWM slice number

◆ pwm_get_counter()

static uint16_t pwm_get_counter ( uint  slice_num)
inlinestatic

Get PWM counter.

Get current value of PWM counter

Parameters
slice_numPWM slice number
Returns
Current value of the PWM counter

◆ pwm_get_default_config()

static pwm_config pwm_get_default_config ( void  )
inlinestatic

Get a set of default values for PWM configuration.

PWM config is free-running at system clock speed, no phase correction, wrapping at 0xffff, with standard polarities for channels A and B.

Returns
Set of default values.

◆ pwm_get_dreq()

static uint pwm_get_dreq ( uint  slice_num)
inlinestatic

Return the DREQ to use for pacing transfers to a particular PWM slice.

Parameters
slice_numPWM slice number

◆ pwm_get_irq_status_mask()

static uint32_t pwm_get_irq_status_mask ( void  )
inlinestatic

Get PWM interrupt status, raw.

Returns
Bitmask of all PWM interrupts currently set

◆ pwm_gpio_to_channel()

static uint pwm_gpio_to_channel ( uint  gpio)
inlinestatic

Determine the PWM channel that is attached to the specified GPIO.

Each slice 0 to 7 has two channels, A and B.

Returns
The PWM channel that controls the specified GPIO.

◆ pwm_gpio_to_slice_num()

static uint pwm_gpio_to_slice_num ( uint  gpio)
inlinestatic

Determine the PWM slice that is attached to the specified GPIO.

Returns
The PWM slice number that controls the specified GPIO.

◆ pwm_init()

static void pwm_init ( uint  slice_num,
pwm_config c,
bool  start 
)
inlinestatic

Initialise a PWM with settings from a configuration object.

Use the pwm_get_default_config() function to initialise a config structure, make changes as needed using the pwm_config_* functions, then call this function to set up the PWM.

Parameters
slice_numPWM slice number
cThe configuration to use
startIf true the PWM will be started running once configured. If false you will need to start manually using pwm_set_enabled() or pwm_set_mask_enabled()

◆ pwm_retard_count()

static void pwm_retard_count ( uint  slice_num)
inlinestatic

Retard PWM count.

Retard the phase of a running counter by 1 count

This function will return once the retardation is complete.

Parameters
slice_numPWM slice number

◆ pwm_set_both_levels()

static void pwm_set_both_levels ( uint  slice_num,
uint16_t  level_a,
uint16_t  level_b 
)
inlinestatic

Set PWM counter compare values.

Set the value of the PWM counter compare values, A and B.

The counter compare register is double-buffered in hardware. This means that, when the PWM is running, a write to the counter compare values does not take effect until 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.

Parameters
slice_numPWM slice number
level_aValue to set compare A to. When the counter reaches this value the A output is deasserted
level_bValue to set compare B to. When the counter reaches this value the B output is deasserted

◆ pwm_set_chan_level()

static void pwm_set_chan_level ( uint  slice_num,
uint  chan,
uint16_t  level 
)
inlinestatic

Set the current PWM counter compare value for one channel.

Set the value of the PWM counter compare value, for either channel A or channel B.

The counter compare register is double-buffered in hardware. This means that, when the PWM is running, a write to the counter compare values does not take effect until 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.

Parameters
slice_numPWM slice number
chanWhich channel to update. 0 for A, 1 for B.
levelnew level for the selected output

◆ pwm_set_clkdiv()

static void pwm_set_clkdiv ( uint  slice_num,
float  divider 
)
inlinestatic

Set PWM clock divider.

Set the clock divider. Counter increment will be on sysclock divided by this value, taking into account the gating.

Parameters
slice_numPWM slice number
dividerFloating point clock divider, 1.f <= value < 256.f

◆ pwm_set_clkdiv_int_frac()

static void pwm_set_clkdiv_int_frac ( uint  slice_num,
uint8_t  integer,
uint8_t  fract 
)
inlinestatic

Set PWM clock divider using an 8:4 fractional value.

Set the clock divider. Counter increment will be on sysclock divided by this value, taking into account the gating.

Parameters
slice_numPWM slice number
integer8 bit integer part of the clock divider
fract4 bit fractional part of the clock divider

◆ pwm_set_clkdiv_mode()

static void pwm_set_clkdiv_mode ( uint  slice_num,
enum pwm_clkdiv_mode  mode 
)
inlinestatic

Set PWM divider mode.

Parameters
slice_numPWM slice number
modeRequired divider mode

◆ pwm_set_counter()

static void pwm_set_counter ( uint  slice_num,
uint16_t  c 
)
inlinestatic

Set PWM counter.

Set the value of the PWM counter

Parameters
slice_numPWM slice number
cValue to set the PWM counter to

◆ pwm_set_enabled()

static void pwm_set_enabled ( uint  slice_num,
bool  enabled 
)
inlinestatic

Enable/Disable PWM.

When a PWM is disabled, it halts its counter, and the output pins are left high or low depending on exactly when the counter is halted. When re-enabled the PWM resumes immediately from where it left off.

If the PWM's output pins need to be low when halted:

  • The counter compare can be set to zero whilst the PWM is enabled, and then the PWM disabled once both pins are seen to be low
  • The GPIO output overrides can be used to force the actual pins low
  • The PWM can be run for one cycle (i.e. enabled then immediately disabled) with a TOP of 0, count of 0 and counter compare of 0, to force the pins low when the PWM has already been halted. The same method can be used with a counter compare value of 1 to force a pin high.

Note that, when disabled, the PWM can still be advanced one count at a time by pulsing the PH_ADV bit in its CSR. The output pins transition as though the PWM were enabled.

Parameters
slice_numPWM slice number
enabledtrue to enable the specified PWM, false to disable.

◆ pwm_set_gpio_level()

static void pwm_set_gpio_level ( uint  gpio,
uint16_t  level 
)
inlinestatic

Helper function to set the PWM level for the slice and channel associated with a GPIO.

Look up the correct slice (0 to 7) and channel (A or B) for a given GPIO, and update the corresponding counter compare field.

This PWM slice should already have been configured and set running. Also be careful of multiple GPIOs mapping to the same slice and channel (if GPIOs have a difference of 16).

The counter compare register is double-buffered in hardware. This means that, when the PWM is running, a write to the counter compare values does not take effect until 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.

Parameters
gpioGPIO to set level of
levelPWM level for this GPIO

◆ pwm_set_irq_enabled()

static void pwm_set_irq_enabled ( uint  slice_num,
bool  enabled 
)
inlinestatic

Enable PWM instance interrupt.

Used to enable a single PWM instance interrupt.

Parameters
slice_numPWM block to enable/disable
enabledtrue to enable, false to disable

◆ pwm_set_irq_mask_enabled()

static void pwm_set_irq_mask_enabled ( uint32_t  slice_mask,
bool  enabled 
)
inlinestatic

Enable multiple PWM instance interrupts.

Use this to enable multiple PWM interrupts at once.

Parameters
slice_maskBitmask of all the blocks to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
enabledtrue to enable, false to disable

◆ pwm_set_mask_enabled()

static void pwm_set_mask_enabled ( uint32_t  mask)
inlinestatic

Enable/Disable multiple PWM slices simultaneously.

Parameters
maskBitmap of PWMs to enable/disable. Bits 0 to 7 enable slices 0-7 respectively

◆ pwm_set_output_polarity()

static void pwm_set_output_polarity ( uint  slice_num,
bool  a,
bool  b 
)
inlinestatic

Set PWM output polarity.

Parameters
slice_numPWM slice number
atrue to invert output A
btrue to invert output B

◆ pwm_set_phase_correct()

static void pwm_set_phase_correct ( uint  slice_num,
bool  phase_correct 
)
inlinestatic

Set PWM phase correct on/off.

Parameters
slice_numPWM slice number
phase_correcttrue to set phase correct modulation, false to set trailing edge

Setting phase control to true means that instead of wrapping back to zero when the wrap point is reached, the PWM starts counting back down. The output frequency is halved when phase-correct mode is enabled.

◆ pwm_set_wrap()

static void pwm_set_wrap ( uint  slice_num,
uint16_t  wrap 
)
inlinestatic

Set the current PWM counter wrap value.

Set the highest value the counter will reach before returning to 0. Also known as TOP.

The counter wrap value is double-buffered in hardware. This means that, when the PWM is running, a write to the counter wrap value does not take effect until 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.

Parameters
slice_numPWM slice number
wrapValue to set wrap to