Lesson 4: Part 1: Timer: Running A Timer

There is bunch of timer available in STM32F030, below is a snapshot from the F0 series datasheet.

Summary of Timers in ST F0 Series
This is tutorial we will be using TIM3 in our exercise. This timer is select as it is one of the timer that is available across all MCU. Initially I want to use TIM6 as example as it have simpler configurations, but only certain MCU part will this timer and thus I have drop the idea.

To understand TIM3 features and SFR control, refer to ReferenceManual at Chapter 14: General Purpose Timer (TIM3). Frankly speaking, I have quite a hard time in understanding the description, and also having difficulties in finding the register I need. I hope this is not a sign for I am too old for this job, :-)
Reference Manual on TIM3


Before we dive into  controlling the timer, we need some understanding on timers. Some reference is here.

Generally to use a timer, we will need to perform the following actions:
  1. Enable timer 3
  2. Timer interrupt duration calculation
  3. Enable timer interrupt
  4. Run timer
  5. Implement timer ISR

1. Enable Timer 3

This is done by enabling Timer3 block by supplying clock.
Enable Timer 3 Block
RCC_APB1ENR: TIM3_EN

2. Timer Interrupt Duration Calculation

2.1 Timer Prescaler

A timer is just a counter that keep running up/down (count up or count down) until overflow and interrupted is generated due to  the overflow. The counter is increment in a fix duration. A 48MHz system, each clock cycle can increment the counter, making the duration for counter 0->1 happen in 1/48MHz (208.3 nano-seconds)

STM32F030 is running at 48MHz, typically we want a timer to have duration of 1milliseconds. In order to 'scale down' the frequency, we will need the prescaler. Each MCU will have its own prescaler formula as describe in user manual.
Timer Prescaler
TIM3_PSC = 47999
As shown in above, CK_CNT is the frequency that we need, PSC is the prescaler value that we should set in order to obtain the frequence we want.
Said we need 1 micro-seconds interval, that would equal to 1MHz, thus the prescale value = 48MHz/1MHz - 1 = 47
However, in this tutorial I will created a 1 seconds timer, a more appropiate frequency would be 1KHz. Thus, the prescale value = 48MHz/1KHz - 1 = 47999.

As the prescale is only 16 bit, the slowest frequency we can have will be 732.4Hz.

2.2 Timer Auto Reload Value

After setting the prescaler 47999, we now have a counter(timer) that increment every 1milliseconds. We want to have a timer that interrupt at 1 second interval, thus we want the counter to count up to 1000 (1000*1milliseconds = 1 second) and generated an interrupt.

The SFR so use in determining the maximum count is Timer Auto Reload Value.
Timer Auto Reload
TIM3_ARR  = 1000
 We just need to set this register as 1000 to get a 1 seconds timer interrupted. The range we can have here is from 1mS to 65535 mS (base on prescale value of 47999).

By adjusting prescaler and auto-reload register, we can control timer interrupt period to a smaller/larger duration.

3. Enable timer interrupt

We need to enable the following SFR for interrupt generation upon timer overflow
Enable Timer 3 Overflow Generated Interrupt
TIM3_DIER : UIE
Interrupt Block : Enable Timer 3 Interrupt
NVIC_ISER : 16 (16 is ISR for Timer 3) as shown below
Vector Table Showing Timer 3 At Position 16

4. Run timer

Start timer with the following

Enable Timer Run
TIM_CR1 : CEN

5. Implement Timer ISR

Timer ISR is pretty simple, we just need to clear the interrupt flag, so that ISR is not called until next interrupt happen.

Then is our user code, here we just set a flag upon interrupt. In the main loop there will be code that trigger LED-LD3 base on this flag. Do notice the flag is declare as below:
volatile unsigned char LEDOnOff;

A 'volatile' keyword is require here to inform compiler that this variable can be change anytime in the program. This will avoid compiler optimizing the LED trigger code in main function. A detail explanation of these will be out of this tutorial scope. I will try explain on this in other post instead.

As a rule of thumb, variable use in the interrupt should always declare with 'volatile' keyword.

As usual, I have push the tutorial code into github.






No comments:

Post a Comment