Skip to content

Commit ab45ef0

Browse files
author
Laurent MEUNIER
committed
[STM32F4] Handle higher range pwm periods
As first reported on STM32F3 family in #1682, we need to cope with periods in the seconds range as well. This is fixed here in the same way as was done for STM32F3 by using the pre-scaler.
1 parent ce5ee17 commit ab45ef0

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

hal/targets/hal/TARGET_STM/TARGET_STM32F4/common_objects.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extern "C" {
4242
struct pwmout_s {
4343
PWMName pwm;
4444
PinName pin;
45+
uint32_t prescaler;
4546
uint32_t period;
4647
uint32_t pulse;
4748
uint8_t channel;

hal/targets/hal/TARGET_STM/TARGET_STM32F4/pwmout_api.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ void pwmout_init(pwmout_t* obj, PinName pin)
9494
obj->pin = pin;
9595
obj->period = 0;
9696
obj->pulse = 0;
97+
obj->prescaler = 1;
9798

9899
pwmout_period_us(obj, 20000); // 20 ms per default
99100
}
@@ -121,7 +122,7 @@ void pwmout_write(pwmout_t* obj, float value)
121122

122123
// Configure channels
123124
sConfig.OCMode = TIM_OCMODE_PWM1;
124-
sConfig.Pulse = obj->pulse;
125+
sConfig.Pulse = obj->pulse / obj->prescaler;
125126
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
126127
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
127128
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
@@ -240,26 +241,45 @@ void pwmout_period_us(pwmout_t* obj, int us)
240241
default:
241242
return;
242243
}
243-
244-
TimHandle.Init.Period = us - 1;
244+
245+
/* To make it simple, we use to possible prescaler values which lead to:
246+
* pwm unit = 1us, period/pulse can be from 1us to 65535us
247+
* or
248+
* pwm unit = 500us, period/pulse can be from 500us to ~32.76sec
249+
* Be careful that all the channels of a PWM shares the same prescaler
250+
*/
251+
if (us > 0xFFFF) {
252+
obj->prescaler = 500;
253+
} else {
254+
obj->prescaler = 1;
255+
}
256+
245257
// TIMxCLK = PCLKx when the APB prescaler = 1 else TIMxCLK = 2 * PCLKx
246258
if (APBxCLKDivider == RCC_HCLK_DIV1)
247-
TimHandle.Init.Prescaler = (uint16_t)((PclkFreq) / 1000000) - 1; // 1 us tick
259+
TimHandle.Init.Prescaler = (uint16_t)(((PclkFreq) / 1000000) * obj->prescaler) - 1; // 1 us tick
248260
else
249-
TimHandle.Init.Prescaler = (uint16_t)((PclkFreq * 2) / 1000000) - 1; // 1 us tick
261+
TimHandle.Init.Prescaler = (uint16_t)(((PclkFreq * 2) / 1000000) * obj->prescaler) - 1; // 1 us tick
262+
263+
if (TimHandle.Init.Prescaler > 0xFFFF)
264+
error("PWM: out of range prescaler");
265+
266+
TimHandle.Init.Period = (us - 1) / obj->prescaler;
267+
if (TimHandle.Init.Period > 0xFFFF)
268+
error("PWM: out of range period");
269+
250270
TimHandle.Init.ClockDivision = 0;
251271
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
252-
272+
253273
if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK) {
254274
error("Cannot initialize PWM\n");
255275
}
256276

257-
// Set duty cycle again
258-
pwmout_write(obj, dc);
259-
260277
// Save for future use
261278
obj->period = us;
262279

280+
// Set duty cycle again
281+
pwmout_write(obj, dc);
282+
263283
__HAL_TIM_ENABLE(&TimHandle);
264284
}
265285

@@ -276,6 +296,7 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms)
276296
void pwmout_pulsewidth_us(pwmout_t* obj, int us)
277297
{
278298
float value = (float)us / (float)obj->period;
299+
printf("pwmout_pulsewidth_us: period=%d, us=%d, dc=%d%%\r\n", obj->period, us, (int) (value*100));
279300
pwmout_write(obj, value);
280301
}
281302

0 commit comments

Comments
 (0)