diff --git a/bsp/stm32/libraries/HAL_Drivers/drv_pwm.c b/bsp/stm32/libraries/HAL_Drivers/drv_pwm.c index b655b7c442..d440b155ed 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drv_pwm.c +++ b/bsp/stm32/libraries/HAL_Drivers/drv_pwm.c @@ -340,6 +340,97 @@ static rt_err_t drv_pwm_set(TIM_HandleTypeDef *htim, struct rt_pwm_configuration return RT_EOK; } +static rt_err_t drv_pwm_set_period(TIM_HandleTypeDef *htim, struct rt_pwm_configuration *configuration) +{ + rt_uint32_t period; + rt_uint64_t tim_clock, psc; + rt_uint32_t pclk1_doubler, pclk2_doubler; + + pclkx_doubler_get(&pclk1_doubler, &pclk2_doubler); + +#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) + if (htim->Instance == TIM9 || htim->Instance == TIM10 || htim->Instance == TIM11) +#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32H7)|| defined(SOC_SERIES_STM32F3) + if (htim->Instance == TIM15 || htim->Instance == TIM16 || htim->Instance == TIM17) +#elif defined(SOC_SERIES_STM32MP1) + if (htim->Instance == TIM4) +#elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) + if (0) +#endif + { +#if !defined(SOC_SERIES_STM32F0) && !defined(SOC_SERIES_STM32G0) + tim_clock = (rt_uint32_t)(HAL_RCC_GetPCLK2Freq() * pclk2_doubler); +#endif + } + else + { + tim_clock = (rt_uint32_t)(HAL_RCC_GetPCLK1Freq() * pclk1_doubler); + } + + /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */ + tim_clock /= 1000000UL; + period = (unsigned long long)configuration->period * tim_clock / 1000ULL ; + psc = period / MAX_PERIOD + 1; + period = period / psc; + __HAL_TIM_SET_PRESCALER(htim, psc - 1); + + if (period < MIN_PERIOD) + { + period = MIN_PERIOD; + } + __HAL_TIM_SET_AUTORELOAD(htim, period - 1); + + return RT_EOK; +} + +static rt_err_t drv_pwm_set_pulse(TIM_HandleTypeDef *htim, struct rt_pwm_configuration *configuration) +{ + rt_uint32_t period, pulse; + rt_uint64_t tim_clock; + rt_uint32_t pclk1_doubler, pclk2_doubler; + /* Converts the channel number to the channel number of Hal library */ + rt_uint32_t channel = 0x04 * (configuration->channel - 1); + + pclkx_doubler_get(&pclk1_doubler, &pclk2_doubler); + +#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) + if (htim->Instance == TIM9 || htim->Instance == TIM10 || htim->Instance == TIM11) +#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32H7)|| defined(SOC_SERIES_STM32F3) + if (htim->Instance == TIM15 || htim->Instance == TIM16 || htim->Instance == TIM17) +#elif defined(SOC_SERIES_STM32MP1) + if (htim->Instance == TIM4) +#elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) + if (0) +#endif + { +#if !defined(SOC_SERIES_STM32F0) && !defined(SOC_SERIES_STM32G0) + tim_clock = (rt_uint32_t)(HAL_RCC_GetPCLK2Freq() * pclk2_doubler); +#endif + } + else + { + tim_clock = (rt_uint32_t)(HAL_RCC_GetPCLK1Freq() * pclk1_doubler); + } + + /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */ + tim_clock /= 1000000UL; + + period = (__HAL_TIM_GET_AUTORELOAD(htim) + 1) * (htim->Instance->PSC + 1) * 1000UL / tim_clock; + pulse = (unsigned long long)configuration->pulse * (__HAL_TIM_GET_AUTORELOAD(htim) + 1) / period; + + if (pulse < MIN_PULSE) + { + pulse = MIN_PULSE; + } + else if (pulse > period) + { + pulse = period; + } + __HAL_TIM_SET_COMPARE(htim, channel, pulse - 1); + + return RT_EOK; +} + static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg) { struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg; @@ -357,6 +448,10 @@ static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg return drv_pwm_enable(htim, configuration, RT_FALSE); case PWM_CMD_SET: return drv_pwm_set(htim, configuration); + case PWM_CMD_SET_PERIOD: + return drv_pwm_set_period(htim, configuration); + case PWM_CMD_SET_PULSE: + return drv_pwm_set_pulse(htim, configuration); case PWM_CMD_GET: return drv_pwm_get(htim, configuration); default: diff --git a/components/drivers/include/drivers/rt_drv_pwm.h b/components/drivers/include/drivers/rt_drv_pwm.h index 2570887d71..597842be79 100644 --- a/components/drivers/include/drivers/rt_drv_pwm.h +++ b/components/drivers/include/drivers/rt_drv_pwm.h @@ -19,6 +19,8 @@ #define PWM_CMD_GET (RT_DEVICE_CTRL_BASE(PWM) + 3) #define PWMN_CMD_ENABLE (RT_DEVICE_CTRL_BASE(PWM) + 4) #define PWMN_CMD_DISABLE (RT_DEVICE_CTRL_BASE(PWM) + 5) +#define PWM_CMD_SET_PERIOD (RT_DEVICE_CTRL_BASE(PWM) + 6) +#define PWM_CMD_SET_PULSE (RT_DEVICE_CTRL_BASE(PWM) + 7) struct rt_pwm_configuration { @@ -50,5 +52,7 @@ rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel); rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel); rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse); +rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period); +rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse); #endif /* __DRV_PWM_H_INCLUDE__ */ diff --git a/components/drivers/misc/rt_drv_pwm.c b/components/drivers/misc/rt_drv_pwm.c index 64eb613a84..53aaad8223 100644 --- a/components/drivers/misc/rt_drv_pwm.c +++ b/components/drivers/misc/rt_drv_pwm.c @@ -177,6 +177,40 @@ rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t perio return result; } +rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period) +{ + rt_err_t result = RT_EOK; + struct rt_pwm_configuration configuration = {0}; + + if (!device) + { + return -RT_EIO; + } + + configuration.channel = channel; + configuration.period = period; + result = rt_device_control(&device->parent, PWM_CMD_SET_PERIOD, &configuration); + + return result; +} + +rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse) +{ + rt_err_t result = RT_EOK; + struct rt_pwm_configuration configuration = {0}; + + if (!device) + { + return -RT_EIO; + } + + configuration.channel = channel; + configuration.pulse = pulse; + result = rt_device_control(&device->parent, PWM_CMD_SET_PULSE, &configuration); + + return result; +} + rt_err_t rt_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *cfg) { rt_err_t result = RT_EOK;