diff --git a/arch/arm/src/stm32l4/stm32l4_tim.c b/arch/arm/src/stm32l4/stm32l4_tim.c index 2e2d1a6de5..df90591d31 100644 --- a/arch/arm/src/stm32l4/stm32l4_tim.c +++ b/arch/arm/src/stm32l4/stm32l4_tim.c @@ -270,6 +270,8 @@ static void stm32l4_tim_dumpregs(FAR struct stm32l4_tim_dev_s *dev); static int stm32l4_tim_setmode(FAR struct stm32l4_tim_dev_s *dev, enum stm32l4_tim_mode_e mode); +static int stm32l4_tim_setfreq(FAR struct stm32l4_tim_dev_s *dev, + uint32_t freq); static int stm32l4_tim_setclock(FAR struct stm32l4_tim_dev_s *dev, uint32_t freq); static uint32_t stm32l4_tim_getclock(FAR struct stm32l4_tim_dev_s *dev); @@ -298,7 +300,10 @@ static int stm32l4_tim_checkint(FAR struct stm32l4_tim_dev_s *dev, int source); static const struct stm32l4_tim_ops_s stm32l4_tim_ops = { + .enable = stm32l4_tim_enable, + .disable = stm32l4_tim_disable, .setmode = stm32l4_tim_setmode, + .setfreq = stm32l4_tim_setfreq, .setclock = stm32l4_tim_setclock, .getclock = stm32l4_tim_getclock, .setperiod = stm32l4_tim_setperiod, @@ -312,8 +317,6 @@ static const struct stm32l4_tim_ops_s stm32l4_tim_ops = .disableint = stm32l4_tim_disableint, .ackint = stm32l4_tim_ackint, .checkint = stm32l4_tim_checkint, - .enable = stm32l4_tim_enable, - .disable = stm32l4_tim_disable, .dump_regs = stm32l4_tim_dumpregs, }; @@ -689,6 +692,166 @@ static int stm32l4_tim_setmode(FAR struct stm32l4_tim_dev_s *dev, return OK; } +/************************************************************************************ + * Name: stm32l4_tim_setfreq + ************************************************************************************/ + +static int stm32l4_tim_setfreq(FAR struct stm32l4_tim_dev_s *dev, + uint32_t freq) +{ + uint32_t freqin; + int prescaler; + uint32_t reload; + uint32_t timclk; + + DEBUGASSERT(dev != NULL); + + /* Disable Timer? */ + + if (freq == 0) + { + stm32l4_tim_disable(dev); + return 0; + } + + /* Get the input clock frequency for this timer. These vary with + * different timer clock sources, MCU-specific timer configuration, and + * board-specific clock configuration. The correct input clock frequency + * must be defined in the board.h header file. + */ + + switch (((struct stm32l4_tim_priv_s *)dev)->base) + { +#ifdef CONFIG_STM32L4_TIM1 + case STM32L4_TIM1_BASE: + freqin = BOARD_TIM1_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM2 + case STM32L4_TIM2_BASE: + freqin = BOARD_TIM2_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM3 + case STM32L4_TIM3_BASE: + freqin = BOARD_TIM3_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM4 + case STM32L4_TIM4_BASE: + freqin = BOARD_TIM4_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM5 + case STM32L4_TIM5_BASE: + freqin = BOARD_TIM5_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM6 + case STM32L4_TIM6_BASE: + freqin = BOARD_TIM6_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM7 + case STM32L4_TIM7_BASE: + freqin = BOARD_TIM7_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM8 + case STM32L4_TIM8_BASE: + freqin = BOARD_TIM8_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM15 + case STM32L4_TIM15_BASE: + freqin = BOARD_TIM15_FREQUENCY; + break; +#endif +#ifdef CONFIG_STM32L4_TIM16 + case STM32L4_TIM16_BASE: + freqin = BOARD_TIM16_FREQUENCY; + break; +#endif + +#ifdef CONFIG_STM32L4_TIM17 + case STM32L4_TIM17_BASE: + freqin = BOARD_TIM17_FREQUENCY; + break; +#endif + + default: + return -EINVAL; + } + + /* Select a pre-scaler value for this timer using the input clock frequency. + * + * Calculate optimal values for the timer prescaler and for the timer + * reload register. If freq is the desired frequency, then + * + * reload = timclk / freq + * reload = (pclck / prescaler) / freq + * + * There are many solutions to do this, but the best solution will be the + * one that has the largest reload value and the smallest prescaler value. + * That is the solution that should give us the most accuracy in the timer + * control. Subject to: + * + * 0 <= prescaler <= 65536 + * 1 <= reload <= 65535 + * + * So ( prescaler = pclck / 65535 / freq ) would be optimal. + */ + + prescaler = (freqin / freq + 65534) / 65535; + + /* We need to decrement value for '1', but only if that will not to + * cause underflow. + */ + + if (prescaler < 1) + { + awarn("WARNING: Prescaler underflowed.\n"); + prescaler = 1; + } + + /* Check for overflow as well. */ + + if (prescaler > 65536) + { + awarn("WARNING: Prescaler overflowed.\n"); + prescaler = 65536; + } + + timclk = freqin / prescaler; + + reload = timclk / freq; + if (reload < 1) + { + awarn("WARNING: Reload value underflowed.\n"); + reload = 1; + } + else if (reload > 65535) + { + awarn("WARNING: Reload value overflowed.\n"); + reload = 65535; + } + + /* Set the reload and prescaler values */ + + stm32l4_putreg16(dev, STM32L4_GTIM_PSC_OFFSET, prescaler - 1); + stm32l4_putreg16(dev, STM32L4_GTIM_ARR_OFFSET, reload); + + return (timclk / reload); +} + /************************************************************************************ * Name: stm32l4_tim_setclock ************************************************************************************/ diff --git a/arch/arm/src/stm32l4/stm32l4_tim.h b/arch/arm/src/stm32l4/stm32l4_tim.h index d69b9a7511..79212ea863 100644 --- a/arch/arm/src/stm32l4/stm32l4_tim.h +++ b/arch/arm/src/stm32l4/stm32l4_tim.h @@ -58,6 +58,7 @@ /* Helpers *******************************************************************/ #define STM32L4_TIM_SETMODE(d,mode) ((d)->ops->setmode(d,mode)) +#define STM32L4_TIM_SETFREQ(d,freq) ((d)->ops->setfreq(d,freq)) #define STM32L4_TIM_SETCLOCK(d,freq) ((d)->ops->setclock(d,freq)) #define STM32L4_TIM_GETCLOCK(d) ((d)->ops->getclock(d)) #define STM32L4_TIM_SETPERIOD(d,period) ((d)->ops->setperiod(d,period)) @@ -173,8 +174,11 @@ struct stm32l4_tim_ops_s { /* Basic Timers */ + void (*enable)(FAR struct stm32l4_tim_dev_s *dev); + void (*disable)(FAR struct stm32l4_tim_dev_s *dev); int (*setmode)(FAR struct stm32l4_tim_dev_s *dev, enum stm32l4_tim_mode_e mode); + int (*setfreq)(FAR struct stm32l4_tim_dev_s *dev, uint32_t freq); int (*setclock)(FAR struct stm32l4_tim_dev_s *dev, uint32_t freq); uint32_t (*getclock)(FAR struct stm32l4_tim_dev_s *dev); void (*setperiod)(FAR struct stm32l4_tim_dev_s *dev, uint32_t period); @@ -197,8 +201,9 @@ struct stm32l4_tim_ops_s void (*disableint)(FAR struct stm32l4_tim_dev_s *dev, int source); void (*ackint)(FAR struct stm32l4_tim_dev_s *dev, int source); int (*checkint)(FAR struct stm32l4_tim_dev_s *dev, int source); - void (*enable)(FAR struct stm32l4_tim_dev_s *dev); - void (*disable)(FAR struct stm32l4_tim_dev_s *dev); + + /* Debug */ + void (*dump_regs)(FAR struct stm32l4_tim_dev_s *dev); }; diff --git a/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c b/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c index 5ec2d25139..d3002079c3 100644 --- a/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c +++ b/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c @@ -359,7 +359,6 @@ static int spwm_tim6_setup(FAR struct spwm_s *spwm) { FAR struct stm32l4_tim_dev_s *tim = NULL; uint64_t freq = 0; - uint32_t per = 0; int ret = OK; /* Get TIM6 interface */ @@ -380,18 +379,8 @@ static int spwm_tim6_setup(FAR struct spwm_s *spwm) */ freq = spwm->samples * spwm->waveform_freq; - per = BOARD_TIM6_FREQUENCY / freq; - if (per > 0xffff) - { - printf("ERROR: can not achieve TIM6 frequency\n"); - ret = -1; - goto errout; - } - /* TODO: TIM_SETFREQ */ - - STM32L4_TIM_SETCLOCK(tim, BOARD_TIM6_FREQUENCY); - STM32L4_TIM_SETPERIOD(tim, per); + STM32L4_TIM_SETFREQ(tim, freq); STM32L4_TIM_ENABLE(tim); /* Attach TIM6 ram vector */