diff --git a/cpu/stm32/include/periph/cpu_pwm.h b/cpu/stm32/include/periph/cpu_pwm.h index 9154b32543..f22c1048f0 100644 --- a/cpu/stm32/include/periph/cpu_pwm.h +++ b/cpu/stm32/include/periph/cpu_pwm.h @@ -33,10 +33,21 @@ extern "C" { /** * @brief PWM channel + * + * When using a general-purpose timer for a PWM device, the outputs OC of + * each of the four capture/compare channels can be used as PWM channel. + * The respective capture/compare channel is then specified with 0...3 in + * `cc_chan` for the outputs OC1...OC4. + * + * Advanced timers like TIM1 and TIM8 have additionally three complementary + * outputs OCN of the capture/compare channels, which can also be used + * as PWM channels. These complementary outputs are defined with an offset + * of 4, i.e. they are specified in `cc_chan` with 4...6 for OC1N...OC3N. */ typedef struct { gpio_t pin; /**< GPIO pin mapped to this channel */ - uint8_t cc_chan; /**< capture compare channel used */ + uint8_t cc_chan; /**< Capture/compare channel used: 0..3 for OC1..OC4 + or 4..6 for OC1N..OC3N for advanced timers */ } pwm_chan_t; /** diff --git a/cpu/stm32/periph/pwm.c b/cpu/stm32/periph/pwm.c index 72a89eef99..09df6d210c 100644 --- a/cpu/stm32/periph/pwm.c +++ b/cpu/stm32/periph/pwm.c @@ -68,9 +68,23 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) /* configure the used pins */ unsigned i = 0; + uint32_t ccer = 0; + while ((i < TIMER_CHANNEL_NUMOF) && (pwm_config[pwm].chan[i].pin != GPIO_UNDEF)) { gpio_init(pwm_config[pwm].chan[i].pin, GPIO_OUT); gpio_init_af(pwm_config[pwm].chan[i].pin, pwm_config[pwm].af); + if (pwm_config[pwm].chan[i].cc_chan < 4) { + /* OCx output channel used */ + ccer |= TIM_CCER_CC1E << ((pwm_config[pwm].chan[i].cc_chan) << 2); + } + else { +#ifdef TIM_CCER_CC1NE + /* OCxN complementary output channel used */ + ccer |= TIM_CCER_CC1NE << ((pwm_config[pwm].chan[i].cc_chan & 0x03) << 2); +#else + assert(false); +#endif + } i++; } @@ -102,8 +116,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) #ifdef TIM_BDTR_MOE dev(pwm)->BDTR = TIM_BDTR_MOE; #endif - dev(pwm)->CCER = (TIM_CCER_CC1E | TIM_CCER_CC2E | - TIM_CCER_CC3E | TIM_CCER_CC4E); + dev(pwm)->CCER = ccer; dev(pwm)->CR1 |= TIM_CR1_CEN; /* return the actual used PWM frequency */ @@ -138,7 +151,7 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value) } /* set new value */ - TIM_CHAN(pwm, pwm_config[pwm].chan[channel].cc_chan) = value; + TIM_CHAN(pwm, (pwm_config[pwm].chan[channel].cc_chan & 0x3)) = value; } void pwm_poweron(pwm_t pwm)