#ifndef STM32U5XX_HAL_TIM_HPP #define STM32U5XX_HAL_TIM_HPP #include "global_variable.h" #include "queue.hpp" #include "reg_nvic.h" #include "reg_rcc.h" #include "reg_tim.h" #include "reg_uart.h" #include "stm32u5xx.h" /** * @brief timer CMS counter mode selection * * 00: EdgeAlignMode: The counter counts up or down depending on the direction * bit (DIR). * * 01: Center-aligned mode 1: The counter counts up and down alternatively. * Output compare interrupt flags of channels configured in output (CCxS=00 in * TIMx_CCMRx register) are set only when the counter is counting down. * * 10: Center-aligned mode 2: The counter counts up and down alternatively. * Output compare interrupt flags of channels configured in output (CCxS=00 in * TIMx_CCMRx register) are set only when the counter is counting up. * * 11: Center-aligned mode 3. The counter counts up and down alternatively. * Output compare interrupt flags of channels configured in output (CCxS=00 in * TIMx_CCMRx register) are set both when the counter is counting up or down. */ typedef enum { EdgeAlignMode, CenterAlign1, CenterAlign2, CenterAlign3 } CMS; /** * @brief timer direction * * 0: Counter used as upcounter * 1: Counter used as downcounter */ typedef enum { UpCounting, DownCounting } timer_dir_e; typedef enum { CH1, CH2, CH3, CH4 } timer_channel_e; class Tim { private: TIM_TypeDef *instance; reg_tim_t *reg; uint32_t clk; uint32_t irq; public: Tim() = default; void setup(TIM_TypeDef *tim) { instance = tim; reg = (reg_tim_t *) tim; } /** * @brief default initialization of timer * @note this function initialize timer in default mode with following settings: * - timer clock enable * - timer counter direction: up counting * - timer alignment mode: edge alignment (the counter register from 0 to ARR total ARR+1 counts) * - timer prescaler: 0 * - timer repetition counter: 0 (RCR) * - timer auto-reload preload enable * - timer interrupt disabled */ void init_default() { rcc_enable_timer_clock(instance); // enable clock reg->cr1.cen = 0; // disable counter reg->cr1.dir = UpCounting; // UpCounting reg->cr1.cms = EdgeAlignMode; // EdgeAlignMode reg->psc.psc = 0; // set prescaler reg->rcr.rep = 0; // set repeat counter -- no repetition reg->cr1.arpe = 1; // enable auto-reload preload reg->dier.uie = 0; // disable interrupt reg->egr.ug = 1; // generate update event to reload the registers immediately reg->cr1.cen = 1; // enable counter } /** * @brief set pwm mode for timer * @note this function set timer in pwm mode with following settings: * - timer clock enable * - pwm mode 1 * @warning This function will change auto-reload register (ARR) and compare register (CCR1) * The value of low + high not allow great than uint16_t. * * @note By default the system clock is 160 MHz, and clock prescaler is 1, so the timer clock is 160 MHz. * @example * if you want to set pwm frequency to 10 kHz, with 50% duty cycle, you should set low to 80k and high to 800k. * `set_pwm(timer1, CH1, 8000, 8000);` * if you want to set pwm frequency to 20 MHz, with 50% duty cycle, you should set low to 4 and high to 4. * `set_pwm(timer1, CH1, 4, 4);` * */ void set_pwm(timer_channel_e ch, uint16_t low, uint16_t high) { CLEAR_BIT(instance->CR1, TIM_CR1_CEN); // disable counter switch (ch) { case CH1: reg->ccmr1.out.cc1s = 0; // set cc1 channel to output reg->ccmr1.out.oc1pe = 0; // disable compare preload. reg->ccmr1.out.oc1m = 0b0110; // set pwm mode 1 reg->ccr1.ccr1 = low; // set low value reg->arr.arr = low + high - 1; // set high value break; default: break; } SET_BIT(instance->CR1, TIM_CR1_CEN); // enable counter } /** * @brief set pwm duty cycle * @note this function set pwm duty cycle by setting compare register * * @param tim timer * @param ch channel * @param duty_cycle duty cycle, range from 0 to 1 */ void timer_set_pwm_duty_cycle(timer_channel_e ch, float duty_cycle) { uint32_t high = (uint16_t) (duty_cycle * (float) (instance->ARR + 1)); uint32_t low = instance->ARR + 1 - high; set_pwm(ch, low, high); }; /** * @brief enable timer channel output * @param tim * @param ch * @note before calling this function, there is not output from the timer channel * @warning Before calling this function, port should be setup */ void enable_output(timer_channel_e ch) { switch (ch) { case CH1: reg->ccer.cc1e = 1; reg->bdtr.moe = 1; break; default: break; } } /********************************************************************/ /* bellow code are deprecated, will be removed in the future */ /********************************************************************/ /** * @brief timer initialization * @param tim timer to initialize * @param dir direction of the timer * @param alignMode alignment mode of the timer. */ void tim_init(timer_dir_e dir, CMS alignMode) { // enable clock RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // enable interrupt // set counter direction instance->CR1 |= dir << TIM_CR1_DIR_Pos; // set align mode instance->CR1 |= alignMode << TIM_CR1_CMS_Pos; // set prescaler instance->PSC = 0; // set repeat counter instance->RCR = 0; // set update generate instance->EGR |= TIM_EGR_UG; // auto-reload preload enable instance->CR1 |= TIM_CR1_ARPE; // enable timer counter instance->ARR = 0x9; instance->RCR = 0x9; instance->CCR1 = 0x5; instance->CR1 = 0x81; // tim->CR1 |= TIM_CR1_CEN; } void tim_set_output(TIM_TypeDef *tim) { tim->CCER |= TIM_CCER_CC1E; } void tim_out_enable(bool ena) { // tim->BDTR |= TIM_BDTR_AOE; // tim->BDTR |= TIM_BDTR_MOE; instance->BDTR = 0x0200A000; } }; #endif // STM32U5XX_HAL_TIM_HPP