Hello everyone ! This post introduces a very basic example of stm32f4 timers’ usage. We’re going to drive our four leds on stm32f4discovery with four general purpose timers TIM2..TIM 5. All of them are used as 16 bit. The task is to let timers count their own period and TIM3..TIM5 timers’ periods are multiples of TIM2’s period. To distinguish that periods of blinking are correct I’ve chosen rather long values: 3, 6, 9 and 12 sec.
One more feature this post is different from previous ones - it’s code will not be 100% assembly. There is a post about plain gcc project template for stm32f4xx. So the concept is to write those things in assembly we want to focus on. You’ll need the possibility to compile together with the ST library to get the code in this post working. For more info please refer to the link I provided above for you.
Making stm32f4 timer to count is simple enough. Let’s look at the main.c code first
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
|
Well, the most useful stuff about timers is hidden from the code above. One of the most important things to know about timers is how to determine exact time which it takes to count for one period. Let’s do little math.
In general to set timer counting period time we need to know the time period of a timer clock signal and to set apropriate value for timer reload register. Timer will count until that value is reached and as a result wait exactly needed time before executing the interrupt handler. Here we’re talking about basic upcounting mode (the default one), but stm32f4 timers are rather flexible and need a bunch of posts to cover their functionality.
Let’s discover how the system clock frequency becomes the frequency of a timer clock signal. So we need to refer to the user manual’s chapter on RCC and here is a figure there which will help us:
Timers source their clocks from “APBx timer clocks” point. Note the block which doubles clock’s signal frequecy if APBx prescaler’s factor is greater than 1. For example while we were speeding up stm32f4discovery to 168MHz, these prescaling factors were APB1 PRESC = 4, APB2 PRESC = 2 and AHB PRESC was 1. Timers TIM2..TIM5 are on APB1 bus. So, in that case the timers’ clock frequency:
ftim = ((168MHz / 1) / 4) * 2 = 2 * 168MHz / 4 = 168MHz / 2 = 84MHz
Well, the good news are that timer also has a prescaler. For example let’s assume that we need 3sec timer count period. If we’ll set maximum reload value for 16bit: 0xFFFF or 65535. Without a prescaler on ftim frequency the maximum timer period could be reached is:
T = (65535 + 1) / 84MHz = 0.00078 sec.
Timer prescaler allows to divide ftim with up to 0xFFFF + 1 factor and rather long delays can be reached. So, knowing the delay value and the timer clock frequency value we still need to figure out two parameters: a preload value, a timer prescaler value. To achieve accurate delay value these parameters should be a proper combination of two whole numbers.
To solve the problem we need to solve the following system of equations:
delay = (Nreload + 1) / fpresc;
fpresc = ftim / (Npresc + 1).
Next script in python shows the principle of how this could be done:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Well, in this post I initialize all four TIM2..TIM5 timers to count 3, 6, 9 and 12 seconds respectively and toggle LEDs.
Here is the code in assembly which does that thing. I simplified code as all the initialization are the same between TIM2..TIM5 timers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
|
The original source can be downloaded here.
If we were coding in plain assembly then we would give our own names to interrupt handlers. But in our gcc examples handlers are already declared in stm32f4xx_startup.S file. This file is located under STM32F4-Discovery_FW_V1.1.0/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO path in library version I have.
There is one more thing still remaining behind the scenes. The default system_stm32fxx.c file is configured for 25 MHz crystal for some reason - the value of a PLL_M constant is 25. It’s located under path STM32F4-Discovery_FW_V1.1.0/Libraries/CMSIS/ST/STM32F4xx/Source/Templates. If we don’t care about system clock frequency in our project - it’s OK. But if we do care like in the current case we need to change it.
In our gcc project workspace for stm32f4xx programming there is an option to use project’s own system_stm32f4xx.c file. Please refer to that post for details. To clear out the meaning of PLL_M value I recommend to read the post about stm32f4xx 168 MHz speed up. Here are my Makefile and system_stm32f4xx.c files for reference.
As we have 8 MHz crystal on board of stm32f4discovery, if PLL_M = 8 then the system clock is 168 MHz and the timer clock is 84 MHz and all the above calculations will give you accurate timer control. If something remains unclear on topic, don’t hesitate to ask questions. The binary for this post is available for download.