Skip to content

Commit 90d1644

Browse files
FRASTMcarlescufi
authored andcommitted
drivers: pwm: stm32 can initialize the PWM complementary output
If the dts defines the PWM complementary output, then the OCN must be init in place of the OC state and polarity. This is an exclusive setting for this pin. The channel in LL_TIM_OC_SetPolarity can be the complementary one. Signed-off-by: Francois Ramu <[email protected]>
1 parent 5eb4df1 commit 90d1644

File tree

1 file changed

+58
-26
lines changed

1 file changed

+58
-26
lines changed

drivers/pwm/pwm_stm32.c

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <init.h>
2020

2121
#include <drivers/clock_control/stm32_clock_control.h>
22+
#include <dt-bindings/pwm/stm32_pwm.h>
2223

2324
#include <logging/log.h>
2425
LOG_MODULE_REGISTER(pwm_stm32, CONFIG_PWM_LOG_LEVEL);
@@ -40,6 +41,10 @@ struct pwm_stm32_capture_data {
4041
bool capture_pulse;
4142
bool continuous;
4243
};
44+
45+
/* first capture is always nonsense, second is nonsense when polarity changed */
46+
#define SKIPPED_PWM_CAPTURES 2u
47+
4348
#endif /*CONFIG_PWM_CAPTURE*/
4449

4550
/** PWM data. */
@@ -66,34 +71,15 @@ struct pwm_stm32_config {
6671
#endif /* CONFIG_PWM_CAPTURE */
6772
};
6873

69-
/** Series F3, F7, G0, G4, H7, L4, MP1 and WB have up to 6 channels, others up
70-
* to 4.
71-
*/
72-
#if defined(CONFIG_SOC_SERIES_STM32F3X) || \
73-
defined(CONFIG_SOC_SERIES_STM32F7X) || \
74-
defined(CONFIG_SOC_SERIES_STM32G0X) || \
75-
defined(CONFIG_SOC_SERIES_STM32G4X) || \
76-
defined(CONFIG_SOC_SERIES_STM32H7X) || \
77-
defined(CONFIG_SOC_SERIES_STM32L4X) || \
78-
defined(CONFIG_SOC_SERIES_STM32MP1X) || \
79-
defined(CONFIG_SOC_SERIES_STM32WBX)
74+
/** Maximum number of timer channels : some stm32 soc have 6 else only 4 */
75+
#if defined(LL_TIM_CHANNEL_CH6)
8076
#define TIMER_HAS_6CH 1
81-
#else
82-
#define TIMER_HAS_6CH 0
83-
#endif
84-
85-
/** Maximum number of timer channels. */
86-
#if TIMER_HAS_6CH
8777
#define TIMER_MAX_CH 6u
8878
#else
79+
#define TIMER_HAS_6CH 0
8980
#define TIMER_MAX_CH 4u
9081
#endif
9182

92-
/* first capture is always nonsense, second is nonsense when polarity changed */
93-
#ifdef CONFIG_PWM_CAPTURE
94-
#define SKIPPED_PWM_CAPTURES 2u
95-
#endif /* CONFIG_PWM_CAPTURE */
96-
9783
/** Channel to LL mapping. */
9884
static const uint32_t ch2ll[TIMER_MAX_CH] = {
9985
LL_TIM_CHANNEL_CH1, LL_TIM_CHANNEL_CH2,
@@ -103,6 +89,21 @@ static const uint32_t ch2ll[TIMER_MAX_CH] = {
10389
#endif
10490
};
10591

92+
93+
/** Some stm32 mcus have complementary channels : 3 or 4 */
94+
static const uint32_t ch2ll_n[] = {
95+
#if defined(LL_TIM_CHANNEL_CH1N)
96+
LL_TIM_CHANNEL_CH1N,
97+
LL_TIM_CHANNEL_CH2N,
98+
LL_TIM_CHANNEL_CH3N,
99+
#if defined(LL_TIM_CHANNEL_CH4N)
100+
/** stm32g4x and stm32u5x have 4 complementary channels */
101+
LL_TIM_CHANNEL_CH4N,
102+
#endif /* LL_TIM_CHANNEL_CH4N */
103+
#endif /* LL_TIM_CHANNEL_CH1N */
104+
};
105+
/** Maximum number of complemented timer channels is ARRAY_SIZE(ch2ll_n)*/
106+
106107
/** Channel to compare set function mapping. */
107108
static void (*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *,
108109
uint32_t) = {
@@ -227,6 +228,7 @@ static int pwm_stm32_pin_set(const struct device *dev, uint32_t pwm,
227228
const struct pwm_stm32_config *cfg = dev->config;
228229

229230
uint32_t channel;
231+
uint32_t current_channel; /* complementary output if used */
230232

231233
if (pwm < 1u || pwm > TIMER_MAX_CH) {
232234
LOG_ERR("Invalid channel (%d)", pwm);
@@ -259,20 +261,47 @@ static int pwm_stm32_pin_set(const struct device *dev, uint32_t pwm,
259261

260262
channel = ch2ll[pwm - 1u];
261263

264+
/* in LL_TIM_CC_DisableChannel and LL_TIM_CC_IsEnabledChannel,
265+
* the channel param could be the complementary one
266+
*/
267+
if ((flags & PWM_STM32_COMPLEMENTARY_MASK) == PWM_STM32_COMPLEMENTARY) {
268+
if (pwm > ARRAY_SIZE(ch2ll_n)) {
269+
/* setting a flag on a channel that has not this capability */
270+
LOG_ERR("Channel %d has NO complementary output", pwm);
271+
return -EINVAL;
272+
}
273+
current_channel = ch2ll_n[pwm - 1u];
274+
} else {
275+
current_channel = channel;
276+
}
277+
262278
if (period_cycles == 0u) {
263-
LL_TIM_CC_DisableChannel(cfg->timer, channel);
279+
LL_TIM_CC_DisableChannel(cfg->timer, current_channel);
264280
return 0;
265281
}
266282

267-
if (!LL_TIM_CC_IsEnabledChannel(cfg->timer, channel)) {
283+
if (!LL_TIM_CC_IsEnabledChannel(cfg->timer, current_channel)) {
268284
LL_TIM_OC_InitTypeDef oc_init;
269285

270286
LL_TIM_OC_StructInit(&oc_init);
271287

272288
oc_init.OCMode = LL_TIM_OCMODE_PWM1;
289+
290+
#if defined(LL_TIM_CHANNEL_CH1N)
291+
/* the flags holds the PWM_STM32_COMPLEMENTARY information */
292+
if ((flags & PWM_STM32_COMPLEMENTARY_MASK) == PWM_STM32_COMPLEMENTARY) {
293+
oc_init.OCNState = LL_TIM_OCSTATE_ENABLE;
294+
oc_init.OCNPolarity = get_polarity(flags);
295+
} else {
296+
oc_init.OCState = LL_TIM_OCSTATE_ENABLE;
297+
oc_init.OCPolarity = get_polarity(flags);
298+
}
299+
#else /* LL_TIM_CHANNEL_CH1N */
300+
273301
oc_init.OCState = LL_TIM_OCSTATE_ENABLE;
274-
oc_init.CompareValue = pulse_cycles;
275302
oc_init.OCPolarity = get_polarity(flags);
303+
#endif /* LL_TIM_CHANNEL_CH1N */
304+
oc_init.CompareValue = pulse_cycles;
276305

277306
#ifdef CONFIG_PWM_CAPTURE
278307
if (IS_TIM_SLAVE_INSTANCE(cfg->timer)) {
@@ -283,17 +312,20 @@ static int pwm_stm32_pin_set(const struct device *dev, uint32_t pwm,
283312
}
284313
#endif /* CONFIG_PWM_CAPTURE */
285314

315+
/* in LL_TIM_OC_Init, the channel is always the non-complementary */
286316
if (LL_TIM_OC_Init(cfg->timer, channel, &oc_init) != SUCCESS) {
287317
LOG_ERR("Could not initialize timer channel output");
288318
return -EIO;
289319
}
290320

291321
LL_TIM_EnableARRPreload(cfg->timer);
322+
/* in LL_TIM_OC_EnablePreload, the channel is always the non-complementary */
292323
LL_TIM_OC_EnablePreload(cfg->timer, channel);
293324
LL_TIM_SetAutoReload(cfg->timer, period_cycles - 1u);
294325
LL_TIM_GenerateEvent_UPDATE(cfg->timer);
295326
} else {
296-
LL_TIM_OC_SetPolarity(cfg->timer, channel, get_polarity(flags));
327+
/* in LL_TIM_OC_SetPolarity, the channel could be the complementary one */
328+
LL_TIM_OC_SetPolarity(cfg->timer, current_channel, get_polarity(flags));
297329
set_timer_compare[pwm - 1u](cfg->timer, pulse_cycles);
298330
LL_TIM_SetAutoReload(cfg->timer, period_cycles - 1u);
299331
}

0 commit comments

Comments
 (0)