STM32F0 Tutorial 2 – SysTick

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:

Image
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! Image
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.

Image
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!

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

Image
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!

Advertisements

5 responses to “STM32F0 Tutorial 2 – SysTick

  1. 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

    • 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.

  2. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s