diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f2727291..a59b80474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,8 @@ if(COMPDEFS MATCHES "(.*)STM32F3xx(.*)") src/core/io/platform/f3xx/UARTf3xx.cpp src/core/io/platform/f3xx/SPIf3xx.cpp src/core/dev/platform/f3xx/IWDGf3xx.cpp - src/core/dev/platform/f3xx/RTCf3xx.cpp) + src/core/dev/platform/f3xx/RTCf3xx.cpp + ) elseif(COMPDEFS MATCHES "(.*)STM32F4xx(.*)") target_sources(${PROJECT_NAME} PRIVATE src/core/utils/platform/f4xx/timef4xx.cpp diff --git a/include/core/dev/MCUTimer.hpp b/include/core/dev/MCUTimer.hpp index e61e0ceba..83c01c7aa 100644 --- a/include/core/dev/MCUTimer.hpp +++ b/include/core/dev/MCUTimer.hpp @@ -9,7 +9,6 @@ #endif namespace core::dev { - /** * Enum for all the hardware timers available on the current MCU */ @@ -17,7 +16,6 @@ enum class MCUTimer { #if defined(STM32F302x8) Timer1, Timer2, - Timer6, Timer15, Timer16, Timer17, @@ -25,16 +23,16 @@ enum class MCUTimer { Timer1, Timer2, Timer3, - Timer6, - Timer7, Timer15, Timer16, Timer17, #elif defined(STM32F446xx) + Timer1, Timer2, Timer3, Timer4, Timer5, + Timer8, Timer9, Timer10, Timer11, @@ -42,15 +40,22 @@ enum class MCUTimer { Timer13, Timer14, #endif + None }; /** * Gets the corresponding HAL TIM_TypeDef* for each MCUTimer + * This function is inlined because of a couple of reasons. + * 1. It is in a header file, and functions in header files should be inlined. + * https://clang.llvm.org/extra/clang-tidy/checks/misc/definitions-in-headers.html + * 2. When this function is not inlined, F3 targets will not build. This is because PWMF3xx requires its own + * `timerInstance` function that requires an MCUTimer import. Since manager.hpp also includes MCUTimer.hpp, and has + * generally broken imports (see [FWT-255] https://rit-evt.atlassian.net/browse/FWT-255). * * @param mcuTimer MCUTimer of which to get the HAL equivalent * @return HAL equivalent of mcuTimer */ -TIM_TypeDef* getTIM(MCUTimer mcuTimer) { +inline TIM_TypeDef* getTIM(const MCUTimer mcuTimer) { TIM_TypeDef* timPeriph; switch (mcuTimer) { #if defined(STM32F302x8) @@ -60,9 +65,6 @@ TIM_TypeDef* getTIM(MCUTimer mcuTimer) { case MCUTimer::Timer2: timPeriph = TIM2; break; - case MCUTimer::Timer6: - timPeriph = TIM6; - break; case MCUTimer::Timer15: timPeriph = TIM15; break; @@ -72,6 +74,9 @@ TIM_TypeDef* getTIM(MCUTimer mcuTimer) { case MCUTimer::Timer17: timPeriph = TIM17; break; + default: + timPeriph = TIM1; + break; #elif defined(STM32F334x8) case MCUTimer::Timer1: timPeriph = TIM1; @@ -82,12 +87,6 @@ TIM_TypeDef* getTIM(MCUTimer mcuTimer) { case MCUTimer::Timer3: timPeriph = TIM3; break; - case MCUTimer::Timer6: - timPeriph = TIM6; - break; - case MCUTimer::Timer7: - timPeriph = TIM7; - break; case MCUTimer::Timer15: timPeriph = TIM15; break; @@ -97,11 +96,13 @@ TIM_TypeDef* getTIM(MCUTimer mcuTimer) { case MCUTimer::Timer17: timPeriph = TIM17; break; + default: + timPeriph = TIM1; + break; #elif defined(STM32F446xx) - /* - * Timers 1 and 8 are advanced timers - * so they are not included in this switch statement - */ + case MCUTimer::Timer1: + timPeriph = TIM1; + break; case MCUTimer::Timer2: timPeriph = TIM2; break; @@ -114,6 +115,9 @@ TIM_TypeDef* getTIM(MCUTimer mcuTimer) { case MCUTimer::Timer5: timPeriph = TIM5; break; + case MCUTimer::Timer8: + timPeriph = TIM8; + break; case MCUTimer::Timer9: timPeriph = TIM9; break; @@ -132,6 +136,9 @@ TIM_TypeDef* getTIM(MCUTimer mcuTimer) { case MCUTimer::Timer14: timPeriph = TIM14; break; + default: + timPeriph = TIM1; + break; #endif } diff --git a/include/core/dev/RTCTimer.hpp b/include/core/dev/RTCTimer.hpp index 82c7f6674..0841d408a 100644 --- a/include/core/dev/RTCTimer.hpp +++ b/include/core/dev/RTCTimer.hpp @@ -17,7 +17,7 @@ class RTCTimer : public Timer { * * @param r */ - RTCTimer(RTC& r); + explicit RTCTimer(RTC& r); /** * Create instance of RTCTimer. @@ -31,8 +31,9 @@ class RTCTimer : public Timer { * not implemented. * * @param[in] irqHandler The IRQ Handler function pointer. Sets a new interrupt handler function + * @param[in] context The context used by the irqHandler. */ - void startTimer(void (*irqHandler)(void* htim)) override {} + void startTimer(void (*irqHandler)(void* context, void* htim), void* context) override {} void startTimer() override; @@ -40,40 +41,47 @@ class RTCTimer : public Timer { void reloadTimer() override; - void setPeriod(uint32_t clock) override; + /** + * Set the period for PWM. + * Note: This does not match the dev::Timer set period, since the RTCTimer does not accept a different period. + * This function will hide the definition from the superclass. So you can safely ignore the warning. + * @param[in] period The period for the RTC timer. + * @param[in] clockPrescaler UNUSED DO NOT SET. + */ + void setPeriod(uint32_t period, uint32_t clockPrescaler = AUTO_PRESCALER); /** * Gets the time since the RTC clock began in seconds * * @return the time since the RTC clock began */ - uint32_t getTime(); + [[nodiscard]] uint32_t getTime() const; /** * Gets whether the timer has gone off * * @return whether the time has gone off */ - bool hasGoneOff(); + [[nodiscard]] bool hasGoneOff() const; private: /** Instance of on-board*/ RTC& rtc; /** - * The amount of seconds that have elapsed while the timer is running. + * The number of seconds that have elapsed while the timer is running. * Only updates when stopTimer() is called. */ - uint32_t time; + uint32_t time = 0; /** The amount of time it takes the timer to go off in SECONDS */ - uint32_t clockPeriod; + uint32_t clockPeriod = 0; /** The epoc time the clock started */ - uint32_t startTime; + uint32_t startTime = 0; /** true if timer has been stopped */ - bool bTimerStopped; + bool bTimerStopped = true; }; } // namespace core::dev diff --git a/include/core/dev/Timer.hpp b/include/core/dev/Timer.hpp index d71554e61..02eac07bc 100644 --- a/include/core/dev/Timer.hpp +++ b/include/core/dev/Timer.hpp @@ -3,19 +3,29 @@ #include -namespace core::dev { - /** - * This class will represent an internal general purpose timer device for the STM32. - * It is capable of triggering interrupts with a given frequency + * If AUTO_PRESCALER is sent as a prescaler the timer will calculate its own Prescaler in the setPeriod function. + * The automatic prescaler is calculated by dividing the system clock speed by 1000, then subtracting 1. + * + * Yes, this is a negative in an uint32_t, but it ends up just causing an underflow, and making it the max of an + * uint32_t. */ +#define AUTO_PRESCALER uint32_t(-1) + +namespace core::dev { class Timer { public: + /** + * Virtual destructor required by C++. + */ + virtual ~Timer() = default; + /** * Starts the given timer and registers the given interrupt pointer to trigger when the timer overflows * @param[in] irqHandler The IRQ Handler function pointer. Sets a new interrupt handler function + * @param[in] context The context to be sent to the irqHandler when it is called. */ - virtual void startTimer(void (*irqHandler)(void* htim)) = 0; + virtual void startTimer(void (*irqHandler)(void* context, void* htim), void* context) = 0; /** * Starts the given timer using the IRQ Handler already assigned to that timer. @@ -36,11 +46,14 @@ class Timer { * Set the clock period for the timer. Will stop the timer, re-initialize the device with the updated period. * You must call startTimer again to continue timer operation. * - * @param[in] clockPeriod the clock period in ms. An interrupt will be triggered at that frequency. + * @param[in] clockPeriod the clock period in ticks (ms when using AUTO_PRESCALER). An interrupt will be triggered + * at that frequency. + * @param [in] clockPrescaler the prescaler used by the timer. Divides the system clock frequency to get it within + * an acceptable range for use with the required period. If set to @ref AUTO_PRESCALER, the function implementation + * will calculate its own prescaler. */ - virtual void setPeriod(uint32_t clockPeriod) = 0; + virtual void setPeriod(uint32_t clockPeriod, uint32_t clockPrescaler = AUTO_PRESCALER) = 0; }; - } // namespace core::dev #endif // EVT_TIMER_HPP diff --git a/include/core/dev/TimerTypes.hpp b/include/core/dev/TimerTypes.hpp new file mode 100644 index 000000000..3482b25af --- /dev/null +++ b/include/core/dev/TimerTypes.hpp @@ -0,0 +1,302 @@ +/** + * @brief This file contains all the types used by timers in EVT-Core. + * + * @details + * This file contains type definitions for the timer configuration structure, and support enums. + * + * TimerConfiguration_t is a configuration structure that timers use to set themselves up. + * + * The enums TimerCounterMode, TimerClockDivision, TimerAutoReloadPreload, TimerClockSource, + * TimerMasterModeSelection, and TimerMasterSlaveMode, are user facing declarations of HAL definitions + * used by TimerConfiguration_t structs. + * + * This file has one oddity, the HAL for supported boards (F3 & fF4) is included to give access to definitions used + * in the enums. Importing these into this file was chosen, instead of two separate F3 & F4 files, because there are + * no differences in the definition names, or supported values between the boards. This file is also NOT included + * into Timer.hpp to reduce the footprint of HAL includes. + */ + +#ifndef EVT_TIMERTYPES_HPP +#define EVT_TIMERTYPES_HPP + +#ifdef STM32F3xx + #include +#endif + +#ifdef STM32F4xx + #include +#endif + +namespace core::dev { +/** + * @brief Timer Counter Mode, analogous to TIM_Counter_Mode. + * @details + * Mirrors the definitions that are grouped under TIM_Counter_Mode. Adds extra documentation & easier use. + */ +enum class TimerCounterMode { + /** The timer's counter counts up from 0 to the period */ + UP = TIM_COUNTERMODE_UP, + /** The timer's counter counts down from the period to 0. */ + DOWN = TIM_COUNTERMODE_DOWN, + /** + * @brief Center-aligned mode 1, used for PWM. + * @details + * Behavior: The interrupt flags for triggers (Update & Capture/Compare) are only set when the counter is counting + * **down**. Compare Event: When the counter matches the CCR value while counting down. + */ + CENTRAL_ALIGNED_1 = TIM_COUNTERMODE_CENTERALIGNED1, + /** + * @brief Center-aligned mode 2, used for PWM. + * @details + * Behavior: The interrupt flags for triggers (Update & Capture/Compare) are only set when the counter is counting + * **up**. Compare Event: When the counter matches the CCR value while counting up. + */ + CENTRAL_ALIGNED_2 = TIM_COUNTERMODE_CENTERALIGNED2, + /** + * @brief Center-aligned mode 3, used for PWM. + * @details + * Behavior: The interrupt flags for triggers (Update & Capture/Compare) are set when the counter is counting **up** + * and counting **down** Compare Event: When the counter matches the CCR value while counting up and down. The event + * will occur twice per PWM period. + */ + CENTRAL_ALIGNED_3 = TIM_COUNTERMODE_CENTERALIGNED3, +}; + +/** + * @brief Timer Clock Division, indicates the clock division ratio. + * @details + * The elements of this enum are used in the clock division bit field. They indicate the division ratio between + * the timer clock (CK_INT) frequency and the dead-time. The dead-time is used by the sample clock (tDTS), + * dead-time generators, and the digital filters (ETR, TIx) + */ +enum class TimerClockDivision { + /** + * @brief Clock division: tDTS=tCK_INT + * @details + * The sample clock frequency (tDTS) = Timer clock (CK_INT) frequency + */ + DIVISION_1 = TIM_CLOCKDIVISION_DIV1, + /** + * @brief Clock division: tDTS=2*tCK_INT + * @details + * The sample clock frequency (tDTS) = 2 * Timer clock (CK_INT) frequency + * 2x `DIVISION_1` + */ + DIVISION_2 = TIM_CLOCKDIVISION_DIV2, + /** + * @brief Clock division: tDTS=4*tCK_INT + * @details + * The sample clock frequency (tDTS) = 4 * Timer clock (CK_INT) frequency + * 4x `DIVISION_1` + */ + DIVISION_4 = TIM_CLOCKDIVISION_DIV4, +}; + +/** + * @brief Indicates whether the Auto Preload Reload register is buffed + */ +enum class TimerAutoReloadPreload { + /** Timer auto reload preload register is not buffered */ + NO_BUFFER = TIM_AUTORELOAD_PRELOAD_DISABLE, + /** Timer auto reload preload register is buffered */ + BUFFER = TIM_AUTORELOAD_PRELOAD_ENABLE, +}; + +/** + * @brief Tells the timer what source will initiate a clock. + * @details + * Clock sources define when a timer will receive a clock. This can be either an internal or external clock source. + * External clock sources have many options for configuring when an external signal will actually tigger a clock. + * Note: Many of these cases need more research. Particularly the external sources, as online information is limited. + * If you need to use one of these, fallback to the reference document for the MCU you are using (Please update this + * with more info) + */ +enum class TimerClockSource { + /** + * @brief Internal clock source + * @details + * The standard setting for timers. This will trigger the timer clock based on the STM32's internal clock. + */ + INTERNAL = TIM_CLOCKSOURCE_INTERNAL, + /** + * @brief External Clock Source, Mode 1 (ITR0) + * @details + * The timer's clock source is synchronized to Interrupt 0. This can be used to synchronize multiple timers + * together. Please see the Timer synchronization section of the Microcontroller Reference Document for more + * information. + */ + EXTERNAL_MODE_1_ITR0 = TIM_CLOCKSOURCE_ITR0, + /** + * @brief External Clock Source, Mode 1 (ITR1) + * @details + * The timer's clock source is synchronized to Interrupt 1. This can be used to synchronize multiple timers + * together. Please see the Timer synchronization section of the Microcontroller Reference Document for more + * information. + */ + EXTERNAL_MODE_1_ITR1 = TIM_CLOCKSOURCE_ITR1, + /** + * @brief External Clock Source, Mode 1 (ITR2) + * @details + * The timer's clock source is synchronized to Interrupt 2. This can be used to synchronize multiple timers + * together. Please see the Timer synchronization section of the Microcontroller Reference Document for more + * information. + */ + EXTERNAL_MODE_1_ITR2 = TIM_CLOCKSOURCE_ITR2, + /** + * @brief External Clock Source, Mode 1 (ITR3) + * @details + * The timer's clock source is synchronized to Interrupt 3. This can be used to synchronize multiple timers + * together. Please see the Timer synchronization section of the Microcontroller Reference Document for more + * information. + */ + EXTERNAL_MODE_1_ITR3 = TIM_CLOCKSOURCE_ITR3, + /** + * @brief External Clock Source, Mode 1 (TTI1FP1 + edge detect) + * @details + * The clock source comes from Filtered Timer Input 1. This should be used if the timer needs to be triggered + * on the rising or falling edge of a signal. + */ + EXTERNAL_MODE_1_TTI1FP1_ED = TIM_CLOCKSOURCE_TI1ED, + /** + * @brief External Clock Source, Mode 1 (TTI1FP1) + * @details + * The clock source comes from Filtered Timer Input 1. + * Note: More information needed + */ + EXTERNAL_MODE_1_TTI1FP1 = TIM_CLOCKSOURCE_TI1, + /** + * @brief External Clock Source, Mode 1 (TTI2FP2) + * @details + * The clock source comes from Filtered Timer Input 2. + * Note: More information needed + */ + EXTERNAL_MODE_1_TTI2FP2 = TIM_CLOCKSOURCE_TI2, + /** + * @brief External Clock Source, Mode 1 (ETRF) + * @details + * The clock source comes from the ETRF trigger / signal. + * Note: More information needed + */ + EXTERNAL_MODE_1_ETRF = TIM_CLOCKSOURCE_ETRMODE1, + /** + * @brief External Clock source mode 2 + * @details + * The timer receives a clock whenever there is an active edge on the ETRF trigger / signal. + * Note: More information needed + */ + EXTERNAL_MODE_2 = TIM_CLOCKSOURCE_ETRMODE2 +}; + +/** + * @brief Controls what signals a timer outputs to timers configured as slaves. + * @details + * Defines how the Master in a master / slave timer relationship should function. Master mode timers can reset, start, + * stop, or clock the counter of another timer configured in Slave Mode. + * Note: Trigger outputs are only affected when TimerMasterSlaveMode is set to ENABLE. + */ +enum class TimerMasterModeSelection { + /** + * @brief Sends a RESET signal to slave timers. + * @details + * The TIMx_EGR.UG bit is used as the trigger output (TRGO), which sends the RESET signal to + * any configured slave timers. + */ + RESET = TIM_TRGO_RESET, + /** + * @brief Sends an ENABLE signal to slave timers. + * @details + * The TIMx_CR1.CEN bit is used as the trigger output (TRGO), which sends the ENABLE signal to + * any configured slave timers. + */ + ENABLE = TIM_TRGO_ENABLE, + /** + * @breif Sends an Update event to slave timers. + */ + UPDATE = TIM_TRGO_UPDATE, + /** + * @brief Capture or a compare match 1 is used as trigger output (TRGO) + */ + OC1 = TIM_TRGO_OC1, + /** + * @brief OC1REF signal is used as trigger output (TRGO) + */ + OC1REF = TIM_TRGO_OC1REF, + /** + * @brief OC2REF signal is used as trigger output (TRGO) + */ + OC2REF = TIM_TRGO_OC2REF, + /** + * @brief OC3REF signal is used as trigger output (TRGO) + */ + OC3REF = TIM_TRGO_OC3REF, + /** + * @brief C4REF signal is used as trigger output (TRGO) + */ + OC4REF = TIM_TRGO_OC4REF, +}; + +/** + * @brief Allows a timer to control another set of timers. + * @details + * When one timer is configured in Master Mode, it can reset, start, stop, or clock the counter of another timer + * configured in Slave Mode. Timers can be chained together through the combination of TimerMasterModeSelection and + * TimerClockSource options. Master / Slave configurations are dependent on the MCU, so it is important to check the + * Reference Document for the MCU you are using. + */ +enum class TimerMasterSlaveMode { + /** + * @brief The Master/Slave mode is enabled. + * @details + * This timer will control other timers that are enabled to listen to TimerMasterModeSelection trigger output as + * their clock source. + */ + ENABLE = TIM_MASTERSLAVEMODE_ENABLE, + /** The Master/Slave mode is disabled. */ + DISABLE = TIM_MASTERSLAVEMODE_DISABLE, +}; + +/** + * @brief A timer configuration provides a timer with all configuration variables needed to be set up.. + * @details + * + */ +typedef struct { + /** + * Specifies how the timer will count. + * Maps to a timer's @ref TIM_Base_InitTypeDef:CounterMode + */ + TimerCounterMode counterMode{}; + + /** + * Specifies the clock division. + * Maps to a timer's @ref TIM_Base_InitTypeDef:ClockDivision + */ + TimerClockDivision clockDivision{}; + + /** + * Specifies the auto reload preload value, which controls whether @ref TIMx_ARR is buffered or not. + * Maps to a timer's @ref TIM_Base_InitTypeDef:AutoReloadPreload + */ + TimerAutoReloadPreload autoReloadPreload{}; + + /** + * Timer clock source + * Maps to @ref TIM_ClockConfigTypeDef:ClockSource + */ + TimerClockSource clockSource{}; + + /** + * Trigger output (TRGO) selection. + * Maps to @ref TIM_MasterConfigTypeDef:MasterOutputTrigger + */ + TimerMasterModeSelection masterOutputTrigger{}; + + /** + * Master/slave mode selection. + * This parameter can be a value of @ref TIM_Master_Slave_Mode + * Maps to @ref TIM_MasterConfigTypeDef:MasterSlaveMode + */ + TimerMasterSlaveMode masterSlaveMode{}; +} TimerConfiguration_t; +} // namespace core::dev +#endif // EVT_TIMERTYPES_HPP diff --git a/include/core/dev/platform/f3xx/Timerf3xx.hpp b/include/core/dev/platform/f3xx/Timerf3xx.hpp index 1a94e04dd..165fb8ef3 100644 --- a/include/core/dev/platform/f3xx/Timerf3xx.hpp +++ b/include/core/dev/platform/f3xx/Timerf3xx.hpp @@ -6,50 +6,86 @@ #include #include +#include namespace core::dev { /** - * Implementation of the Timer class for STM32f3xx MCUs + * Concrete implementation of the Timer class for STM32f3xx MCUs. */ -class Timerf3xx : public Timer { +class TimerF3xx : public Timer { public: + /** + * The default configuration for an F3 timer. + */ + static constexpr TimerConfiguration_t defaultConfig = {TimerCounterMode::UP, + TimerClockDivision::DIVISION_1, + TimerAutoReloadPreload::BUFFER, + TimerClockSource::INTERNAL, + TimerMasterModeSelection::RESET, + TimerMasterSlaveMode::DISABLE}; /** * Will initialize the timer device on the STM with the given period and the given IRQ Handler * that triggers with the given period. Starts the timer - * @param timerPeripheral[in] The timer peripheral to configure. Possible options for this board are - * TIM2, TIM15, TIM16, TIM17. It is up to the user to verify that resource conflicts - * do not occur. * + * @param timerPeripheral[in] The timer peripheral to configure. It is up to the user to verify that resource + * conflicts do not occur. F334 Valid Options: TIM1, TIM2, TIM3, TIM15, TIM16, TIM17. F3O2 Valid Options: TIM1, + * TIM2, TIM15, TIM16, TIM17. * @param[in] timerPeripheral The timer to use - * @param[in] clockPeriod the clock period in ms. An interrupt will be triggered at that frequency. + * @param[in] clockPeriod The clock period in ticks (ms when using AUTO_PRESCALER). An interrupt will be triggered + * at this frequency. + * @param[in] configuration The configuration tells the timer how to configure itself. Defaults to @ref + * TimerF3xx::defaultConfig. + * @param[in] clockPrescaler The prescaler that the clock will use. If clockPrescaler is set to @ref AUTO_PRESCALER, + * this function will calculate its own prescaler value. */ - explicit Timerf3xx(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod); + explicit TimerF3xx(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod, + const TimerConfiguration_t& configuration = defaultConfig, + uint32_t clockPrescaler = AUTO_PRESCALER); - void startTimer(void (*irqHandler)(void* htim)) override; + /** @inheritDoc */ + void startTimer(void (*irqHandler)(void* context, void* htim), void* context) override; + /** @inheritDoc */ void startTimer() override; + /** @inheritDoc */ void stopTimer() override; + /** @inheritDoc */ void reloadTimer() override; - void setPeriod(uint32_t clockPeriod) override; + /** @inheritDoc */ + void setPeriod(uint32_t clockPeriod, uint32_t clockPrescaler = AUTO_PRESCALER) override; -private: - // Pointer to the halTimer struct stored in the global array in Timerf3xx.cpp +protected: + /** + * Pointer to the halTimer struct stored in the global array in Timerf4xx.cpp + */ TIM_HandleTypeDef* halTimer; - // Timer clock period - uint32_t clockPeriod; + /** + * Timer clock period + */ + uint32_t clockPeriod{}; + + /** + * The configuration that this timer will use. + */ + TimerConfiguration_t configuration; /** * Handles the initialization of the timer module. Actually configures the device and enables it. - * @param[in] timerPeripheral The timer peripheral to configure. Possible options for this board are - * TIM2, TIM15, TIM16, TIM17. It is up to the user to verify that resource conflicts do not occur. - * @param[in] clockPeriod the clock period in ms. An interrupt will be triggered at that frequency. + * + * @param timerPeripheral[in] The timer peripheral to configure. It is up to the user to verify that resource + * conflicts do not occur. F334 Valid Options: TIM1, TIM2, TIM3, TIM15, TIM16, TIM17. F3O2 Valid Options: TIM1, + * TIM2, TIM15, TIM16, TIM17. + * @param[in] clockPeriod the clock period in ticks (ms when using AUTO_PRESCALER). An interrupt will be triggered + * at that frequency. + * @param[in] clockPrescaler the prescaler that the clock will use. If clockPrescaler is set to @ref AUTO_PRESCALER, + * this function will calculate its own prescaler value. */ - void initTimer(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod); + void initTimer(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod, uint32_t clockPrescaler); }; } // namespace core::dev diff --git a/include/core/dev/platform/f4xx/Timerf4xx.hpp b/include/core/dev/platform/f4xx/Timerf4xx.hpp index 242c1c575..5e5ab886a 100644 --- a/include/core/dev/platform/f4xx/Timerf4xx.hpp +++ b/include/core/dev/platform/f4xx/Timerf4xx.hpp @@ -6,50 +6,88 @@ #include #include +#include namespace core::dev { /** - * Implementation of the Timer class for STM32f4xx MCUs + * Concrete implementation of the Timer class for STM32f4xx MCUs. */ -class Timerf4xx : public Timer { +class TimerF4xx final : public Timer { public: + /** + * A default configuration for an F4 timer. + */ + static constexpr TimerConfiguration_t defaultConfig = {TimerCounterMode::UP, + TimerClockDivision::DIVISION_1, + TimerAutoReloadPreload::BUFFER, + TimerClockSource::INTERNAL, + TimerMasterModeSelection::RESET, + TimerMasterSlaveMode::DISABLE}; + + ~TimerF4xx() override; + /** * Will initialize the timer device on the STM with the given period and the given IRQ Handler - * that triggers with the given period. - * @param timerPeripheral[in] The timer peripheral to configure. It is up to the user to verify - * that resource conflicts do not occur. + * that triggers with the given period. Starts the timer * - * @param[in] timerPeripheral The timer to use - * @param[in] clockPeriod the clock period in ms. An interrupt will be triggered at that frequency. + * @param timerPeripheral[in] The timer peripheral to configure. It is up to the user to verify that resource + * conflicts do not occur. F446xx Valid Options: TIM1, TIM2, TIM3, TIM4, TIM5, TIM8, TIM9, TIM10, TIM11, TIM12, + * TIM13, TIM14. + * @param[in] timerPeripheral the timer peripheral to use. + * @param[in] clockPeriod the clock period in ticks (ms when using AUTO_PRESCALER). An interrupt will be triggered + * at this frequency. + * @param[in] configuration the configuration tells the timer how to configure itself. Defaults to @ref + * TimerF4xx::defaultConfig. + * @param[in] clockPrescaler the prescaler that the clock will use. If clockPrescaler is set to @ref AUTO_PRESCALER, + * this function will calculate its own prescaler value. */ - explicit Timerf4xx(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod); + explicit TimerF4xx(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod, + const TimerConfiguration_t& configuration = defaultConfig, + uint32_t clockPrescaler = AUTO_PRESCALER); - void startTimer(void (*irqHandler)(void* htim)) override; + /** @inheritDoc */ + void startTimer(void (*irqHandler)(void* context, void* htim), void* context) override; + /** @inheritDoc */ void startTimer() override; + /** @inheritDoc */ void stopTimer() override; + /** @inheritDoc */ void reloadTimer() override; - void setPeriod(uint32_t clockPeriod) override; + /** @inheritDoc */ + void setPeriod(uint32_t clockPeriod, uint32_t clockPrescaler = AUTO_PRESCALER) override; -private: - // Pointer to the halTimer struct stored in the global array in Timerf4xx.cpp - TIM_HandleTypeDef* halTimer; +protected: + /** + * Pointer to the halTimer struct stored in the global array in Timerf4xx.cpp + */ + TIM_HandleTypeDef* halTimer = {}; - // Timer clock period + /** + * Timer clock period + */ uint32_t clockPeriod; + /** + * The configuration that this timer will use. + */ + TimerConfiguration_t configuration; + /** * Handles the initialization of the timer module. Actually configures the device and enables it. - * @param[in] timerPeripheral The timer peripheral to configure. - * @param[in] clockPeriod the clock period in ms. An interrupt will be triggered at that frequency. + * @param[in] timerPeripheral The timer peripheral to configure. Possible options for this board are + * TIM2, TIM15, TIM16, TIM17. It is up to the user to verify that resource conflicts do not occur. + * @param[in] clockPeriod the clock period in ticks (ms when using AUTO_PRESCALER). An interrupt will be triggered + * at that frequency. + * @param[in] clockPrescaler the prescaler that the clock will use. If clockPrescaler is set to @ref AUTO_PRESCALER, + * this function will calculate its own prescaler value. */ - void initTimer(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod); + void initTimer(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod, uint32_t clockPrescaler); }; - } // namespace core::dev -#endif //_EVT_TIMER4xx_H +#endif //_EVT_TIMER4xx_H \ No newline at end of file diff --git a/include/core/io/PWM.hpp b/include/core/io/PWM.hpp index 41642d44f..5d8c5af8b 100644 --- a/include/core/io/PWM.hpp +++ b/include/core/io/PWM.hpp @@ -6,7 +6,7 @@ namespace core::io { // Forward declarations: -// The diferent pins are hardware specific. Forward declarations to allow +// The different pins are hardware specific. Forward declarations to allow // at compilation time the decision of which pins should be used. enum class Pin; diff --git a/include/core/io/platform/f3xx/PWMf3xx.hpp b/include/core/io/platform/f3xx/PWMf3xx.hpp index c8b5ed8de..aebc259f1 100644 --- a/include/core/io/platform/f3xx/PWMf3xx.hpp +++ b/include/core/io/platform/f3xx/PWMf3xx.hpp @@ -1,38 +1,51 @@ #ifndef _EVT_PWMf3xx_ #define _EVT_PWMf3xx_ -#include - -#include +#include +#include #include -#include namespace core::io { -class PWMf3xx : public PWM { +/** + * @brief A PWM instance for F3xx family STM32s + * + * A subclass of both @ref PWM and @ref TimerF3xx. Since PWM on the F3 requires its own instance of a timer, a subclass + * is used instead of an internal timer variable. This provides more control over the timer, and is more accurate to + * what PWM is on the F3 (just a timer instance that flips a GPIO pin). + */ +class PWMf3xx : public PWM, public dev::TimerF3xx { public: - /** - * Setup the given pin for PWM usage. - * - * @param pin[in] The pin to setup for PWM - */ - PWMf3xx(Pin pin); + /** @inheritDoc */ + explicit PWMf3xx(Pin pin); - void setDutyCycle(uint32_t dutyCycle); + /** @inheritDoc */ + void setDutyCycle(uint32_t dutyCycle) override; + /** + * @inheritDoc PWM::setPeriod + * This function will hide the definition from the TimerF3xx. So you can safely ignore the warning. + */ void setPeriod(uint32_t period); - uint32_t getDutyCycle(); + /** @inheritDoc */ + uint32_t getDutyCycle() override; - uint32_t getPeriod(); + /** @inheritDoc */ + uint32_t getPeriod() override; private: - /// HAL timer representation - TIM_HandleTypeDef halTIM; - /// Channel identification - uint32_t halTIMChannelID; - /// HAL channel representation - TIM_OC_InitTypeDef halChannel; + static constexpr dev::TimerConfiguration_t defaultConfig = {dev::TimerCounterMode::UP, + dev::TimerClockDivision::DIVISION_1, + dev::TimerAutoReloadPreload::BUFFER, + dev::TimerClockSource::INTERNAL, + dev::TimerMasterModeSelection::RESET, + dev::TimerMasterSlaveMode::DISABLE}; + + /** + * The channel that the timer will run on for this PWM instance + * */ + uint32_t halTIMChannelID{}; }; } // namespace core::io diff --git a/include/core/io/platform/f4xx/ADCf4xx.hpp b/include/core/io/platform/f4xx/ADCf4xx.hpp index 1f06e5674..77ca2ee86 100644 --- a/include/core/io/platform/f4xx/ADCf4xx.hpp +++ b/include/core/io/platform/f4xx/ADCf4xx.hpp @@ -2,8 +2,6 @@ #define _EVT_ADCf4xx_ #include -#include - #include namespace core::io { @@ -48,7 +46,7 @@ class ADCf4xx : public ADC { // Flag to indicate if the timer has been initialized static bool timerInit; // Timer handle for TIM8, used to configure and control the timer instance - static TIM_HandleTypeDef htim8; + static dev::TimerF4xx timer8; /** * Structure to represent the state of an ADC instance. diff --git a/include/core/io/platform/f4xx/PWMf4xx.hpp b/include/core/io/platform/f4xx/PWMf4xx.hpp index 79c5841a2..5adbfa2c0 100644 --- a/include/core/io/platform/f4xx/PWMf4xx.hpp +++ b/include/core/io/platform/f4xx/PWMf4xx.hpp @@ -11,19 +11,19 @@ namespace core::io { class PWMf4xx : public PWM { public: - /** - * Setup the given pin for PWM usage. - * - * @param pin[in] The pin to setup for PWM - */ + /** @inheritDoc */ PWMf4xx(Pin pin); + /** @inheritDoc */ void setDutyCycle(uint32_t dutyCycle) override; + /** @inheritDoc */ void setPeriod(uint32_t period) override; + /** @inheritDoc */ uint32_t getDutyCycle() override; + /** @inheritDoc */ uint32_t getPeriod() override; private: diff --git a/include/core/manager.hpp b/include/core/manager.hpp index fa5676914..10c79d9f3 100644 --- a/include/core/manager.hpp +++ b/include/core/manager.hpp @@ -124,14 +124,32 @@ RTC& getRTC() { #endif #ifdef MCU_SUPPORTED +/** + * A verbose method for getting an EVT-Core timer. This initializer supports a timer configuration object, which allows + * for configuration of the timer. + * + * @tparam mcuTimer The microcontroller timer that the timer will run on. + * @param clockPeriod The clock period to run the timer at + * @param configuration Configuration variables for the timer. + * @return a configured timer object, with the given configuration & clock period. + */ template -Timer& getTimer(uint32_t clockPeriod) { +Timer& getTimer(uint32_t clockPeriod, + // This is a little wonky... we need the correct config so we need to get it from the respective board specific + // class. The only real way to do this, is to use a ifdef and grab the right class. + #ifdef STM32F3xx + TimerConfiguration_t configuration = TimerF3xx::defaultConfig + #endif + #ifdef STM32F4xx + TimerConfiguration_t configuration = TimerF4xx::defaultConfig + #endif +) { #ifdef STM32F3xx - static Timerf3xx timer(getTIM(mcuTimer), clockPeriod); + static TimerF3xx timer(getTIM(mcuTimer), clockPeriod, configuration); return timer; #endif #ifdef STM32F4xx - static Timerf4xx timer(getTIM(mcuTimer), clockPeriod); + static TimerF4xx timer(getTIM(mcuTimer), clockPeriod, configuration); return timer; #endif } diff --git a/libs/HALf3/src/system_stm32f3xx.c b/libs/HALf3/src/system_stm32f3xx.c index 18054e7d9..4181cc710 100644 --- a/libs/HALf3/src/system_stm32f3xx.c +++ b/libs/HALf3/src/system_stm32f3xx.c @@ -164,6 +164,7 @@ void SystemInit(void) /** * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can * be used by the user application to setup the SysTick timer or configure * other parameters. diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 2949ab704..bfb8c9a47 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(rtos) add_subdirectory(thermistor) add_subdirectory(timer) add_subdirectory(spi) +add_subdirectory(timer_configuration) \ No newline at end of file diff --git a/samples/blink/main.cpp b/samples/blink/main.cpp index d93a30229..1d27bcd73 100644 --- a/samples/blink/main.cpp +++ b/samples/blink/main.cpp @@ -12,9 +12,8 @@ #include #include -namespace io = core::io; -namespace dev = core::dev; -namespace time = core::time; +namespace io = core::io; +namespace dev = core::dev; int main() { // Initialize system @@ -30,7 +29,7 @@ int main() { led.toggle(); // Wait half a second - time::wait(500); + core::time::wait(500); } return 0; diff --git a/samples/canopen/canopen_sample/main.cpp b/samples/canopen/canopen_sample/main.cpp index 961736f41..5c470bc78 100644 --- a/samples/canopen/canopen_sample/main.cpp +++ b/samples/canopen/canopen_sample/main.cpp @@ -37,7 +37,7 @@ namespace time = core::time; * NOTE: For this sample, every non-extended (so 11 bit CAN IDs) will be * assumed to be intended to be passed as a CANopen message. * - * @param message[in] The passed in CAN message that was read. + * @param[in] message The passed in CAN message that was read. */ void canInterrupt(io::CANMessage& message, void* priv) { core::types::FixedQueue* queue = diff --git a/samples/canopen/canopen_tpdo/main.cpp b/samples/canopen/canopen_tpdo/main.cpp index 1806f25b0..f03050570 100644 --- a/samples/canopen/canopen_tpdo/main.cpp +++ b/samples/canopen/canopen_tpdo/main.cpp @@ -71,6 +71,7 @@ int main() { // create the TPDO node TPDOCanNode testCanNode; + // Initialize the timer dev::Timer& timer = dev::getTimer(100); /////////////////////////////////////////////////////////////////////////// diff --git a/samples/pwm/main.cpp b/samples/pwm/main.cpp index c3745e0da..c1b096d0b 100644 --- a/samples/pwm/main.cpp +++ b/samples/pwm/main.cpp @@ -2,7 +2,6 @@ * This example shows off a basic PWM signal. You will need to use a logic * analyzer to see the generated square wave. */ -#include #include #include @@ -20,7 +19,7 @@ int main() { pwm.setDutyCycle(50); while (1) { - time::wait(5000); + time::wait(1000); pwm.setDutyCycle(70); time::wait(5000); pwm.setDutyCycle(30); diff --git a/samples/timer/main.cpp b/samples/timer/main.cpp index 1064850ca..832a598de 100644 --- a/samples/timer/main.cpp +++ b/samples/timer/main.cpp @@ -4,21 +4,27 @@ #include #include #include +#include + #include namespace io = core::io; namespace dev = core::dev; +namespace log = core::log; io::GPIO* ledGPIO; io::GPIO* interruptGPIO2Hz; io::GPIO* interruptGPIOStopStart; io::GPIO* reloadGPIO; -void timer2IRQHandler(void* htim) { - io::GPIO::State state = ledGPIO->readPin(); - io::GPIO::State toggleState = state == io::GPIO::State::HIGH ? io::GPIO::State::LOW : io::GPIO::State::HIGH; - ledGPIO->writePin(toggleState); - interruptGPIO2Hz->writePin(toggleState); +void timer2IRQHandler(void* context, void* htim) { + // io::GPIO::State state = ledGPIO->readPin(); + // io::GPIO::State toggleState = state == io::GPIO::State::HIGH ? io::GPIO::State::LOW : io::GPIO::State::HIGH; + // ledGPIO->writePin(toggleState); + // interruptGPIO2Hz->writePin(toggleState); + io::UART* uart = (io::UART*) context; + + uart->printf("Starting log test\n\r"); } void timer15IRQHandler(void* htim) { @@ -33,6 +39,8 @@ void timer16IRQHandler(void* htim) { reloadGPIO->writePin(toggleState); } +namespace log = core::log; + int main() { // Initialize system core::platform::init(); @@ -43,21 +51,36 @@ int main() { interruptGPIOStopStart = &io::getGPIO(io::GPIO::Direction::OUTPUT); reloadGPIO = &io::getGPIO(io::GPIO::Direction::OUTPUT); - // Setup the Timer - dev::Timer& timer2 = dev::getTimer(500); + io::UART& uart = io::getUART(9600); + + // Set up the logger with a UART, logLevel, and clock + // If timestamps aren't needed, don't set the logger's clock + log::LOGGER.setUART(&uart); + log::LOGGER.setLogLevel(log::Logger::LogLevel::INFO); + dev::RTC& rtc = dev::getRTC(); + log::LOGGER.setClock(&rtc); + + // Set up the Timer + dev::Timer& sampleTimer1 = dev::getTimer(1000); + +#ifdef STM32F4xx // F4xx does not support Timers 15 & 16, change them to Timer11 & Timer12 - dev::Timer& timer15 = dev::getTimer(100); - dev::Timer& timer16 = dev::getTimer(200); + dev::Timer& sampleTimer2 = dev::getTimer(200); + dev::Timer& sampleTimer3 = dev::getTimer(200); +#else + // dev::Timer& sampleTimer2 = dev::getTimer(1000); + // dev::Timer& sampleTimer3 = dev::getTimer(1000); +#endif - timer2.startTimer(timer2IRQHandler); - timer15.startTimer(timer15IRQHandler); - timer16.startTimer(timer16IRQHandler); + sampleTimer1.startTimer(timer2IRQHandler, &uart); + // sampleTimer2.startTimer(timer15IRQHandler); + // sampleTimer3.startTimer(timer16IRQHandler); while (1) { - core::time::wait(500); - timer15.stopTimer(); - timer16.reloadTimer(); - core::time::wait(500); - timer15.startTimer(); + // core::time::wait(500); + // sampleTimer2.stopTimer(); + // sampleTimer3.reloadTimer(); + // core::time::wait(500); + // sampleTimer2.startTimer(); } } diff --git a/samples/timer_configuration/CMakeLists.txt b/samples/timer_configuration/CMakeLists.txt new file mode 100644 index 000000000..45a9e7999 --- /dev/null +++ b/samples/timer_configuration/CMakeLists.txt @@ -0,0 +1,3 @@ +include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/evt-core_build.cmake) + +make_exe(timer_configuration main.cpp) diff --git a/samples/timer_configuration/main.cpp b/samples/timer_configuration/main.cpp new file mode 100644 index 000000000..f2c13a203 --- /dev/null +++ b/samples/timer_configuration/main.cpp @@ -0,0 +1,79 @@ +/** + * This sample will demo the the configuration object of a timer. + */ +#include +#include +#include +#include + +namespace io = core::io; +namespace dev = core::dev; + +io::GPIO* ledGPIO; +io::GPIO* interruptGPIO2Hz; +io::GPIO* interruptGPIOStopStart; +io::GPIO* reloadGPIO; + +void timer2IRQHandler(void* htim, void* context) { + io::GPIO::State state = ledGPIO->readPin(); + io::GPIO::State toggleState = state == io::GPIO::State::HIGH ? io::GPIO::State::LOW : io::GPIO::State::HIGH; + ledGPIO->writePin(toggleState); + interruptGPIO2Hz->writePin(toggleState); +} + +void timer15IRQHandler(void* htim, void* context) { + io::GPIO::State state = interruptGPIOStopStart->readPin(); + io::GPIO::State toggleState = state == io::GPIO::State::HIGH ? io::GPIO::State::LOW : io::GPIO::State::HIGH; + interruptGPIOStopStart->writePin(toggleState); +} + +void timer16IRQHandler(void* htim, void* context) { + io::GPIO::State state = reloadGPIO->readPin(); + io::GPIO::State toggleState = state == io::GPIO::State::HIGH ? io::GPIO::State::LOW : io::GPIO::State::HIGH; + reloadGPIO->writePin(toggleState); +} + +int main() { + // Initialize system + core::platform::init(); + + // Setup GPIO + ledGPIO = &io::getGPIO(); + interruptGPIO2Hz = &io::getGPIO(io::GPIO::Direction::OUTPUT); + interruptGPIOStopStart = &io::getGPIO(io::GPIO::Direction::OUTPUT); + reloadGPIO = &io::getGPIO(io::GPIO::Direction::OUTPUT); + + dev::TimerConfiguration_t configuration = { + dev::TimerCounterMode::UP, // Tell the counter to count upwards towards the clock period + dev::TimerClockDivision::DIVISION_1, // Used the default clock division + dev::TimerAutoReloadPreload::BUFFER, // Enables the auto reload preload which makes TIMx_ARR buffered. + dev::TimerClockSource::INTERNAL, // Set the clock source to be the microcontrollers internal clock. + dev::TimerMasterModeSelection::RESET, // Tells the timer to reset whenever it enters a Master / Slave + // configuration. Will not be triggered or used in this configuration. + dev::TimerMasterSlaveMode::DISABLE // Disable Masster Slave Mode for the timer + }; + + // Set up the Timer + dev::Timer& sampleTimer1 = dev::getTimer(1000, configuration); + +#ifdef STM32F4xx + // F4xx does not support Timers 15 & 16, change them to Timer11 & Timer12 + dev::Timer& sampleTimer2 = dev::getTimer(200, configuration); + dev::Timer& sampleTimer3 = dev::getTimer(200, configuration); +#else + dev::Timer& sampleTimer2 = dev::getTimer(1000, configuration); + dev::Timer& sampleTimer3 = dev::getTimer(1000, configuration); +#endif + + sampleTimer1.startTimer(timer2IRQHandler, nullptr); + sampleTimer2.startTimer(timer15IRQHandler, nullptr); + sampleTimer3.startTimer(timer16IRQHandler, nullptr); + + while (1) { + core::time::wait(500); + sampleTimer2.stopTimer(); + sampleTimer3.reloadTimer(); + core::time::wait(500); + sampleTimer2.startTimer(); + } +} diff --git a/src/core/dev/RTCTimer.cpp b/src/core/dev/RTCTimer.cpp index 6c806a40c..cfd937c69 100644 --- a/src/core/dev/RTCTimer.cpp +++ b/src/core/dev/RTCTimer.cpp @@ -30,15 +30,15 @@ void RTCTimer::reloadTimer() { bTimerStopped = false; } -void RTCTimer::setPeriod(uint32_t clock) { - clockPeriod = clock / 1000; +void RTCTimer::setPeriod(const uint32_t period, const uint32_t prescaler) { + clockPeriod = period / 1000; } -uint32_t RTCTimer::getTime() { +uint32_t RTCTimer::getTime() const { return bTimerStopped ? time : time + rtc.getTime() - startTime; } -bool RTCTimer::hasGoneOff() { +bool RTCTimer::hasGoneOff() const { return getTime() >= clockPeriod; } diff --git a/src/core/dev/platform/f3xx/Timerf3xx.cpp b/src/core/dev/platform/f3xx/Timerf3xx.cpp index 5d4a7a2ac..0fb383555 100644 --- a/src/core/dev/platform/f3xx/Timerf3xx.cpp +++ b/src/core/dev/platform/f3xx/Timerf3xx.cpp @@ -1,32 +1,167 @@ #include #include +#include + +#if defined(STM32F302x8) + #define F302_TIMER_COUNT 5 + +TIM_HandleTypeDef halTimers[F302_TIMER_COUNT]; +void (*timerInterruptHandlers[F302_TIMER_COUNT])(void* context, void* htim) = {nullptr}; +void* timerInterruptContexts[F302_TIMER_COUNT] = {}; + +// Timer 6 is technically available but does not support Capture Compare channels, so is therefore not supported. +enum timerInterruptIndex { + TIM1_IDX = 0u, + TIM2_IDX = 1u, + TIM15_IDX = 2u, + TIM16_IDX = 3u, + TIM17_IDX = 4u, + NO_IDX = -1 +}; + +/** + * Returns the corresponding index for the given timer device as stored in the + * timerInterruptHandlers array + * @param[in] peripheral the TIM_TypeDef pointer to the timer device + * @return an uint8_t between 0-3 corresponding to an element of timerInterruptHandlers + */ +timerInterruptIndex getTimerInterruptIndex(TIM_TypeDef* peripheral) { + timerInterruptIndex interruptIdx; + + if (peripheral == TIM1) { + interruptIdx = TIM1_IDX; + } else if (peripheral == TIM2) { + interruptIdx = TIM2_IDX; + } else if (peripheral == TIM15) { + interruptIdx = TIM15_IDX; + } else if (peripheral == TIM16) { + interruptIdx = TIM16_IDX; + } else if (peripheral == TIM17) { + interruptIdx = TIM17_IDX; + } else { + interruptIdx = NO_IDX; + } + + return interruptIdx; +} +extern "C" void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) { + TIM_TypeDef* peripheral = htim->Instance; + IRQn_Type irqNum; + + if (peripheral == TIM1) { + __HAL_RCC_TIM1_CLK_ENABLE(); + irqNum = TIM1_UP_TIM16_IRQn; + } else if (peripheral == TIM2) { + __HAL_RCC_TIM2_CLK_ENABLE(); + irqNum = TIM2_IRQn; + } else if (peripheral == TIM15) { + __HAL_RCC_TIM15_CLK_ENABLE(); + irqNum = TIM15_IRQn; + } else if (peripheral == TIM16) { + __HAL_RCC_TIM16_CLK_ENABLE(); + irqNum = TIM1_UP_TIM16_IRQn; + } else if (peripheral == TIM17) { + __HAL_RCC_TIM17_CLK_ENABLE(); + irqNum = TIM17_IRQn; + } else { + return; // Should never reach, but if an invalid peripheral is passed in then simply return + } + + HAL_NVIC_SetPriority(irqNum, core::platform::TIMER_INTERRUPT_PRIORITY, 0); + HAL_NVIC_EnableIRQ(irqNum); +} + +extern "C" void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { + TIM_TypeDef* peripheral = htim->Instance; + IRQn_Type irqNum; -TIM_HandleTypeDef halTimers[4]; -void (*timerInterruptHandlers[4])(void* htim) = {nullptr}; + if (peripheral == TIM1) { + __HAL_RCC_TIM1_CLK_DISABLE(); + irqNum = TIM1_UP_TIM16_IRQn; + } else if (peripheral == TIM2) { + __HAL_RCC_TIM2_CLK_DISABLE(); + irqNum = TIM2_IRQn; + } else if (peripheral == TIM15) { + __HAL_RCC_TIM15_CLK_DISABLE(); + irqNum = TIM15_IRQn; + } else if (peripheral == TIM16) { + __HAL_RCC_TIM16_CLK_DISABLE(); + irqNum = TIM1_UP_TIM16_IRQn; + } else if (peripheral == TIM17) { + __HAL_RCC_TIM17_CLK_DISABLE(); + irqNum = TIM17_IRQn; + } else { + return; // Should never reach, but if an invalid peripheral is passed in then simply return + } -enum class timerInterruptIndex { - TIM2_IDX = 0u, - TIM15_IDX = 1u, - TIM16_IDX = 2u, - TIM17_IDX = 3u + HAL_NVIC_DisableIRQ(irqNum); +} +#elif defined(STM32F334x8) // #if defined(STM32F302x8) + #define F334_TIMER_COUNT 6 + +TIM_HandleTypeDef halTimers[F334_TIMER_COUNT]; + +void (*timerInterruptHandlers[F334_TIMER_COUNT])(void* context, void* htim) = {nullptr}; +void* timerInterruptContexts[F334_TIMER_COUNT] = {}; + +// Timer 6 is technically available but does not support Capture Compare channels, so is therefore not supported. +enum timerInterruptIndex { + TIM1_IDX = 0u, + TIM2_IDX = 1u, + TIM3_IDX = 2u, + TIM15_IDX = 3u, + TIM16_IDX = 4u, + TIM17_IDX = 5u, + NO_IDX = -1 }; -uint8_t getTimerInterruptIndex(TIM_TypeDef* peripheral); +/** + * Returns the corresponding index for the given timer device as stored in the + * timerInterruptHandlers array + * @param htim the TIM_TypeDef pointer to the timer device + * @return an uint8_t between 0-3 corresponding to an element of timerInterruptHandlers + */ +timerInterruptIndex getTimerInterruptIndex(TIM_TypeDef* peripheral) { + timerInterruptIndex interruptIdx; + + if (peripheral == TIM1) { + interruptIdx = TIM1_IDX; + } else if (peripheral == TIM2) { + interruptIdx = TIM2_IDX; + } else if (peripheral == TIM3) { + interruptIdx = TIM3_IDX; + } else if (peripheral == TIM15) { + interruptIdx = TIM15_IDX; + } else if (peripheral == TIM16) { + interruptIdx = TIM16_IDX; + } else if (peripheral == TIM17) { + interruptIdx = TIM17_IDX; + } else { + interruptIdx = NO_IDX; + } + return interruptIdx; +} extern "C" void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) { TIM_TypeDef* peripheral = htim->Instance; IRQn_Type irqNum; - if (peripheral == TIM2) { + if (peripheral == TIM1) { + __HAL_RCC_TIM1_CLK_ENABLE(); + irqNum = TIM1_UP_TIM16_IRQn; + } else if (peripheral == TIM2) { __HAL_RCC_TIM2_CLK_ENABLE(); irqNum = TIM2_IRQn; + } else if (peripheral == TIM3) { + __HAL_RCC_TIM3_CLK_ENABLE(); + irqNum = TIM3_IRQn; } else if (peripheral == TIM15) { __HAL_RCC_TIM15_CLK_ENABLE(); irqNum = TIM15_IRQn; } else if (peripheral == TIM16) { __HAL_RCC_TIM16_CLK_ENABLE(); - irqNum = TIM16_IRQn; + irqNum = TIM1_UP_TIM16_IRQn; } else if (peripheral == TIM17) { __HAL_RCC_TIM17_CLK_ENABLE(); irqNum = TIM17_IRQn; @@ -42,15 +177,21 @@ extern "C" void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { TIM_TypeDef* peripheral = htim->Instance; IRQn_Type irqNum; - if (peripheral == TIM2) { + if (peripheral == TIM1) { + __HAL_RCC_TIM1_CLK_DISABLE(); + irqNum = TIM1_UP_TIM16_IRQn; + } else if (peripheral == TIM2) { __HAL_RCC_TIM2_CLK_DISABLE(); irqNum = TIM2_IRQn; + } else if (peripheral == TIM3) { + __HAL_RCC_TIM3_CLK_DISABLE(); + irqNum = TIM3_IRQn; } else if (peripheral == TIM15) { __HAL_RCC_TIM15_CLK_DISABLE(); irqNum = TIM15_IRQn; } else if (peripheral == TIM16) { __HAL_RCC_TIM16_CLK_DISABLE(); - irqNum = TIM16_IRQn; + irqNum = TIM1_UP_TIM16_IRQn; } else if (peripheral == TIM17) { __HAL_RCC_TIM17_CLK_DISABLE(); irqNum = TIM17_IRQn; @@ -61,6 +202,23 @@ extern "C" void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { HAL_NVIC_DisableIRQ(irqNum); } +extern "C" void TIM3_IRQHandler(void) { + HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM3)]); +} +#endif // #elif defined(STM32F334x8). + +// Common IRQHandlers between both f3s +extern "C" void TIM1_UP_TIM16_IRQHandler(void) { + if (const timerInterruptIndex tim1Index = getTimerInterruptIndex(TIM1); halTimers[tim1Index].Instance != nullptr) { + HAL_TIM_IRQHandler(&halTimers[tim1Index]); + } + + if (const timerInterruptIndex tim16Index = getTimerInterruptIndex(TIM16); + halTimers[tim16Index].Instance != nullptr) { + HAL_TIM_IRQHandler(&halTimers[tim16Index]); + } +} + extern "C" void TIM2_IRQHandler(void) { HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM2)]); } @@ -69,93 +227,82 @@ extern "C" void TIM15_IRQHandler(void) { HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM15)]); } -extern "C" void TIM16_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM16)]); -} - extern "C" void TIM17_IRQHandler(void) { HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM17)]); } - extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { uint8_t interruptIdx = getTimerInterruptIndex(htim->Instance); - if (timerInterruptHandlers[interruptIdx] != nullptr) { - timerInterruptHandlers[interruptIdx](htim); - } -} -/** - * Returns the corresponding index for the given timer device as stored in the - * timerInterruptHandlers array - * @param htim the TIM_TypeDef pointer to the timer device - * @return an uint8_t between 0-3 corresponding to an element of timerInterruptHandlers - */ -uint8_t getTimerInterruptIndex(TIM_TypeDef* peripheral) { - uint8_t interruptIdx; - - if (peripheral == TIM2) { - interruptIdx = static_cast(timerInterruptIndex::TIM2_IDX); - } else if (peripheral == TIM15) { - interruptIdx = static_cast(timerInterruptIndex::TIM15_IDX); - } else if (peripheral == TIM16) { - interruptIdx = static_cast(timerInterruptIndex::TIM16_IDX); - } else if (peripheral == TIM17) { - interruptIdx = static_cast(timerInterruptIndex::TIM17_IDX); - } else { - interruptIdx = -1; + if (timerInterruptHandlers[interruptIdx] != nullptr) { + void* context = timerInterruptContexts[interruptIdx]; + timerInterruptHandlers[interruptIdx](context, htim); } - - return interruptIdx; } namespace core::dev { -Timerf3xx::Timerf3xx(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod) { - initTimer(timerPeripheral, clockPeriod); +TimerF3xx::TimerF3xx(TIM_TypeDef* timerPeripheral, const uint32_t clockPeriod, + const TimerConfiguration_t& configuration, const uint32_t clockPrescaler) + : configuration(configuration) { this->halTimer = &halTimers[getTimerInterruptIndex(timerPeripheral)]; + initTimer(timerPeripheral, clockPeriod, clockPrescaler); } -void Timerf3xx::initTimer(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod) { +void TimerF3xx::initTimer(TIM_TypeDef* timerPeripheral, const uint32_t clockPeriod, const uint32_t clockPrescaler) { this->clockPeriod = clockPeriod; auto& htim = halTimers[getTimerInterruptIndex(timerPeripheral)]; - htim.Instance = timerPeripheral; - uint32_t prescaler = HAL_RCC_GetHCLKFreq() / 1000; - htim.Init.Prescaler = prescaler - 1; // Sets f_CK_PSC to 1000 Hz + htim.Instance = timerPeripheral; + if (clockPrescaler == AUTO_PRESCALER) { + const uint32_t prescaler = HAL_RCC_GetHCLKFreq() / 1000; + htim.Init.Prescaler = prescaler - 1; // Sets f_CK_PSC to 1000 Hz + } else { + htim.Init.Prescaler = clockPrescaler; + } + // Allows period increments of 1 ms with max of 2^(32) ms. - htim.Init.CounterMode = TIM_COUNTERMODE_UP; + htim.Init.CounterMode = static_cast(this->configuration.counterMode); htim.Init.Period = clockPeriod - 1; - htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + htim.Init.ClockDivision = static_cast(this->configuration.clockDivision); + htim.Init.AutoReloadPreload = static_cast(this->configuration.autoReloadPreload); HAL_TIM_Base_Init(&htim); - TIM_ClockConfigTypeDef clockConfig = {0}; - TIM_MasterConfigTypeDef masterConfig = {0}; + TIM_ClockConfigTypeDef clockConfig = {0}; - clockConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + clockConfig.ClockSource = static_cast(this->configuration.clockSource); HAL_TIM_ConfigClockSource(&htim, &clockConfig); - masterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - masterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + TIM_MasterConfigTypeDef masterConfig = {0}; + + masterConfig.MasterOutputTrigger = static_cast(this->configuration.masterOutputTrigger); + // Should not be needed if it is always set to reset + // masterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + masterConfig.MasterSlaveMode = static_cast(this->configuration.masterSlaveMode); + HAL_TIMEx_MasterConfigSynchronization(&htim, &masterConfig); + + log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Finished timer setup"); } -void Timerf3xx::startTimer(void (*irqHandler)(void* htim)) { +void TimerF3xx::startTimer(void (*irqHandler)(void* context, void* htim), void* context) { + log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Start Timer IRQ"); TIM_TypeDef* timerPeripheral = this->halTimer->Instance; // If timer is not waiting to start, stop it if (halTimer->State != HAL_TIM_STATE_READY) { stopTimer(); } + timerInterruptContexts[getTimerInterruptIndex(timerPeripheral)] = context; timerInterruptHandlers[getTimerInterruptIndex(timerPeripheral)] = irqHandler; startTimer(); } -void Timerf3xx::stopTimer() { +void TimerF3xx::stopTimer() { HAL_TIM_Base_Stop_IT(this->halTimer); } -void Timerf3xx::startTimer() { +void TimerF3xx::startTimer() { + log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Start Timer no IRQ"); // If timer is not waiting to start, stop it if (halTimer->State != HAL_TIM_STATE_READY) { stopTimer(); // Stop timer in case it was already running @@ -167,12 +314,13 @@ void Timerf3xx::startTimer() { HAL_TIM_Base_Start_IT(htim); } -void Timerf3xx::reloadTimer() { +void TimerF3xx::reloadTimer() { this->halTimer->Instance->CNT = 0; // Clear the Counter register to reset the timer } -void Timerf3xx::setPeriod(uint32_t clockPeriod) { +void TimerF3xx::setPeriod(const uint32_t clockPeriod, const uint32_t clockPrescaler) { + core::log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Set period: %d, Prescaler: %d", clockPeriod, clockPrescaler); stopTimer(); - initTimer(this->halTimer->Instance, clockPeriod); + initTimer(this->halTimer->Instance, clockPeriod, clockPrescaler); } } // namespace core::dev diff --git a/src/core/dev/platform/f4xx/Timerf4xx.cpp b/src/core/dev/platform/f4xx/Timerf4xx.cpp index a7782f36a..c44566b07 100644 --- a/src/core/dev/platform/f4xx/Timerf4xx.cpp +++ b/src/core/dev/platform/f4xx/Timerf4xx.cpp @@ -1,30 +1,77 @@ #include #include +#include +#define F4_TIMER_COUNT 12 -TIM_HandleTypeDef halTimers[10]; -void (*timerInterruptHandlers[10])(void* htim) = {nullptr}; +TIM_HandleTypeDef halTimers[F4_TIMER_COUNT]; +void (*timerInterruptHandlers[F4_TIMER_COUNT])(void* context, void* htim) = {nullptr}; +void* timerInterruptContexts[F4_TIMER_COUNT] = {}; enum timerInterruptIndex { - TIM2_IDX = 0u, - TIM3_IDX = 1u, - TIM4_IDX = 2u, - TIM5_IDX = 3u, - TIM9_IDX = 4u, - TIM10_IDX = 5u, - TIM11_IDX = 6u, - TIM12_IDX = 7u, - TIM13_IDX = 8u, - TIM14_IDX = 9u + TIM1_IDX = 0u, + TIM2_IDX = 1u, + TIM3_IDX = 2u, + TIM4_IDX = 3u, + TIM5_IDX = 4u, + TIM8_IDX = 5u, + TIM9_IDX = 6u, + TIM10_IDX = 7u, + TIM11_IDX = 8u, + TIM12_IDX = 9u, + TIM13_IDX = 10u, + TIM14_IDX = 11u, + NO_IDX = -1 }; -uint8_t getTimerInterruptIndex(TIM_TypeDef* peripheral); +/** + * Returns the corresponding index for the given timer device as stored in the + * timerInterruptHandlers array + * @param htim the TIM_TypeDef pointer to the timer device + * @return an uint8_t between 0-9 corresponding to an element of timerInterruptHandlers + */ +timerInterruptIndex getTimerInterruptIndex(TIM_TypeDef* peripheral) { + timerInterruptIndex interruptIdx; + + if (peripheral == TIM1) { + interruptIdx = TIM1_IDX; + } else if (peripheral == TIM2) { + interruptIdx = TIM2_IDX; + } else if (peripheral == TIM3) { + interruptIdx = TIM3_IDX; + } else if (peripheral == TIM4) { + interruptIdx = TIM4_IDX; + } else if (peripheral == TIM5) { + interruptIdx = TIM5_IDX; + } else if (peripheral == TIM9) { + interruptIdx = TIM9_IDX; + } else if (peripheral == TIM10) { + interruptIdx = TIM10_IDX; + } else if (peripheral == TIM11) { + interruptIdx = TIM11_IDX; + } else if (peripheral == TIM12) { + interruptIdx = TIM12_IDX; + } else if (peripheral == TIM13) { + interruptIdx = TIM13_IDX; + } else if (peripheral == TIM14) { + interruptIdx = TIM14_IDX; + } else if (peripheral == TIM8) { + interruptIdx = TIM8_IDX; + } else { + interruptIdx = NO_IDX; + } + + return interruptIdx; +} extern "C" void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) { TIM_TypeDef* peripheral = htim->Instance; IRQn_Type irqNum; - if (peripheral == TIM2) { + if (peripheral == TIM1) { + __HAL_RCC_TIM1_CLK_ENABLE(); + irqNum = TIM1_UP_TIM10_IRQn; + } else if (peripheral == TIM2) { __HAL_RCC_TIM2_CLK_ENABLE(); irqNum = TIM2_IRQn; } else if (peripheral == TIM3) { @@ -54,6 +101,9 @@ extern "C" void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) { } else if (peripheral == TIM14) { __HAL_RCC_TIM14_CLK_ENABLE(); irqNum = TIM8_TRG_COM_TIM14_IRQn; + } else if (peripheral == TIM8) { + __HAL_RCC_TIM8_CLK_ENABLE(); + irqNum = TIM8_UP_TIM13_IRQn; } else { return; // Should never reach, but if an invalid peripheral is passed in then simply return } @@ -66,7 +116,10 @@ extern "C" void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { TIM_TypeDef* peripheral = htim->Instance; IRQn_Type irqNum; - if (peripheral == TIM2) { + if (peripheral == TIM1) { + __HAL_RCC_TIM1_CLK_DISABLE(); + irqNum = TIM1_UP_TIM10_IRQn; + } else if (peripheral == TIM2) { __HAL_RCC_TIM2_CLK_DISABLE(); irqNum = TIM2_IRQn; } else if (peripheral == TIM3) { @@ -96,6 +149,9 @@ extern "C" void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { } else if (peripheral == TIM14) { __HAL_RCC_TIM14_CLK_DISABLE(); irqNum = TIM8_TRG_COM_TIM14_IRQn; + } else if (peripheral == TIM8) { + __HAL_RCC_TIM8_CLK_DISABLE(); + irqNum = TIM8_UP_TIM13_IRQn; } else { return; // Should never reach, but if an invalid peripheral is passed in then simply return } @@ -103,6 +159,37 @@ extern "C" void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { HAL_NVIC_DisableIRQ(irqNum); } +extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { + uint8_t interruptIdx = getTimerInterruptIndex(htim->Instance); + + if (timerInterruptHandlers[interruptIdx] != nullptr) { + void* context = timerInterruptContexts[interruptIdx]; + timerInterruptHandlers[interruptIdx](context, htim); + } +} + +extern "C" void TIM1_UP_TIM10_IRQHandler(void) { + if (const timerInterruptIndex tim1Index = getTimerInterruptIndex(TIM1); halTimers[tim1Index].Instance != nullptr) { + HAL_TIM_IRQHandler(&halTimers[tim1Index]); + } + + if (const timerInterruptIndex tim10Index = getTimerInterruptIndex(TIM10); + halTimers[tim10Index].Instance != nullptr) { + HAL_TIM_IRQHandler(&halTimers[tim10Index]); + } +} + +extern "C" void TIM8_UP_TIM13_IRQHandler(void) { + if (const timerInterruptIndex tim8Index = getTimerInterruptIndex(TIM8); halTimers[tim8Index].Instance != nullptr) { + HAL_TIM_IRQHandler(&halTimers[tim8Index]); + } + + if (const timerInterruptIndex tim13Index = getTimerInterruptIndex(TIM13); + halTimers[tim13Index].Instance != nullptr) { + HAL_TIM_IRQHandler(&halTimers[tim13Index]); + } +} + extern "C" void TIM2_IRQHandler(void) { HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM2)]); } @@ -119,140 +206,91 @@ extern "C" void TIM5_IRQHandler(void) { HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM5)]); } -extern "C" void TIM1_BRK_TIM9_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM9)]); -} - -extern "C" void TIM1_UP_TIM10_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM10)]); -} - -extern "C" void TIM1_TRG_COM_TIM11_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM11)]); -} - -extern "C" void TIM8_BRK_TIM12_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM12)]); -} - -extern "C" void TIM8_UP_TIM13_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM13)]); -} +namespace core::dev { +TimerF4xx::TimerF4xx(TIM_TypeDef* timerPeripheral, const uint32_t clockPeriod, + const TimerConfiguration_t& configuration, const uint32_t clockPrescaler) + : configuration(configuration) { + this->clockPeriod = clockPeriod; + this->halTimer = &halTimers[getTimerInterruptIndex(timerPeripheral)]; + initTimer(timerPeripheral, clockPeriod, clockPrescaler); +}; -extern "C" void TIM8_TRG_COM_TIM14_IRQHandler(void) { - HAL_TIM_IRQHandler(&halTimers[getTimerInterruptIndex(TIM14)]); -} +TimerF4xx::~TimerF4xx() = default; -extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { - uint8_t interruptIdx = getTimerInterruptIndex(htim->Instance); - if (timerInterruptHandlers[interruptIdx] != nullptr) { - timerInterruptHandlers[interruptIdx](htim); - } -} +void TimerF4xx::initTimer(TIM_TypeDef* timerPeripheral, const uint32_t clockPeriod, const uint32_t clockPrescaler) { + this->clockPeriod = clockPeriod; + auto& htim = halTimers[getTimerInterruptIndex(timerPeripheral)]; -/** - * Returns the corresponding index for the given timer device as stored in the - * timerInterruptHandlers array - * @param htim the TIM_TypeDef pointer to the timer device - * @return an uint8_t between 0-9 corresponding to an element of timerInterruptHandlers - */ -uint8_t getTimerInterruptIndex(TIM_TypeDef* peripheral) { - uint8_t interruptIdx; + htim.Instance = timerPeripheral; + // Allows period increments of 1 ms with max of 2^(32) ms. + htim.Init.CounterMode = static_cast(this->configuration.counterMode); + htim.Init.ClockDivision = static_cast(this->configuration.clockDivision); + htim.Init.AutoReloadPreload = static_cast(this->configuration.autoReloadPreload); - if (peripheral == TIM2) { - interruptIdx = timerInterruptIndex::TIM2_IDX; - } else if (peripheral == TIM3) { - interruptIdx = timerInterruptIndex::TIM3_IDX; - } else if (peripheral == TIM4) { - interruptIdx = timerInterruptIndex::TIM4_IDX; - } else if (peripheral == TIM5) { - interruptIdx = timerInterruptIndex::TIM5_IDX; - } else if (peripheral == TIM9) { - interruptIdx = timerInterruptIndex::TIM9_IDX; - } else if (peripheral == TIM10) { - interruptIdx = timerInterruptIndex::TIM10_IDX; - } else if (peripheral == TIM11) { - interruptIdx = timerInterruptIndex::TIM11_IDX; - } else if (peripheral == TIM12) { - interruptIdx = timerInterruptIndex::TIM12_IDX; - } else if (peripheral == TIM13) { - interruptIdx = timerInterruptIndex::TIM13_IDX; - } else if (peripheral == TIM14) { - interruptIdx = timerInterruptIndex::TIM14_IDX; + if (clockPrescaler == AUTO_PRESCALER) { + const uint32_t prescaler = SystemCoreClock / 1000; + htim.Init.Prescaler = prescaler - 1; // Sets f_CK_PSC to 1000 Hz } else { - interruptIdx = -1; + htim.Init.Prescaler = clockPrescaler; } - return interruptIdx; -} - -namespace core::dev { - -Timerf4xx::Timerf4xx(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod) { - initTimer(timerPeripheral, clockPeriod); - this->halTimer = &halTimers[getTimerInterruptIndex(timerPeripheral)]; -} - -void Timerf4xx::initTimer(TIM_TypeDef* timerPeripheral, uint32_t clockPeriod) { this->clockPeriod = clockPeriod; - auto& htim = halTimers[getTimerInterruptIndex(timerPeripheral)]; + htim.Init.Period = clockPeriod - 1; - htim.Instance = timerPeripheral; - uint32_t prescaler = SystemCoreClock / 1000; - htim.Init.Prescaler = prescaler - 1; // Sets f_CK_PSC to 1000 Hz - // Allows period increments of 1 ms with max of 2^(32) ms. - htim.Init.CounterMode = TIM_COUNTERMODE_UP; - htim.Init.Period = clockPeriod - 1; - htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_Base_Init(&htim); - TIM_ClockConfigTypeDef clockConfig = {0}; - TIM_MasterConfigTypeDef masterConfig = {0}; + TIM_ClockConfigTypeDef clockConfig = {}; - clockConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + clockConfig.ClockSource = static_cast(this->configuration.clockSource); HAL_TIM_ConfigClockSource(&htim, &clockConfig); + TIM_MasterConfigTypeDef masterConfig = {}; + // Timers 9-14 are NOT master mode compatible, so waste of time to go through config if (getTimerInterruptIndex(timerPeripheral) < timerInterruptIndex::TIM9_IDX) { - masterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - masterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + masterConfig.MasterOutputTrigger = static_cast(this->configuration.masterOutputTrigger); + masterConfig.MasterSlaveMode = static_cast(this->configuration.masterSlaveMode); HAL_TIMEx_MasterConfigSynchronization(&htim, &masterConfig); } -} -void Timerf4xx::startTimer(void (*irqHandler)(void* htim)) { + core::log::LOGGER.log(core::log::Logger::LogLevel::DEBUG, "Finished timer setup"); +}; + +void TimerF4xx::startTimer(void (*irqHandler)(void* context, void* htim), void* context) { TIM_TypeDef* timerPeripheral = this->halTimer->Instance; + // If timer is not waiting to start, stop it if (halTimer->State != HAL_TIM_STATE_READY) { stopTimer(); } + timerInterruptContexts[getTimerInterruptIndex(timerPeripheral)] = context; timerInterruptHandlers[getTimerInterruptIndex(timerPeripheral)] = irqHandler; startTimer(); } -void Timerf4xx::stopTimer() { +void TimerF4xx::stopTimer() { HAL_TIM_Base_Stop_IT(this->halTimer); } -void Timerf4xx::startTimer() { +void TimerF4xx::startTimer() { // If timer is not waiting to start, stop it if (halTimer->State != HAL_TIM_STATE_READY) { stopTimer(); // Stop timer in case it was already running } auto htim = this->halTimer; + // Clear the interrupt flag so interrupt doesn't trigger immediately __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); HAL_TIM_Base_Start_IT(htim); } -void Timerf4xx::reloadTimer() { +void TimerF4xx::reloadTimer() { this->halTimer->Instance->CNT = 0; // Clear the Counter register to reset the timer } -void Timerf4xx::setPeriod(uint32_t clockPeriod) { +void TimerF4xx::setPeriod(const uint32_t clockPeriod, const uint32_t clockPrescaler) { stopTimer(); - initTimer(this->halTimer->Instance, clockPeriod); + initTimer(this->halTimer->Instance, clockPeriod, clockPrescaler); } } // namespace core::dev diff --git a/src/core/io/CANopen.cpp b/src/core/io/CANopen.cpp index d6bfcfa8b..290d9827b 100644 --- a/src/core/io/CANopen.cpp +++ b/src/core/io/CANopen.cpp @@ -205,7 +205,7 @@ static void canClose(void) {} /** * Interrupt handler for the timer, updates that the timer has gone off */ -void timerHandler(void* halTim) { +void timerHandler(void* context, void* halTim) { timerCounter++; } @@ -220,7 +220,7 @@ static void timerInit(uint32_t freq) { static void timerReload(uint32_t reload) { __evt_core_can_timer__->stopTimer(); __evt_core_can_timer__->setPeriod(10); - __evt_core_can_timer__->startTimer(timerHandler); + __evt_core_can_timer__->startTimer(timerHandler, nullptr); timerCounter = 0; timerRunning = true; counterTarget = reload; @@ -230,7 +230,7 @@ static void timerReload(uint32_t reload) { * Start the "timer" running */ static void timerStart(void) { - __evt_core_can_timer__->startTimer(timerHandler); + __evt_core_can_timer__->startTimer(timerHandler, nullptr); timerRunning = true; timerCounter = 0; } diff --git a/src/core/io/platform/f3xx/PWMf3xx.cpp b/src/core/io/platform/f3xx/PWMf3xx.cpp index 09ef793f6..9c98f8570 100644 --- a/src/core/io/platform/f3xx/PWMf3xx.cpp +++ b/src/core/io/platform/f3xx/PWMf3xx.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -8,33 +10,28 @@ namespace core::io { * is pulled from the STM32F302x8 documentation. Easier representation of this * data can be found on MBed's STM32F302r8 documentation. * - * @param pin The pin to check the instance of - * @param instance The instance to assign to - * @param channel The channel to assign to - * @param alternateFunction The GPIO identifier for the function of the pin + * @param[in] pin The pin to check the instance of + * @param[in] channel The channel to assign to + * @param[in] alternateFunction The GPIO identifier for the function of the pin */ -static void getInstance(Pin pin, TIM_TypeDef** instance, uint32_t* channel, uint32_t* alternateFunction) { +static void getInstance(Pin pin, uint32_t* channel, uint32_t* alternateFunction) { switch (pin) { #if defined(STM32F302x8) case Pin::PA_0: - *instance = TIM2; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM2; break; // complementary channel //////////////////////////////////////////// case Pin::PA_1: - *instance = TIM15; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF9_TIM15; break; case Pin::PA_2: - *instance = TIM15; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF9_TIM15; break; case Pin::PA_3: - *instance = TIM15; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF3_TIM15; break; @@ -45,172 +42,140 @@ static void getInstance(Pin pin, TIM_TypeDef** instance, uint32_t* channel, uint // *alternateFunction = GPIO_AF2_TIM3; // break; case Pin::PA_5: - *instance = TIM2; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF10_TIM2; break; case Pin::PA_8: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PA_6: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PA_7: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM17; break; case Pin::PA_9: - *instance = TIM1; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PA_10: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PA_11: - *instance = TIM1; *channel = TIM_CHANNEL_4; *alternateFunction = GPIO_AF11_TIM1; break; case Pin::PA_12: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; // complementary channel case Pin::PA_13: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PA_15: - *instance = TIM2; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF10_TIM2; break; // complementary channel case Pin::PB_0: - *instance = TIM1; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF6_TIM1; break; // complementary channel case Pin::PB_1: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PB_3: - *instance = TIM2; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF1_TIM2; case Pin::PB_4: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PB_5: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF10_TIM17; break; // complementary channel case Pin::PB_6: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; // complementary channel case Pin::PB_7: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM17; break; case Pin::PB_8: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PB_9: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM17; break; case Pin::PB_10: - *instance = TIM2; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF1_TIM2; break; case Pin::PB_11: - *instance = TIM2; *channel = TIM_CHANNEL_4; *alternateFunction = GPIO_AF1_TIM2; break; // complementation channel case Pin::PB_13: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PB_14: - *instance = TIM15; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM15; break; case Pin::PB_15: - *instance = TIM15; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF1_TIM15; break; case Pin::PC_0: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF2_TIM1; break; case Pin::PC_1: - *instance = TIM1; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF2_TIM1; break; case Pin::PC_2: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF2_TIM1; break; case Pin::PC_3: - *instance = TIM1; *channel = TIM_CHANNEL_4; *alternateFunction = GPIO_AF2_TIM1; break; // complementary channel case Pin::PC_13: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF4_TIM1; break; // complementary channel case Pin::PF_0: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF6_TIM1; break; #elif defined(STM32F334x8) case Pin::PA_0: - *instance = TIM2; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM2; break; // complementary channel case Pin::PA_1: - *instance = TIM15; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF2_TIM15; break; @@ -236,143 +201,116 @@ static void getInstance(Pin pin, TIM_TypeDef** instance, uint32_t* channel, uint // *alternateFunction = GPIO_AF10_TIM2; // break; case Pin::PA_8: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PA_6: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PA_7: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM17; break; case Pin::PA_9: - *instance = TIM1; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PA_10: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PA_11: - *instance = TIM1; *channel = TIM_CHANNEL_4; *alternateFunction = GPIO_AF11_TIM1; break; case Pin::PA_12: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; // complementary channel case Pin::PA_13: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PA_15: - *instance = TIM2; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM2; break; // complementary channel case Pin::PB_0: - *instance = TIM1; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF6_TIM1; break; // complementary channel case Pin::PB_1: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PB_3: - *instance = TIM2; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF1_TIM2; break; case Pin::PB_4: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PB_5: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF10_TIM17; break; // complementary channel case Pin::PB_6: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; // complementary channel case Pin::PB_7: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM17; break; case Pin::PB_8: - *instance = TIM16; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM16; break; case Pin::PB_9: - *instance = TIM17; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM17; break; case Pin::PB_10: - *instance = TIM2; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF1_TIM2; break; case Pin::PB_11: - *instance = TIM2; *channel = TIM_CHANNEL_4; *alternateFunction = GPIO_AF1_TIM2; break; // complementary channel case Pin::PB_13: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF6_TIM1; break; case Pin::PB_14: - *instance = TIM15; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF1_TIM15; break; case Pin::PB_15: - *instance = TIM15; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF1_TIM15; break; case Pin::PC_0: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF2_TIM1; break; case Pin::PC_1: - *instance = TIM1; *channel = TIM_CHANNEL_2; *alternateFunction = GPIO_AF2_TIM1; break; case Pin::PC_2: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF2_TIM1; break; case Pin::PC_3: - *instance = TIM1; *channel = TIM_CHANNEL_4; *alternateFunction = GPIO_AF2_TIM1; break; @@ -399,57 +337,172 @@ static void getInstance(Pin pin, TIM_TypeDef** instance, uint32_t* channel, uint // break; // complementary channel case Pin::PC_13: - *instance = TIM1; *channel = TIM_CHANNEL_1; *alternateFunction = GPIO_AF4_TIM1; break; // complementary channel case Pin::PF_0: - *instance = TIM1; *channel = TIM_CHANNEL_3; *alternateFunction = GPIO_AF6_TIM1; break; #endif default: - *instance = NULL; *channel = -1; *alternateFunction = -1; } } -PWMf3xx::PWMf3xx(Pin pin) : PWM(pin) { - TIM_TypeDef* instance; - uint32_t alternateFunction; - getInstance(pin, &instance, &halTIMChannelID, &alternateFunction); - - if (instance == TIM1) { - __HAL_RCC_TIM1_CLK_ENABLE(); - } else if (instance == TIM2) { - __HAL_RCC_TIM2_CLK_ENABLE(); - } else if (instance == TIM15) { - __HAL_RCC_TIM15_CLK_ENABLE(); - } else if (instance == TIM16) { - __HAL_RCC_TIM16_CLK_ENABLE(); - } else if (instance == TIM17) { - __HAL_RCC_TIM17_CLK_ENABLE(); +/** + * Finds the correct timer instance for a given PWM @Pin + * @param[in] pin the PWM pin to get a timer instance for. + * @return The @ref MCUTimer that correspeonds to the @pin + */ +static dev::MCUTimer timerInstance(Pin pin) { + switch (pin) { +#if defined(STM32F302x8) + case Pin::PA_0: + return dev::MCUTimer::Timer2; + case Pin::PA_1: + return dev::MCUTimer::Timer15; + case Pin::PA_2: + return dev::MCUTimer::Timer15; + case Pin::PA_3: + return dev::MCUTimer::Timer15; + case Pin::PA_5: + return dev::MCUTimer::Timer2; + case Pin::PA_8: + return dev::MCUTimer::Timer1; + case Pin::PA_6: + return dev::MCUTimer::Timer16; + case Pin::PA_7: + return dev::MCUTimer::Timer17; + case Pin::PA_9: + return dev::MCUTimer::Timer1; + case Pin::PA_10: + return dev::MCUTimer::Timer1; + case Pin::PA_11: + return dev::MCUTimer::Timer1; + case Pin::PA_12: + return dev::MCUTimer::Timer16; + case Pin::PA_13: + return dev::MCUTimer::Timer16; + case Pin::PA_15: + return dev::MCUTimer::Timer2; + case Pin::PB_0: + return dev::MCUTimer::Timer1; + case Pin::PB_1: + return dev::MCUTimer::Timer1; + case Pin::PB_3: + return dev::MCUTimer::Timer2; + case Pin::PB_4: + return dev::MCUTimer::Timer16; + case Pin::PB_5: + return dev::MCUTimer::Timer17; + case Pin::PB_6: + return dev::MCUTimer::Timer16; + case Pin::PB_7: + return dev::MCUTimer::Timer17; + case Pin::PB_8: + return dev::MCUTimer::Timer16; + case Pin::PB_9: + return dev::MCUTimer::Timer17; + case Pin::PB_10: + return dev::MCUTimer::Timer2; + case Pin::PB_11: + return dev::MCUTimer::Timer2; + case Pin::PB_13: + return dev::MCUTimer::Timer1; + case Pin::PB_14: + return dev::MCUTimer::Timer15; + case Pin::PB_15: + return dev::MCUTimer::Timer15; + case Pin::PC_0: + return dev::MCUTimer::Timer1; + case Pin::PC_1: + return dev::MCUTimer::Timer1; + case Pin::PC_2: + return dev::MCUTimer::Timer1; + case Pin::PC_3: + return dev::MCUTimer::Timer1; + case Pin::PC_13: + return dev::MCUTimer::Timer1; + case Pin::PF_0: + return dev::MCUTimer::Timer1; +#elif defined(STM32F334x8) + case Pin::PA_0: + return dev::MCUTimer::Timer2; + case Pin::PA_1: + return dev::MCUTimer::Timer15; + case Pin::PA_8: + return dev::MCUTimer::Timer1; + case Pin::PA_6: + return dev::MCUTimer::Timer16; + case Pin::PA_7: + return dev::MCUTimer::Timer17; + case Pin::PA_9: + return dev::MCUTimer::Timer1; + case Pin::PA_10: + return dev::MCUTimer::Timer1; + case Pin::PA_11: + return dev::MCUTimer::Timer1; + case Pin::PA_12: + return dev::MCUTimer::Timer16; + case Pin::PA_13: + return dev::MCUTimer::Timer16; + case Pin::PA_15: + return dev::MCUTimer::Timer2; + case Pin::PB_0: + return dev::MCUTimer::Timer1; + case Pin::PB_1: + return dev::MCUTimer::Timer1; + case Pin::PB_3: + return dev::MCUTimer::Timer2; + case Pin::PB_4: + return dev::MCUTimer::Timer16; + case Pin::PB_5: + return dev::MCUTimer::Timer17; + case Pin::PB_6: + return dev::MCUTimer::Timer16; + case Pin::PB_7: + return dev::MCUTimer::Timer17; + case Pin::PB_8: + return dev::MCUTimer::Timer16; + case Pin::PB_9: + return dev::MCUTimer::Timer17; + case Pin::PB_10: + return dev::MCUTimer::Timer2; + case Pin::PB_11: + return dev::MCUTimer::Timer2; + case Pin::PB_13: + return dev::MCUTimer::Timer1; + case Pin::PB_14: + return dev::MCUTimer::Timer15; + case Pin::PB_15: + return dev::MCUTimer::Timer15; + case Pin::PC_0: + return dev::MCUTimer::Timer1; + case Pin::PC_1: + return dev::MCUTimer::Timer1; + case Pin::PC_2: + return dev::MCUTimer::Timer1; + case Pin::PC_3: + return dev::MCUTimer::Timer1; + case Pin::PC_13: + return dev::MCUTimer::Timer1; + case Pin::PF_0: + return dev::MCUTimer::Timer1; +#endif + default: + return dev::MCUTimer::None; } - // TODO:Investigate Timer 3 on 334 - // } else if (instance == TIM3) { - // __HAL_RCC_TIM3_CLK_ENABLE(); - // } - - TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; +} - halTIM.Instance = instance; - halTIM.Init.Prescaler = 0; - halTIM.Init.CounterMode = TIM_COUNTERMODE_UP; - halTIM.Init.Period = 0; - halTIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - halTIM.Init.RepetitionCounter = 0; - halTIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; - HAL_TIM_Base_Init(&halTIM); +PWMf3xx::PWMf3xx(Pin pin) : PWM(pin), TimerF3xx(dev::getTIM(timerInstance(pin)), 0, defaultConfig, AUTO_PRESCALER) { + uint32_t alternateFunction; + getInstance(pin, &halTIMChannelID, &alternateFunction); - HAL_TIM_PWM_Init(&halTIM); + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + HAL_TIM_PWM_Init(halTimer); sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; @@ -459,7 +512,7 @@ PWMf3xx::PWMf3xx(Pin pin) : PWM(pin) { sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.BreakFilter = 0; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; - HAL_TIMEx_ConfigBreakDeadTime(&halTIM, &sBreakDeadTimeConfig); + HAL_TIMEx_ConfigBreakDeadTime(halTimer, &sBreakDeadTimeConfig); // Setup GPIO pin for PMW GPIO_InitTypeDef gpioInit = {0}; @@ -468,6 +521,8 @@ PWMf3xx::PWMf3xx(Pin pin) : PWM(pin) { GPIOf3xx::gpioStateInit( &gpioInit, myPins, numOfPins, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, alternateFunction); + + TimerF3xx::startTimer(); } void PWMf3xx::setDutyCycle(uint32_t dutyCycle) { @@ -475,16 +530,16 @@ void PWMf3xx::setDutyCycle(uint32_t dutyCycle) { TIM_OC_InitTypeDef sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_PWM1; - sConfigOC.Pulse = dutyCycle * halTIM.Init.Period / 100; + sConfigOC.Pulse = dutyCycle * halTimer->Init.Period / 100; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; - HAL_TIM_PWM_Stop(&halTIM, halTIMChannelID); - HAL_TIM_PWM_ConfigChannel(&halTIM, &sConfigOC, halTIMChannelID); - HAL_TIM_PWM_Start(&halTIM, halTIMChannelID); + HAL_TIM_PWM_Stop(halTimer, halTIMChannelID); + HAL_TIM_PWM_ConfigChannel(halTimer, &sConfigOC, halTIMChannelID); + HAL_TIM_PWM_Start(halTimer, halTIMChannelID); } void PWMf3xx::setPeriod(uint32_t period) { @@ -493,7 +548,7 @@ void PWMf3xx::setPeriod(uint32_t period) { } this->period = period; - HAL_TIM_PWM_Stop(&halTIM, halTIMChannelID); + HAL_TIM_PWM_Stop(halTimer, halTIMChannelID); uint32_t autoReload; uint32_t prescaler = -1; @@ -506,21 +561,20 @@ void PWMf3xx::setPeriod(uint32_t period) { autoReload = period * clockFrequency / (prescaler + 1) / 1000000 - 1; } while (autoReload > 65535); - halTIM.Init.Period = autoReload; - halTIM.Init.Prescaler = prescaler; - HAL_TIM_Base_Init(&halTIM); - HAL_TIM_PWM_Start(&halTIM, halTIMChannelID); + TimerF3xx::setPeriod(autoReload, prescaler); + TimerF3xx::startTimer(); + + HAL_TIM_PWM_Start(halTimer, halTIMChannelID); // Duty cycle value depends on period, need to update duty cycle setDutyCycle(this->dutyCycle); } uint32_t PWMf3xx::getDutyCycle() { - return dutyCycle; + return this->dutyCycle; } uint32_t PWMf3xx::getPeriod() { - return period; + return this->period; } - } // namespace core::io diff --git a/src/core/io/platform/f4xx/ADCf4xx.cpp b/src/core/io/platform/f4xx/ADCf4xx.cpp index 1cbc30f72..77e4b3ef7 100644 --- a/src/core/io/platform/f4xx/ADCf4xx.cpp +++ b/src/core/io/platform/f4xx/ADCf4xx.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -54,7 +55,16 @@ constexpr uint8_t ADC3_SLOT = 2; ADCf4xx::ADC_State core::io::ADCf4xx::adcArray[NUM_ADCS]; bool core::io::ADCf4xx::timerInit = false; -TIM_HandleTypeDef core::io::ADCf4xx::htim8; + +dev::TimerConfiguration_t configuration = {dev::TimerCounterMode::UP, + dev::TimerClockDivision::DIVISION_1, + dev::TimerAutoReloadPreload::ENABLE, + dev::TimerClockSource::INTERNAL, + dev::TimerMasterModeSelection::UPDATE, + dev::TimerMasterSlaveMode::DISABLE}; + +dev::TimerF4xx core::io::ADCf4xx::timer8 = dev::TimerF4xx(TIM8, 1000, configuration); + float core::io::ADCf4xx::vref_voltage = DEFAULT_VREF_POS; ADCf4xx::ADCf4xx(Pin pin, ADCPeriph adcPeriph) @@ -64,8 +74,8 @@ ADCf4xx::ADCf4xx(Pin pin, ADCPeriph adcPeriph) return; } - if (ADCf4xx::timerInit) { - HAL_TIM_Base_DeInit(&ADCf4xx::htim8); // Stop Timer8 (Trigger Source For ADC's) + if (timerInit) { + ADCf4xx::timer8.stopTimer(); ADCf4xx::timerInit = false; } @@ -84,10 +94,8 @@ ADCf4xx::ADCf4xx(Pin pin, ADCPeriph adcPeriph) dmaHandle[adcNum] = &this->ADCf4xx::adcArray[adcNum].halDMA; adcHandle[adcNum] = &this->ADCf4xx::adcArray[adcNum].halADC; - if (!ADCf4xx::timerInit) { - __HAL_RCC_TIM8_CLK_ENABLE(); - initTimer(); - HAL_TIM_Base_Start(&ADCf4xx::htim8); // Start Timer8 (Trigger Source For ADC's) + if (!timerInit) { + ADCf4xx::timer8.startTimer(); ADCf4xx::timerInit = true; } @@ -225,7 +233,7 @@ void ADCf4xx::addChannel(uint8_t rank) { GPIOf4xx::gpioStateInit(&gpioInit, pins, numOfPins, GPIO_MODE_ANALOG, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH); ADC_ChannelConfTypeDef adcChannel; - Channel_Support channelStruct; + Channel_Support channelStruct = {}; // Combines the ADC channel with the ADC peripherals it supports into a struct, avoiding having multi-layered switch // statements switch (pin) { @@ -322,30 +330,4 @@ uint8_t ADCf4xx::getADCNum(ADCPeriph periph) { return ADC3_SLOT; } } - -/* - * This method initializes timer 8 with a Trigger Output of "Update Trigger", with a timer frequency of 1kHz. - * The timer does not specifically tell the exact ADC to do a conversion, it just sends a general Update Trigger every - * cycle. The ADC's are listening for this Update Trigger from timer 8, which is set in the ADC initialization. - */ -void ADCf4xx::initTimer() { - TIM_ClockConfigTypeDef sClockSourceConfig = {0}; - TIM_MasterConfigTypeDef sMasterConfig = {0}; - - ADCf4xx::htim8.Instance = TIM8; - ADCf4xx::htim8.Init.Prescaler = 0; - ADCf4xx::htim8.Init.CounterMode = TIM_COUNTERMODE_UP; - ADCf4xx::htim8.Init.Period = (SystemCoreClock / 1000) - 1; - ADCf4xx::htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - ADCf4xx::htim8.Init.RepetitionCounter = 0; - ADCf4xx::htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; - HAL_TIM_Base_Init(&ADCf4xx::htim8); - sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; - HAL_TIM_ConfigClockSource(&ADCf4xx::htim8, &sClockSourceConfig); - - sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - HAL_TIMEx_MasterConfigSynchronization(&ADCf4xx::htim8, &sMasterConfig); -} - } // namespace core::io