From 7c657ad5c97062718af2b3d7e363b53e6463089f Mon Sep 17 00:00:00 2001 From: Laurent Meunier Date: Mon, 2 May 2016 10:39:56 +0200 Subject: [PATCH 1/4] [STM32F3] Increase the supported period range (#1682) Introducing the prescaler management allows a wider period range support, from about 65ms before now up to about 32s. We're also introducing asserts in case the period or prescaler is truncated as the HW registers are 16 bits large. --- .../TARGET_DISCO_F303VC/objects.h | 1 + .../TARGET_DISCO_F334C8/objects.h | 1 + .../TARGET_NUCLEO_F302R8/objects.h | 1 + .../TARGET_NUCLEO_F303K8/objects.h | 1 + .../TARGET_NUCLEO_F303RE/objects.h | 1 + .../TARGET_NUCLEO_F334R8/objects.h | 1 + .../TARGET_STM/TARGET_STM32F3/pwmout_api.c | 22 ++++++++++++++++--- 7 files changed, 25 insertions(+), 3 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F303VC/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F303VC/objects.h index 974f6a8066e..a1cba7d5836 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F303VC/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F303VC/objects.h @@ -99,6 +99,7 @@ struct i2c_s { struct pwmout_s { PWMName pwm; PinName pin; + uint32_t prescaler; uint32_t period; uint32_t pulse; uint32_t channel; diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F334C8/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F334C8/objects.h index 974f6a8066e..a1cba7d5836 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F334C8/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_DISCO_F334C8/objects.h @@ -99,6 +99,7 @@ struct i2c_s { struct pwmout_s { PWMName pwm; PinName pin; + uint32_t prescaler; uint32_t period; uint32_t pulse; uint32_t channel; diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F302R8/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F302R8/objects.h index 974f6a8066e..a1cba7d5836 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F302R8/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F302R8/objects.h @@ -99,6 +99,7 @@ struct i2c_s { struct pwmout_s { PWMName pwm; PinName pin; + uint32_t prescaler; uint32_t period; uint32_t pulse; uint32_t channel; diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303K8/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303K8/objects.h index 974f6a8066e..a1cba7d5836 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303K8/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303K8/objects.h @@ -99,6 +99,7 @@ struct i2c_s { struct pwmout_s { PWMName pwm; PinName pin; + uint32_t prescaler; uint32_t period; uint32_t pulse; uint32_t channel; diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303RE/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303RE/objects.h index 974f6a8066e..a1cba7d5836 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303RE/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F303RE/objects.h @@ -99,6 +99,7 @@ struct i2c_s { struct pwmout_s { PWMName pwm; PinName pin; + uint32_t prescaler; uint32_t period; uint32_t pulse; uint32_t channel; diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F334R8/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F334R8/objects.h index 974f6a8066e..a1cba7d5836 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F334R8/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/TARGET_NUCLEO_F334R8/objects.h @@ -99,6 +99,7 @@ struct i2c_s { struct pwmout_s { PWMName pwm; PinName pin; + uint32_t prescaler; uint32_t period; uint32_t pulse; uint32_t channel; diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c index 73a639e6590..d77fa075b8e 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c @@ -96,7 +96,7 @@ void pwmout_write(pwmout_t* obj, float value) // Configure channels sConfig.OCMode = TIM_OCMODE_PWM1; - sConfig.Pulse = obj->pulse; + sConfig.Pulse = obj->pulse / obj->prescaler; sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfig.OCFastMode = TIM_OCFAST_DISABLE; @@ -161,8 +161,24 @@ void pwmout_period_us(pwmout_t* obj, int us) // Update the SystemCoreClock variable SystemCoreClockUpdate(); - TimHandle.Init.Period = us - 1; - TimHandle.Init.Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 us tick + /* To make it simple, we use to possible prescaler values which lead to: + * pwm unit = 1us, period/pulse can be from 1us to 65535us + * or + * pwm unit = 500us, period/pulse can be from 500us to ~32.76sec + * Be careful that all the channels of a PWM shares the same prescaler + */ + if (us > 0xFFFF) { + obj->prescaler = 500; + } else { + obj->prescaler = 1; + } + TimHandle.Init.Prescaler = ((SystemCoreClock / 1000000) * obj->prescaler) - 1; + + MBED_ASSERT(TimHandle.Init.Prescaler < 0xFFFF); + + TimHandle.Init.Period = (us - 1) / obj->prescaler; + MBED_ASSERT(TimHandle.Init.Period < 0xFFFF); + TimHandle.Init.ClockDivision = 0; TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; From c9350f8e5ad7e974d943992139a5fc3dbff4fd70 Mon Sep 17 00:00:00 2001 From: Laurent Meunier Date: Tue, 3 May 2016 16:31:46 +0200 Subject: [PATCH 2/4] Update ARDUINO test to allow period change --- libraries/tests/mbed/pwm/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/tests/mbed/pwm/main.cpp b/libraries/tests/mbed/pwm/main.cpp index 30eab22d736..2b0dccf222a 100644 --- a/libraries/tests/mbed/pwm/main.cpp +++ b/libraries/tests/mbed/pwm/main.cpp @@ -19,15 +19,15 @@ float value = 0.75; int main() { #if defined(TARGET_FF_ARDUINO) PwmOut pwm(D9); + int period_us = 40000; // allows to test various periods - pwm.period_ms(10); + pwm.period_us(period_us); pwm.write(value); float result = floor(pwm.read() * 100 + 0.5) / 100; // round it to 0.xx - printf("Initialize PWM on pin D9 with duty cycle: %.2f\n", result); + printf("PWM period = %dus with duty cycle: %d%%\n", period_us, (int) (result * 100)); notify_completion(result == value ? true : false); - #elif defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) || defined(TARGET_LPC4088) || defined(TARGET_LPC2460) PwmOut pwm_p25(p25); PwmOut pwm_p26(p26); From 731148eb72f0c2614ea931adeab71201005c85f5 Mon Sep 17 00:00:00 2001 From: Laurent Meunier Date: Wed, 4 May 2016 08:59:57 +0200 Subject: [PATCH 3/4] Back to 10ms period As suggested in review comments, let's keep default 10ms period --- libraries/tests/mbed/pwm/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/tests/mbed/pwm/main.cpp b/libraries/tests/mbed/pwm/main.cpp index 2b0dccf222a..bdafaa8c6db 100644 --- a/libraries/tests/mbed/pwm/main.cpp +++ b/libraries/tests/mbed/pwm/main.cpp @@ -19,13 +19,13 @@ float value = 0.75; int main() { #if defined(TARGET_FF_ARDUINO) PwmOut pwm(D9); - int period_us = 40000; // allows to test various periods + int period_ms = 10; - pwm.period_us(period_us); + pwm.period_ms(period_ms); pwm.write(value); float result = floor(pwm.read() * 100 + 0.5) / 100; // round it to 0.xx - printf("PWM period = %dus with duty cycle: %d%%\n", period_us, (int) (result * 100)); + printf("PWM period = %dms with duty cycle: %d%%\n", period_ms, (int) (result * 100)); notify_completion(result == value ? true : false); #elif defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) || defined(TARGET_LPC4088) || defined(TARGET_LPC2460) From c5c95d11f31d5cedab3478e422ede42c330564f8 Mon Sep 17 00:00:00 2001 From: Laurent Meunier Date: Wed, 4 May 2016 09:25:40 +0200 Subject: [PATCH 4/4] Use runtime error detection Rather than MBED_ASSERT, let's use error() function to detect out of range parameters during runtime execution --- .../mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c index d77fa075b8e..c538e6474a3 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3/pwmout_api.c @@ -174,10 +174,12 @@ void pwmout_period_us(pwmout_t* obj, int us) } TimHandle.Init.Prescaler = ((SystemCoreClock / 1000000) * obj->prescaler) - 1; - MBED_ASSERT(TimHandle.Init.Prescaler < 0xFFFF); + if (TimHandle.Init.Prescaler > 0xFFFF) + error("PWM: out of range prescaler"); TimHandle.Init.Period = (us - 1) / obj->prescaler; - MBED_ASSERT(TimHandle.Init.Period < 0xFFFF); + if (TimHandle.Init.Period > 0xFFFF) + error("PWM: out of range period"); TimHandle.Init.ClockDivision = 0; TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;