11#include "hardware/structs/pwm.h"
12#include "hardware/regs/dreq.h"
13#include "hardware/regs/intctrl.h"
20#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_PWM
21#ifdef PARAM_ASSERTIONS_ENABLED_PWM
22#define PARAM_ASSERTIONS_ENABLED_HARDWARE_PWM PARAM_ASSERTIONS_ENABLED_PWM
24#define PARAM_ASSERTIONS_ENABLED_HARDWARE_PWM 0
85#define PWM_DREQ_NUM(slice_num) (DREQ_PWM_WRAP0 + (slice_num))
94#ifndef PWM_GPIO_SLICE_NUM
95#define PWM_GPIO_SLICE_NUM(gpio) ({ \
98 slice_num = ((gpio) >> 1u) & 7u; \
100 slice_num = 8u + (((gpio) >> 1u) & 3u); \
107#ifndef PICO_PWM_CLKDIV_ROUND_NEAREST
108#define PICO_PWM_CLKDIV_ROUND_NEAREST PICO_CLKDIV_ROUND_NEAREST
111static inline void check_slice_num_param(__unused uint slice_num) {
112 valid_params_if(HARDWARE_PWM, slice_num < NUM_PWM_SLICES);
121 valid_params_if(HARDWARE_PWM, gpio < NUM_BANK0_GPIOS);
133 valid_params_if(HARDWARE_PWM, gpio < NUM_BANK0_GPIOS);
147 c->csr = (c->csr & ~PWM_CH0_CSR_PH_CORRECT_BITS)
148 | (bool_to_bit(phase_correct) << PWM_CH0_CSR_PH_CORRECT_LSB);
162 valid_params_if(HARDWARE_PWM, div >= 1.f && div < 256.f);
163 const int frac_bit_count = REG_FIELD_WIDTH(PWM_CH0_DIV_FRAC);
164#if PICO_PWM_CLKDIV_ROUND_NEAREST
165 div += 0.5f / (1 << frac_bit_count);
167 c->div = (uint32_t)(div * (
float)(1u << frac_bit_count));
182 static_assert(REG_FIELD_WIDTH(PWM_CH0_DIV_INT) == 8,
"");
183 valid_params_if(HARDWARE_PWM, div_int >= 1 && div_int < 256);
184 static_assert(REG_FIELD_WIDTH(PWM_CH0_DIV_FRAC) == 4,
"");
185 valid_params_if(HARDWARE_PWM, div_frac4 < 16);
186 c->div = (((uint)div_int) << PWM_CH0_DIV_INT_LSB) | (((uint)div_frac4) << PWM_CH0_DIV_FRAC_LSB);
190static inline void pwm_config_set_clkdiv_int_frac(
pwm_config *c, uint8_t div_int, uint8_t div_frac4) {
223 c->csr = (c->csr & ~PWM_CH0_CSR_DIVMODE_BITS)
224 | (((uint)mode) << PWM_CH0_CSR_DIVMODE_LSB);
235 c->csr = (c->csr & ~(PWM_CH0_CSR_A_INV_BITS | PWM_CH0_CSR_B_INV_BITS))
236 | ((bool_to_bit(a) << PWM_CH0_CSR_A_INV_LSB) | (bool_to_bit(b) << PWM_CH0_CSR_B_INV_LSB));
263 check_slice_num_param(slice_num);
264 pwm_hw->slice[slice_num].csr = 0;
266 pwm_hw->slice[slice_num].ctr = PWM_CH0_CTR_RESET;
267 pwm_hw->slice[slice_num].cc = PWM_CH0_CC_RESET;
268 pwm_hw->slice[slice_num].top = c->top;
269 pwm_hw->slice[slice_num].div = c->div;
270 pwm_hw->slice[slice_num].csr = c->csr | (bool_to_bit(start) << PWM_CH0_CSR_EN_LSB);
307 check_slice_num_param(slice_num);
308 pwm_hw->slice[slice_num].top = wrap;
327 check_slice_num_param(slice_num);
329 &pwm_hw->slice[slice_num].cc,
330 ((uint)level) << (chan ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB),
331 chan ? PWM_CH0_CC_B_BITS : PWM_CH0_CC_A_BITS
351 check_slice_num_param(slice_num);
352 pwm_hw->slice[slice_num].cc = (((uint)level_b) << PWM_CH0_CC_B_LSB) | (((uint)level_a) << PWM_CH0_CC_A_LSB);
374 valid_params_if(HARDWARE_PWM, gpio < NUM_BANK0_GPIOS);
387 check_slice_num_param(slice_num);
388 return (uint16_t)(pwm_hw->slice[slice_num].ctr);
401 check_slice_num_param(slice_num);
402 pwm_hw->slice[slice_num].ctr = c;
415 check_slice_num_param(slice_num);
416 hw_set_bits(&pwm_hw->slice[slice_num].csr, PWM_CH0_CSR_PH_ADV_BITS);
417 while (pwm_hw->slice[slice_num].csr & PWM_CH0_CSR_PH_ADV_BITS) {
432 check_slice_num_param(slice_num);
433 hw_set_bits(&pwm_hw->slice[slice_num].csr, PWM_CH0_CSR_PH_RET_BITS);
434 while (pwm_hw->slice[slice_num].csr & PWM_CH0_CSR_PH_RET_BITS) {
449 check_slice_num_param(slice_num);
450 valid_params_if(HARDWARE_PWM, div_int >= 1);
451 static_assert(REG_FIELD_WIDTH(PWM_CH0_DIV_FRAC) == 4,
"");
452 valid_params_if(HARDWARE_PWM, div_frac4 < 16);
453 pwm_hw->slice[slice_num].div = (((uint)div_int) << PWM_CH0_DIV_INT_LSB) | (((uint)div_frac4) << PWM_CH0_DIV_FRAC_LSB);
457static inline void pwm_set_clkdiv_int_frac(uint slice_num, uint8_t div_int, uint8_t div_frac4) {
470 check_slice_num_param(slice_num);
471 valid_params_if(HARDWARE_PWM, divider >= 1.f && divider < 256.f);
472 uint8_t i = (uint8_t)divider;
473 uint8_t f = (uint8_t)((divider - i) * (0x01 << 4));
485 check_slice_num_param(slice_num);
486 hw_write_masked(&pwm_hw->slice[slice_num].csr, bool_to_bit(a) << PWM_CH0_CSR_A_INV_LSB | bool_to_bit(b) << PWM_CH0_CSR_B_INV_LSB,
487 PWM_CH0_CSR_A_INV_BITS | PWM_CH0_CSR_B_INV_BITS);
498 check_slice_num_param(slice_num);
503 hw_write_masked(&pwm_hw->slice[slice_num].csr, ((uint)mode) << PWM_CH0_CSR_DIVMODE_LSB, PWM_CH0_CSR_DIVMODE_BITS);
516 check_slice_num_param(slice_num);
517 hw_write_masked(&pwm_hw->slice[slice_num].csr, bool_to_bit(phase_correct) << PWM_CH0_CSR_PH_CORRECT_LSB, PWM_CH0_CSR_PH_CORRECT_BITS);
547 check_slice_num_param(slice_num);
548 hw_write_masked(&pwm_hw->slice[slice_num].csr, bool_to_bit(enabled) << PWM_CH0_CSR_EN_LSB, PWM_CH0_CSR_EN_BITS);
576#ifndef PWM_DEFAULT_IRQ_NUM
578#define PWM_DEFAULT_IRQ_NUM() PWM_IRQ_WRAP
580#define PWM_DEFAULT_IRQ_NUM() PWM_IRQ_WRAP_0
582#define PWM_IRQ_WRAP PWM_IRQ_WRAP_0
583#define isr_pwm_wrap isr_pwm_wrap_0
598 check_slice_num_param(slice_num);
628static inline void pwm_set_irq1_enabled(uint slice_num,
bool enabled) {
629 check_slice_num_param(slice_num);
650 check_slice_num_param(slice_num);
651 invalid_params_if(HARDWARE_PWM, irq_index >= NUM_PWM_IRQS);
652 check_slice_num_param(slice_num);
654 hw_set_bits(&pwm_hw->irq_ctrl[irq_index].inte, 1u << slice_num);
656 hw_clear_bits(&pwm_hw->irq_ctrl[irq_index].inte, 1u << slice_num);
671 valid_params_if(HARDWARE_PWM, slice_mask < 256);
679 static_assert(PWM_IRQ_WRAP_1 == PWM_IRQ_WRAP_0 + 1,
"");
682 hw_set_bits(&pwm_hw->irq_ctrl[irq_index].inte, slice_mask);
684 hw_clear_bits(&pwm_hw->irq_ctrl[irq_index].inte, slice_mask);
711static inline void pwm_set_irq1_mask_enabled(uint32_t slice_mask,
bool enabled) {
732 invalid_params_if(HARDWARE_PWM, irq_index >= NUM_PWM_IRQS);
734 hw_set_bits(&pwm_hw->irq_ctrl[irq_index].inte, slice_mask);
736 hw_clear_bits(&pwm_hw->irq_ctrl[irq_index].inte, slice_mask);
746 pwm_hw->intr = 1u << slice_num;
773static inline uint32_t pwm_get_irq1_status_mask(
void) {
774 return pwm_hw->ints1;
785 invalid_params_if(HARDWARE_PWM, irq_index >= NUM_PWM_IRQS);
786 return pwm_hw->irq_ctrl[irq_index].ints;
795 pwm_hw->intf = 1u << slice_num;
813static inline void pwm_force_irq1(uint slice_num) {
814 pwm_hw->intf1 = 1u << slice_num;
825 invalid_params_if(HARDWARE_PWM, irq_index >= NUM_PWM_IRQS);
826 pwm_hw->irq_ctrl[irq_index].intf = 1u << slice_num;
835 check_slice_num_param(slice_num);
static __force_inline void hw_set_bits(io_rw_32 *addr, uint32_t mask)
Atomically set the specified bits to 1 in a HW register.
Definition address_mapped.h:135
static __force_inline void hw_write_masked(io_rw_32 *addr, uint32_t values, uint32_t write_mask)
Set new values for a sub-set of the bits in a HW register.
Definition address_mapped.h:171
static __force_inline void hw_clear_bits(io_rw_32 *addr, uint32_t mask)
Atomically clear the specified bits to 0 in a HW register.
Definition address_mapped.h:145
@ DREQ_PWM_WRAP1
Select PWM Counter 1's Wrap Value as DREQ.
Definition dreq.h:92
@ DREQ_PWM_WRAP0
Select PWM Counter 0's Wrap Value as DREQ.
Definition dreq.h:91
@ DREQ_PWM_WRAP7
Select PWM Counter 7's Wrap Value as DREQ.
Definition dreq.h:98
static void pwm_init(uint slice_num, pwm_config *c, bool start)
Initialise a PWM with settings from a configuration object.
Definition pwm.h:262
static void pwm_config_set_phase_correct(pwm_config *c, bool phase_correct)
Set phase correction in a PWM configuration.
Definition pwm.h:146
static void pwm_set_irq_enabled(uint slice_num, bool enabled)
Enable PWM instance interrupt via the default PWM IRQ (PWM_IRQ_WRAP_0 on RP2350)
Definition pwm.h:597
pwm_clkdiv_mode
PWM Divider mode settings.
Definition pwm.h:55
static void pwm_set_clkdiv_int_frac4(uint slice_num, uint8_t div_int, uint8_t div_frac4)
Set PWM clock divider using an 8:4 fractional value.
Definition pwm.h:448
static void pwm_retard_count(uint slice_num)
Retard PWM count.
Definition pwm.h:431
static void pwm_config_set_clkdiv_int(pwm_config *c, uint32_t div_int)
Set PWM clock divider in a PWM configuration.
Definition pwm.h:204
static uint16_t pwm_get_counter(uint slice_num)
Get PWM counter.
Definition pwm.h:386
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:326
static uint32_t pwm_get_irq0_status_mask(void)
Get PWM interrupt status, raw for the PWM_IRQ_WRAP_0.
Definition pwm.h:763
static void pwm_set_clkdiv_mode(uint slice_num, enum pwm_clkdiv_mode mode)
Set PWM divider mode.
Definition pwm.h:497
static void pwm_set_enabled(uint slice_num, bool enabled)
Enable/Disable PWM.
Definition pwm.h:546
static void pwm_set_mask_enabled(uint32_t mask)
Enable/Disable multiple PWM slices simultaneously.
Definition pwm.h:556
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.
Definition pwm.h:373
static void pwm_config_set_clkdiv_mode(pwm_config *c, enum pwm_clkdiv_mode mode)
Set PWM counting mode in a PWM configuration.
Definition pwm.h:218
static void pwm_irqn_set_slice_enabled(uint irq_index, uint slice_num, bool enabled)
Enable PWM instance interrupt via either PWM_IRQ_WRAP_0 or PWM_IRQ_WRAP_1.
Definition pwm.h:649
static uint pwm_get_dreq(uint slice_num)
Return the DREQ to use for pacing transfers to a particular PWM slice.
Definition pwm.h:834
static void pwm_force_irq(uint slice_num)
Force PWM interrupt for the default PWM IRQ (PWM_IRQ_WRAP_0 on RP2350)
Definition pwm.h:794
static void pwm_irqn_force(uint irq_index, uint slice_num)
Force PWM interrupt via PWM_IRQ_WRAP_0 or PWM_IRQ_WRAP_1.
Definition pwm.h:824
static void pwm_set_counter(uint slice_num, uint16_t c)
Set PWM counter.
Definition pwm.h:400
static void pwm_force_irq0(uint slice_num)
Force PWM interrupt via PWM_IRQ_WRAP_0.
Definition pwm.h:803
static uint32_t pwm_get_irq_status_mask(void)
Get PWM interrupt status, raw for the default PWM IRQ (PWM_IRQ_WRAP_0 on RP2350)
Definition pwm.h:754
static void pwm_config_set_clkdiv(pwm_config *c, float div)
Set PWM clock divider in a PWM configuration.
Definition pwm.h:161
static void pwm_irqn_set_slice_mask_enabled(uint irq_index, uint slice_mask, bool enabled)
Enable PWM instance interrupts via either PWM_IRQ_WRAP_0 or PWM_IRQ_WRAP_1.
Definition pwm.h:731
static void pwm_set_wrap(uint slice_num, uint16_t wrap)
Set the current PWM counter wrap value.
Definition pwm.h:306
#define PWM_DEFAULT_IRQ_NUM()
Returns the irq_num_t for the default PWM IRQ.
Definition pwm.h:578
static void pwm_set_irq0_enabled(uint slice_num, bool enabled)
Enable PWM instance interrupt via PWM_IRQ_WRAP_0.
Definition pwm.h:614
static void pwm_config_set_clkdiv_int_frac4(pwm_config *c, uint32_t div_int, uint8_t div_frac4)
Set PWM clock divider in a PWM configuration using an 8:4 fractional value.
Definition pwm.h:181
static uint pwm_gpio_to_slice_num(uint gpio)
Determine the PWM slice that is attached to the specified GPIO.
Definition pwm.h:120
static void pwm_clear_irq(uint slice_num)
Clear a single PWM channel interrupt.
Definition pwm.h:745
static void pwm_set_clkdiv(uint slice_num, float divider)
Set PWM clock divider.
Definition pwm.h:469
static uint pwm_gpio_to_channel(uint gpio)
Determine the PWM channel that is attached to the specified GPIO.
Definition pwm.h:132
static void pwm_advance_count(uint slice_num)
Advance PWM count.
Definition pwm.h:414
static void pwm_set_output_polarity(uint slice_num, bool a, bool b)
Set PWM output polarity.
Definition pwm.h:484
static uint32_t pwm_irqn_get_status_mask(uint irq_index)
Get PWM interrupt status, raw for either PWM_IRQ_WRAP_0 or PWM_IRQ_WRAP_1.
Definition pwm.h:784
#define PWM_DREQ_NUM(slice_num)
Returns the dreq_num_t used for pacing DMA transfers for a given PWM slice.
Definition pwm.h:85
static void pwm_config_set_output_polarity(pwm_config *c, bool a, bool b)
Set output polarity in a PWM configuration.
Definition pwm.h:234
static void pwm_set_irq_mask_enabled(uint32_t slice_mask, bool enabled)
Enable multiple PWM instance interrupts via the default PWM IRQ (PWM_IRQ_WRAP_0 on RP2350)
Definition pwm.h:670
static void pwm_set_phase_correct(uint slice_num, bool phase_correct)
Set PWM phase correct on/off.
Definition pwm.h:515
static void pwm_config_set_wrap(pwm_config *c, uint16_t wrap)
Set PWM counter wrap value in a PWM configuration.
Definition pwm.h:247
static pwm_config pwm_get_default_config(void)
Get a set of default values for PWM configuration.
Definition pwm.h:281
#define PWM_GPIO_SLICE_NUM(gpio)
Returns the PWM slice number for a given GPIO number.
Definition pwm.h:95
static void pwm_set_irq0_mask_enabled(uint32_t slice_mask, bool enabled)
Enable multiple PWM instance interrupts via PWM_IRQ_WRAP_0.
Definition pwm.h:697
static void pwm_set_both_levels(uint slice_num, uint16_t level_a, uint16_t level_b)
Set PWM counter compare values.
Definition pwm.h:350
@ PWM_DIV_B_FALLING
Fractional divider advances with each falling edge of the PWM B pin.
Definition pwm.h:59
@ PWM_DIV_B_HIGH
Fractional divider is gated by the PWM B pin.
Definition pwm.h:57
@ PWM_DIV_FREE_RUNNING
Free-running counting at rate dictated by fractional divider.
Definition pwm.h:56
@ PWM_DIV_B_RISING
Fractional divider advances with each rising edge of the PWM B pin.
Definition pwm.h:58