From 435f7a416d4962564584c79004679fa73a2c23a4 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Sat, 15 Apr 2023 09:58:06 +0200 Subject: [PATCH] Basic driver to configure STM32F4 timers as perioric update sources. --- platform/mcu/STM32F4xx/drivers/Timer.hpp | 147 +++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 platform/mcu/STM32F4xx/drivers/Timer.hpp diff --git a/platform/mcu/STM32F4xx/drivers/Timer.hpp b/platform/mcu/STM32F4xx/drivers/Timer.hpp new file mode 100644 index 00000000..25c2d21d --- /dev/null +++ b/platform/mcu/STM32F4xx/drivers/Timer.hpp @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +#include + +/** + * Handler class for STM32F4 Timer peripheral. + */ +class Timer +{ +public: + + /** + * Constructor. + * + * @param tim: base address of timer peripheral to manage. + */ + constexpr Timer(const uint32_t tim) : tim(tim) {} + + ~Timer() = default; + + /** + * Configure timer prescaler and auto-reload registers for a given update + * frequency. + * + * @param busFreq: frequency of the APB bus the timer is attached to, in Hz. + * @param updFreq: desidered update frequency, in Hz. + * @return effective timer update frequency, in Hz. + */ + uint32_t setUpdateFrequency(const uint32_t busFreq, const uint32_t updFreq) const + { + /* + * Timer update frequency is given by: + * Fupd = (Fbus / prescaler) / autoreload + * + * First of all we fix the prescaler to 1 and compute the autoreload: if + * the result is greater than the maximum autoreload value, we proceed + * iteratively. + */ + uint32_t psc = 1; + uint32_t arr = busFreq / updFreq; + while(arr >= 0xFFFF) + { + psc += 1; + arr = (busFreq / psc) / updFreq; + } + + // Values put in registers have to be decremented by one, see RM + reinterpret_cast< TIM_TypeDef * >(tim)->PSC = psc - 1; + reinterpret_cast< TIM_TypeDef * >(tim)->ARR = arr - 1; + reinterpret_cast< TIM_TypeDef * >(tim)->CR2 = TIM_CR2_MMS_1; + + return (busFreq / psc) / arr; + } + + /** + * Configure timer prescaler and auto-reload registers for a given update + * frequency. + * + * @param updFreq: desidered update frequency, in Hz. + * @return effective timer update frequency, in Hz. + */ + uint32_t setUpdateFrequency(const uint32_t updFreq) const + { + /* + * Compute the frequency of the bus the timer is attached to. + * This formula takes into account that if the APB1 clock is divided by + * a factor of two or greater, the timer is clocked at twice the bus + * interface. + */ + uint32_t busFreq = SystemCoreClock; + uint32_t APB = (tim & 0x40010000) >> 16; + uint32_t shift = RCC_CFGR_PPRE1_Pos << (3 * APB); + + if(RCC->CFGR & RCC_CFGR_PPRE1_2) + busFreq /= 1 << ((RCC->CFGR >> shift) & 0x3); + + return setUpdateFrequency(busFreq, updFreq); + } + + /** + * Enable or disable the generation of DMA requests on timer update events. + * + * @param enable: set to true to enable the generation of DMA requests. + */ + inline void enableDmaTrigger(const bool enable) const + { + if(enable) + reinterpret_cast< TIM_TypeDef * >(tim)->DIER = TIM_DIER_UDE; + else + reinterpret_cast< TIM_TypeDef * >(tim)->DIER = 0; + } + + /** + * Clear and start the timer's counter. + */ + inline void start() const + { + reinterpret_cast< TIM_TypeDef * >(tim)->CNT = 0; + reinterpret_cast< TIM_TypeDef * >(tim)->EGR = TIM_EGR_UG; + reinterpret_cast< TIM_TypeDef * >(tim)->CR1 = TIM_CR1_CEN; + } + + /** + * Stop the timer's counter. + */ + inline void stop() const + { + reinterpret_cast< TIM_TypeDef * >(tim)->CR1 = 0; + } + + /** + * Get current value of timer's counter. + * + * @return value of timer's counter. + */ + inline uint16_t value() const + { + return reinterpret_cast< TIM_TypeDef * >(tim)->CNT = 0; + } + +private: + + const uint32_t tim; +}; + +#endif /* TIMER_H */