One of the most cool features of the ARM Cortex series of processors is the SysTick. The SysTick is a 24 bit timer with a user configurable prescalar which can be used for simple variable incrementing tasks such as incrementing a second counter or similar. For the example of done, I’ve made the SysTick counter increment a 32bit unsigned variable every millisecond. By incrementing every millisecond, the variable will roll over every 49 days or so. As the SysTick is a 24bit timer, the maximum prescalar is 16777215. With a clock speed of 48MHz and the prescalar set to this value (2^24-1), the timer interrupt will be called every 2.86Hz. With this clock speed, that is the slowest frequency the SysTick timer can run at. I’ve written a pretty simple program that toggles LED’s at a rate dependent on whether the user button is pressed or not. If the button is pressed, the LED’s toggle slower, if the button is released, the LED’s toggle faster. The LED toggle rate is controlled by a delay function which depends on the SysTick timer variables. As with the previous tutorial on GPIO’s (https://hsel.co.uk/2014/05/31/stm32f0-tutorial-1-gpio/), I’ve used GPIO functions in this piece of code to control the LED’s and read the push button. I’ve also setup a new project in the same method shown and included the same libraries. So, onwards with the tutorial!
Setting up the definitions and SysTick IRQ Handler
As the SysTick timer produces an interrupt every time it overflows, an interrupt handler will need to be set up. Fortunately, the STM32 peripheral library sorts out all the interrupt vectors and includes a nice list of all the interrupt handlers for you. These can be found in “startup_stm32f0xx.s:

As can be seen, the text surrounded by the red box is the SysTick interrupt handler names SysTick_Handler. Now that the name of the SysTick interrupt handler has been found, code can start being written! 
Like with the beginning of all projects, the blank canvas!
Like on the GPIO tutorial, you will need to include the two libraries used for clock and GPIO control.
#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
I always like to have my definitions and global variables below my library inclusions so next come these:
//Define interrupt rates
#define MillisecondsIT 1e3 //LED Definitions
#define GLed GPIO_Pin_9
#define BLed GPIO_Pin_8
#define LEDGPIO GPIOC
//Button Definitions
#define PushButton GPIO_Pin_0
#define PushButtonGPIO GPIOA
//Define time keeping variables
volatile uint32_t Milliseconds = 0, Seconds = 0;
As with my previous tutorial on GPIO usage, the buttons and GPIO’s are defined to make the code much more readable and portable. The first define, “MillisecondIT” is used to set the rate at which the interrupt is fired. Unfortunately at a 48MHz clock (set further on in the code by SystemInit) doesn’t allow for a 1 second interrupt rate as 2^24 is less than 48MHz. The two variables at the bottom, “Milliseconds” and “Seconds” are both incremented with in the interrupt and contain the amount of milliseconds and seconds since the while loop had started. To keep to a standard project layout, after the global variable definitions come my interrupt handler. Inside of this handler, the Millisecond variable is incremented and a small bit of code is used to increment the Seconds variable every time 1000 milliseconds has passed. The code for the interrupt handler is:
void SysTick_Handler(void){
Milliseconds++; //Increment millisecond variable
if(Milliseconds%1000 == 999){ //If 1000 milliseconds have passed, increment seconds
Seconds++;
}
}
What is happening here is relatively simple. Every time the SysTick timer overflows, the microcontroller calls the function SysTick_Handler(void) as this function is called essentially from nowhere, nothing can be passed to or returned from the function so it therefore takes no variables (void) and sends no variables on exit (declared as void function). Inside of this interrupt handler, the Milliseconds variable is incremented. If the Milliseconds variable divided by 1000 has a remainder of 999 (modulo gives the remainder after division), the Seconds variable is incremented. This causes the Seconds variable to be incremented every 1000 milliseconds. If processor speed is not a problem and one would rather use a memory based method, a Current Milliseconds – Previous Milliseconds > 999 method could be used though this method isn’t drastically slow.
Now that one of the hardest parts is out of the way, the next functions allow the microcontroller to delay for a given amount of time. Note: A single line of assembly is used in this section though its not hard to understand. The code for second and millisecond delay is as follows:
//Delay function for millisecond delay void DelayMil(uint32_t MilS){
volatile uint32_t MSStart = Milliseconds;
while((Milliseconds – MSStart)<MilS) asm volatile(“nop”);
}
//Delay function for second delay void DelaySec(uint32_t S){
volatile uint32_t Ss = Seconds;
while((Seconds – Ss)<S) asm volatile(“nop”);
}
As can be seen, both functions essentially have the same method of delay. All that is happening here is a variable is set to the “seconds” or “milliseconds” when the function is entered (stored in either Ss for seconds or MSStart for milliseconds), a while loop then continuously checks whether the current value of seconds or milliseconds, minus the initial function entry value is less than the delay time passed by the user. For example, in the millisecond delay function, when Milliseconds – MSStart is less than MilS then the while loop will continue to execute. once Milliseconds – MSStart is more than MilS, the while loop will exit along with the delay function. In both of the while loops is a small nugget of code: asm volatile(“nop”);, all that this code says is “execute the assembly instruction nop (no operation)”, the volatile statement is there to ensure the compiler doesn’t optimize the useless statement away. None of my tutorial code will have any optimization for ease of debugging, unless of course, it is about optimization.

The current code up to now. The final code will be available at the bottom!
So far, the two delay functions, along with the SysTick Handler function have been written. From now, it’s just standard code to setup the SysTick timer, along with the GPIOs. Onwards with the int main()!
int main(){
SystemInit(); //Ensure CPU is running at correctly set clock speed
SystemCoreClockUpdate(); //Update SystemCoreClock variable to current clock speed
SysTick_Config(SystemCoreClock/MillisecondsIT); //Set up a systick interrupt every millisecond
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); //Enable GPIO clock for GPIOC (LED GPIOs)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //Enable GPIO clock for GPIOA (Button GPIO)
//Initialize LED GPIO’s as outputs
G.GPIO_Pin = BLed | GLed;
G.GPIO_Mode = GPIO_Mode_OUT;
G.GPIO_PuPd = GPIO_PuPd_NOPULL;
G.GPIO_Speed = GPIO_Speed_Level_1;
G.GPIO_OType = GPIO_OType_PP;
GPIO_Init(LEDGPIO, &G);
//Initialize push button as input
G.GPIO_Pin = PushButton;
G.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(PushButtonGPIO, &G);
//Initialize a variable to keep current LED state
uint8_t ToggleVar = 1;
//Set time variables to zero at the start of the infinite loop
Milliseconds = Seconds = 0;
Most of the comments are self explanatory though I’ll explain more so regardless. When the PLL values are set for the STM32F0xx series clock, you need to tell the processor to use them instead of the internal 8MHz oscillator as the main system clock. You can modify the startup file for this though its just as easy to add it as a function call at the top of your code using the call SystemInit(). Now that the clock has been successfully initialized, the system clock speed should be updated just for safe keeping. This can be easily done using a function named SystemCoreClockUpdate(). In the STM32F0xx peripheral files is a global variable named SystemCoreClock. This variable contains the calculated processor frequency in Hz and is really useful for all sorts of calculations based on the clock rate, for example in the next function below.
The next function is the one that actually sets the rate at which the SysTick interrupt is fired. Theoretically, if the value sent to the function SysTick_Config() was equal to the CPU clock, the timer would overflow every second meaning: Overflow time = SystemCoreClock / ValueSentToFunction. As I want the timer to overflow every millisecond, I need the ValueSentToFunction to equal 1000 as x/1000 is equal to x*0.001. If I wanted the timer to overflow every microsecond (1e-6 seconds), ValueSentToFunction would need to be equal to 1e6.
SysTick_Config(SystemCoreClock/MillisecondsIT); //Set up a systick interrupt every millisecond
After the initialization of the CPU clock, along with the SysTick timer, the next few lines of code are really simple if you’ve read my past tutorial, due to this, I won’t cover them in this tutorial.
The next two lines of code initialize three variables. One of such being ToggleVar which stores the current state of the LED’s and the other line resets Milliseconds and Seconds to zero.
Finally, comes the main loop that is continuously executed. Inside of this loop consists of two LED writes depending on ToggleVar, along with a button read and a delay. The code is as follows:
while(1)
{
//Toggle the variable ToggleVar between each LED
ToggleVar = ~ToggleVar;
//If ToggleVar is equal to 1, turn on green led and turn blue led off
if(ToggleVar == 1){
GPIO_SetBits(LEDGPIO, GLed);
GPIO_ResetBits(LEDGPIO, BLed);
}
else{ //Otherwise, flip LEDs
GPIO_ResetBits(LEDGPIO, GLed);
GPIO_SetBits(LEDGPIO, BLed);
}
if(GPIO_ReadInputDataBit(PushButtonGPIO, PushButton) == SET){ //If Push button is pressed
DelaySec(1); //Delay for a second between toggles
}
else{ //If Push button isn’t pressed
DelayMil(100); //Delay for 100ms between toggles
}
}
With the comments, I’d hope the code is pretty self explanatory but I’ll go through it just incase! Everytime the loop is executed, the value stored in ToggleVar is inverted, meaning ToggleVar will always go between 1 and 254 (uint8_t maximum size is 255, – 1 = 254). The section below says “If ToggleVar is equal to 1, turn the green LED on and the blue LED off, otherwise turn the green LED off and the blue LED on”. The final piece of code depicts the rate of the LED flicker. All it says is “if PushButton is pressed, set toggle rate to 1 second, otherwise if the button isn’t pressed, set toggle rate to 100 milliseconds”. Thats the end of the code!
I’ve taken photos of the LED’s toggling though its quite hard to see in a static picture that the rate of toggle is dependent on the button press!

Initial state, toggling at 10Hz, A bit hard to see in a photo but they are, honest!

Pressing the user button causes the toggle rate to slow to 1Hz.
And so, the final code is:
#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
//Define interrupt rates
#define MillisecondsIT 1e3
//LED Definitions
#define GLed GPIO_Pin_9
#define BLed GPIO_Pin_8
#define LEDGPIO GPIOC
//Button Definitions
#define PushButton GPIO_Pin_0
#define PushButtonGPIO GPIOA
//Define time keeping variables
volatile uint32_t Milliseconds = 0, Seconds = 0;
//Systick interrupt handler, interrupts at “interrupt rate” per second
//Currently set to interrupt at millisecond intervals
void SysTick_Handler(void){
Milliseconds++; //Increment millisecond variable
if(Milliseconds%1000 == 999){ //If 1000 milliseconds have passed, increment seconds
Seconds++;
}
}
//Delay function for millisecond delay
void DelayMil(uint32_t MilS){
volatile uint32_t MSStart = Milliseconds;
while((Milliseconds – MSStart)<MilS) asm volatile(“nop”);
}
//Delay function for second delay
void DelaySec(uint32_t S){
volatile uint32_t Ss = Seconds;
while((Seconds – Ss)<S) asm volatile(“nop”);
}
//GPIO type def initialization
GPIO_InitTypeDef G;
int main(void)
{
SystemInit(); //Ensure CPU is running at correctly set clock speed
SystemCoreClockUpdate(); //Update SystemCoreClock variable to current clock speed
SysTick_Config(SystemCoreClock/MillisecondsIT); //Set up a systick interrupt every millisecond
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); //Enable GPIO clock for GPIOC (LED GPIOs)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //Enable GPIO clock for GPIOA (Button GPIO)
//Initialize LED GPIO’s as outputs
G.GPIO_Pin = BLed | GLed;
G.GPIO_Mode = GPIO_Mode_OUT;
G.GPIO_PuPd = GPIO_PuPd_NOPULL;
G.GPIO_Speed = GPIO_Speed_Level_1;
G.GPIO_OType = GPIO_OType_PP;
GPIO_Init(LEDGPIO, &G);
//Initialize push button as input
G.GPIO_Pin = PushButton;
G.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(PushButtonGPIO, &G);
//Initialize a variable to keep current LED state
uint8_t ToggleVar = 1;
//Set time variables to zero at the start of the infinite loop
Milliseconds = Seconds = 0;
while(1)
{
//Toggle the variable ToggleVar between each LED
ToggleVar = ~ToggleVar;
//If ToggleVar is equal to 1, turn on green led and turn blue led off
if(ToggleVar == 1){
GPIO_SetBits(LEDGPIO, GLed);
GPIO_ResetBits(LEDGPIO, BLed);
}
else{ //Otherwise, flip LEDs
GPIO_ResetBits(LEDGPIO, GLed);
GPIO_SetBits(LEDGPIO, BLed);
}
if(GPIO_ReadInputDataBit(PushButtonGPIO, PushButton) == SET){ //If Push button is pressed
DelaySec(1); //Delay for a second between toggles
}
else{ //If Push button isn’t pressed
DelayMil(100); //Delay for 100ms between toggles
}
}
}
The whole project can be found at my github repository!
https://github.com/pyrohaz/STM32F0-Discovery-SysTick-Tutorial
Hope this tutorial has helped some of you learn the simple use of the SysTick timer.
Keep tuned for more STM32F0 tutorials!
I read a lot of interesting content here. Probably you spend a lot
of time writing, i know how to save you a lot of time, there is an online tool that creates
readable, google friendly posts in seconds, just search in google – laranita free content
there will be no problem of overflow ?
Well the interrupt is fired every time the SysTick timer overflows though I’m assuming you mean overflow of the MSec variable. Theoretically, MSec can overflow though this will happen after 2^32-1 milliseconds which is equivalent to about 7 weeks! At any point that the system is reset, it will restart the MSec counter.
oh ! ok thank you. I didn’t make the calculus
Effectively 7 weeks without one reset has few chance to happen.
Yep! If you’re using the MSec counter for timing, e.g:
if((MSec-MSecOld)>10){
Code
}
Then you can add another check like:
if((MSec10){
Code
}
}
else if(MSec>=MSecOld){
if((MSec-MSecOld)>10){
Code
}
}
The top condition works because subtracting one smaller number from a larger number using unsigned arithmetic will cause it to rollover, giving you the difference between the two as variable overflow causes the number to wrap around from 2^32-1 to 0.