1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
19572: cpu/stm32/periph_pwm: support of complementary timer outputs r=maribu a=gschorcht

### Contribution description

This PR provides the support of complementary timer outputs as PWM channels for advanced timers (TIM1/TIM8).

To use a complementary output of an advanced timer as PWM channel, the output is defined with an offset of 4, i.e. normal outputs are in the range of 0 to 3 (CH1...CH4) and complementary outputs are in the range of 4 to 6 (CH1N...CH3N). If the defined output is less than 4, the normal output is enabled, otherwise the complementary output is enabled.

This change is required to support PWM on boards that have connected the complementary outputs of advanced timers to the PWM connector pins, for example the STM32L496-DISCO board.

### Testing procedure

- Green CI
- Use any STM32 board which supports the `periph_pwm` feature. `tests/periph_pwm` should still work.
- Change the configuration for this board so that either timer TIM1 or TIM8 and a complementary channel is used for any exposed GPIO. `tests/periph_pwm` should also work with such a configuration.

### Issues/PRs references


Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
This commit is contained in:
bors[bot] 2023-05-20 09:57:27 +00:00 committed by GitHub
commit f47003c1db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 4 deletions

View File

@ -33,10 +33,21 @@ extern "C" {
/**
* @brief PWM channel
*
* When using a general-purpose timer for a PWM device, the outputs OC<n> 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 OC<n>N 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;
/**

View File

@ -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)