Systick Interrupt: Periodic Tasks

In pervious two guides we took look at how to use systick timer to blink an led without using delay (here) and how to use interrupt to blink multiple led (here). In this guide, we shall use systick timer to handle multiple periodic tasks. Task 1 will be running each 500 milliseconds. Task 2 will be running each 1000 milliseconds and Task 3 will be running each 1500 milliseconds.

In this guide, we will cover the following:

  • What is a periodic task
  • Required parts
  • Code
  • Result

1. What is periodic tasks

A periodic task is the one that repeats after a certain fixed time interval. For example in Automotive, you set the cruise control speed to 100KMPH. The mcu keeps track the speed of the vehicle and desired speed. The rate of obtaining the speed of vehicle called periodic task. The most important feature of periodic tasks is it runs to completion, in another word, it should not include any while (1) loop.

2. Required parts

In this guide, we need only STM32F411RE Nucleo-64 no extra components needed.

3. Code

#include "stm32f4xx.h"                  // Device header
#include "stdint.h"
#include "stdio.h"
#define rate 1000
uint64_t previous;
volatile uint64_t ms,rms, periodic_1,periodic_2,periodic_3;


void USART2_Init(void);
void UART_Write_String(char *p);
uint64_t millis(void);	
void UART_Write_String(char *p);
int main(void)

{

__disable_irq();
	
	SysTick->LOAD=16000-1;
	SysTick->VAL=0;
	SysTick->CTRL=7; //0b00000111;
	
	USART2_Init(); //initialize uart2 
	
	RCC->AHB1ENR |=RCC_AHB1ENR_GPIOAEN;
	GPIOA->MODER|= GPIO_MODER_MODER5_0; //PA5 as output
	__enable_irq();

while(1)

{
if(millis()-previous>rate) //if current time is elapsed, execute the if condition 
		{
		GPIOA->ODR^=GPIO_ODR_OD5;
		previous=millis();
		}
}

}

void periodicTask1(void)
	{
		
	periodic_1++;
	UART_Write_String("periodic Task 1 \r\n");
	}

	void periodicTask2(void)
	{
	periodic_2++;
	UART_Write_String("periodic Task 2 \r\n");
	}
	
	void periodicTask3(void)
	{
	periodic_3++;
	UART_Write_String("periodic Task 3 \r\n");
	}

	
	uint64_t millis(void)
	{
	__disable_irq();
	rms=ms; //store current ms in rms
	__enable_irq();
	return rms;
	}

void SysTick_Handler(void){
ms++;
	
if(ms%500==0){periodicTask1();}	
if(ms%1000==0){periodicTask2();}	
if(ms%1500==0){periodicTask3();}	
	
}


void USART2_Init(void){
RCC->APB1ENR|=RCC_APB1ENR_USART2EN;
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
GPIOA->AFR[0]=0x0700;
GPIOA->MODER|=(1<<5);//set bit5
GPIOA->MODER&=~(1<<4);//reset bit4
USART2->BRR  = 0x0681;    //9600 @16MHz
USART2->CR1  |=0x2008; // enable tx

}

void USART_write(int ch){
while(!(USART2->SR&0x0080)){
}
USART2->DR=(ch);
	
}

void UART_Write_String(char *p)
	{
	while(*p!='\0')
{
USART_write(*p);
p++;
}
}

For how initialize systick interrupt, check this guide (here)

For UART initialization, check this guide (here) and how send a string (here)

For periodic tasks, we are check if the ms when divided by 500,1000 and 1500 return only (i.e. 3 not 3.1 ) like this

	
if(ms%500==0){periodicTask1();}	
if(ms%1000==0){periodicTask2();}	
if(ms%1500==0){periodicTask3();}	


Result

After compiling and upload the code, open teraterm and set the baudrate to 9600 and you should see this in the terminal

Notice that each two time task 1 is executed, you will get 1 execution for task 2.

Task 3 is executed after three tasks of task1 and 1 task of task2

Add Comment

Your email address will not be published. Required fields are marked *