STM32 - Timer === ###### tags: `firmware_hardware` `electrical_system` `NTURT` #### Author: @andre-liang ![](https://i.imgur.com/ib1aXDy.jpg) ~~過氣遊戲~~ ### Preface When the microcontroller is interacting with the real world, one of the important aspect is time. We want to tell the MCU when to do certain things, one example is the `HAL_Delay()` function mentioned beforehand. Timer is a peripheral for time-related tasks. ### How it works? In order for computers to know time, a common practice is to privode some sort of electrical signal with consistent frequency, thus the computer can count how many pulses have occured, subsequently calculate how much time have passed. A crystal oscillator can generate a stable clock for the MCU. ![](https://i.imgur.com/TNhQUJO.jpg) *source: [link](https://www.everythingrf.com/browse/crystal-oscillators)* ### Timer on STM32 On our STM32 model (STM32F103C8T6), there are 7 timers, include an advanced-control timer, three general-purpose timers, two watchdog timers and a SysTick timer. For further detail, please check the datasheet. ![](https://i.imgur.com/XuGGjIO.png) source: [link](https://www.st.com/resource/en/datasheet/cd00161566.pdf) ### Config Open up a new project use STM32CubeMX. ![](https://i.imgur.com/gTGb11t.png) You can see that the defalut clock speed for our MCU is 8 MHz, the clock used by the TIMER is called APB (Advanced Peripheral Bus), TIM1 use APB2, TIM2~4 use APB1. APBs have independent prescalers, while each timers also have independnet prescaler to change the clock speed of the timer. ![](https://i.imgur.com/BIGaXmq.png) In this lecture, we will use TIM2 (General Timer) as a example, open its configuration panel at `Pinout & Configuration > Timers > TIM1`. Choose Clock Source to be `Internal Clock`(built-in clock on the MCU, external clock is also possible if you connect a oscillator to the MCU). Next we will configure the `Parameter Settings` to setup TIM2 ![](https://i.imgur.com/jXsTv1G.png) #### Prescaler ![](https://i.imgur.com/G3VgG0t.png) source: [link](https://www.mlmvlab.bime.ntu.edu.tw/_files/ugd/0752bb_18d49c36137b4060a3d0dd3044590832.pdf) Since the timer use a finite set of bits (a.k.a register) to store its counting value, the maximun time duration a timer can record is `COUNTER_RESOLUTION*WAVE_PERIOD`, a prescaler is used to generate longer wave peroid, but it sacrifice precision. #### Counter Mode ![](https://i.imgur.com/syGVKyj.jpg) source: [link](https://electronics.stackexchange.com/questions/121583/whats-the-benefit-of-upcounting-or-downcounting-or-center-aligned-mode-of-timer) Upcounting means the value of timer counter will increase by one when timer recieve a pulse, while downcounting means the opposite. I couldn't find useful information about center-aligned mode, but I belive it have to do with PWM functionality, it's a topic for another day. #### Counter Period (AutoReload Register) In upcounting mode, the timer counter will be set back to zero when counter register equals autoreload register, and the counter register will be set back to zero. In downcounting mode, the timer counter will be initialized as the autoreload register value, then when the counter reaches zero, goes back to default value. ![](https://i.imgur.com/qKpuvdE.png) source: [link](https://ithelp.ithome.com.tw/articles/10273881) Note that in center-aligned mode, a interrupt is triggered at both the beginning and end of a period. #### Channel ![](https://i.imgur.com/635cxzc.jpg) Channels can perform certain task when the timer is reloaded. #### Setup Note that you have to set the value in the config register equals to actual value +1. A useful trick to keep track of the actual value is shown as followed: ![](https://i.imgur.com/bq862yG.png) with `Prescaler = 8000` and `AutoReload = 1000` means the timer counter will increase its value by one evey 1 micro seconds (`CPU_CLOCK = 8MHz`, `TIM2_CLOCK = 1KHz`, `period = 0.001sec = 1μs`), and it will reset every 1 second. ### Example In this example, we want to benchmark the performance of STM32 using the calculation of fibonacci sequence, the computation time required should scale exponentially. #### Variables ```clike= int sec, fibResult; float executionTime; ``` Define them in the global scope, so they can be accessed in the live expression window. #### Functions ```cpp= int calFib(int n) { if (n == 0 || n == 1) { return 1; } else { return calFib(n - 1) + calFib(n - 2); } } ``` This is the function that calculate the n-th fibonacci number recursively. ```cpp= void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == htim2.Instance) { sec += 1; } } ``` This is the timer global interrupt callback function, when the TIM2 counter reaches 1000, it will reset and trigger this callback function. Which means time have passed `1000 * 1μs = 1sec` , thus `sec += 1`. ```cpp= float calTimeInterval() { float result = (float) sec + (float) __HAL_TIM_GET_COUNTER(&htim2) / 1000.0; sec = 0; __HAL_TIM_SET_COUNTER(&htim2, 0); return result; } ``` This function will calculate the time interval between last function call. Note that `__HAL_TIM_GET_COUNTER()` get the timer counter value, `__HAL_TIM_SET_COUNTER()` set the timer counter to desired value. #### Initialize Timer ```clike= MX_TIM2_Init(); ``` This function is generated by the STM32CubeMx tool, initialize the timer in the main function before main loop. #### Main Loop ```cpp= while (1) { for (int i = 0; i < 30; i++) { calTimeInterval(); fibResult = calFib(i); executionTime = calTimeInterval(); } } ``` In the main loop, the MCU will calcute the fibonacci sequence from 0 to 30 and store the value and execution time in the global variables. #### Result video: [link](https://drive.google.com/file/d/17k_7uDs8nMeFvYXAiO5LZwkcbrFBbAd1/view?usp=share_link) ### Conclusion The timer is useful in usecases such as delay the code execution, measure time interval, output analog signal (PWM), sending data with varies protocols (suck as UART, I2C).