Lesson 5: Part 2: SysTick Timer - Building Operating System

As promise, we will be doing some real work here, making our first Operating System - task scheduler function.

The task scheduler that perform round-robin with no priority. Each task will have a task timer count which get decrement. And when the timer count reach zero, the task is ready to be executed. There will be no preemptive function and thus each task that executed should not have an infinite loop that occupied CPU time indefinitely. This is just a brief explanation of the task scheduler in action as the main focus here is on the SysTick.

Below is the snapshot of the code on the task scheduler.

Structure Defining Task Called Interval and Task Pointer
SysTick Timer Interrupt That Decrement Task Delay


Called Task Upon Task Delay Timeout
Again, the above complete source code has been uploaded into github.

Lesson 5: Part 1: SysTick Timer - Running it

On ARM architecture, a special peripheral that I appreciated much is this:  a dedicated timer called system tick, which use as system tick for RTOS or task scheduler.

The register settings is much simpler as it is meant to be used as system tick in software. In this tutorial, again, we will be using this timer to toggle the LED. On second thought, lets have some fun instead, lets build a Operating System! Unfortunately, this operating system is only have a round-robin task scheduler.

I shall split this into 2 session, first is a guide to enabling the System Tick. The second tutorial will be putting System Tick into our task scheduler.

Do take note that the system tick description is in the programming manual. In here, I will be setting the system tick to timeout every 100ms. This is too big for normal application, but since I will be running tasks with 1seconds and 2 seconds timeout later on, it is good enough here.

After running so many tutorial, finally I saw some easy guide as below:
Guide On Setting Up SysTick
First is the program reload value. With system clock running at 48MHz, each clock running at 1/48MHz, which is 20.83nS. To get to 100ms, I will need 4800000 tick. This correspond to the reload value that I should use.
SysTick Reload Value:
STK_RVR : 4800000
Next I just need to clear the current value to zero
Clear SysTick Current Count
STK_CVR : 0
And finally configure program control and status register
Setting Control and Status Register
STK_CSR : 0x000007
That's it. A few SFR setting and we are good to go. Just go to github(Lesson5_SysTick_Blinking_LED) to grab the source code. And it seems that I still need the blinking LED in this and next (task scheduler) example. Below is the code snippet on SFR settings.
Source Code To Setup SysTick


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.