Add fuction to set timer frequency.

This commit is contained in:
Daniel P. Carvalho 2020-11-05 09:50:15 -03:00 committed by Alan Carvalho de Assis
parent 3f6157001a
commit e73e03a33f
3 changed files with 173 additions and 16 deletions

View File

@ -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
************************************************************************************/

View File

@ -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);
};

View File

@ -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 */