Building Board Support Package (BSP) for STM32F411-Nucleo64 Part3: System Tick implementation

In the previous guide (here), we took a look how to build core configuration for STM32F411. In this guide, we shall see how to use System Time (SysTick) to implement system tick in your board support package.

In this guide, we shall cover the following:

  • What is system tick in embedded systems.
  • System Tick implementation.
  • Code.
  • Result.

1. What is system tick in embedded system:

The system tick is the time unit that OS timers and delays are based on. The system tick is a scheduling event – i.e. it causes the scheduler to run and may cause a context switch – for example if a timer has expired or a task delay completed.

In shoot, it is the heart of the embedded system.

2. System Tick implementation:

Within the bsp.h header file, declare the following three functions:

void BSP_Ticks_Init(uint32_t freq);

The function take frequency (freq) as an argument and return nothing (void).

uint32_t BSP_Get_Ticks(void);

The function takes no argument and return the current time in milliseconds.

void BSP_Delay(uint32_t delay_ms);

This function will force delay the CPU and it takes the delay amount in milliseconds as argument and returns nothing.

Thats all for the header file.

For more details how to configure the systick, please refer to this guide here.

In bsp.c source file, declare the following volatile:

volatile uint32_t ticks;

This will hold the ticks of the system and it will be incremented in the interrupt handler. Hence, the volatile keyword.

For tick initialising:

void BSP_Ticks_Init(uint32_t freq)
{
	/*Load the SysTick value to be the core frequency over 1000
	 *
	 * Since the core frequency is in MHz, dividing it by 1000 will get 1ms period
	 * */
	SysTick->LOAD=(freq/1000)-1;

	/*Set the source to be internal core clock*/
	SysTick->CTRL=(1<<SysTick_CTRL_CLKSOURCE_Pos);

	/*Enable The interrupt */

	SysTick->CTRL|=(1<<SysTick_CTRL_TICKINT_Pos);

	/*Enable Systick Interrupt in NIVC*/

	NVIC_EnableIRQ(SysTick_IRQn);

	/*Enable Systick*/
	SysTick->CTRL|=(1<<SysTick_CTRL_ENABLE_Pos);

}

SysTick interrupt handler:

void SysTick_Handler(void)
{
	ticks++;
}

Get tick function:

uint32_t BSP_Get_Ticks(void)
{
	uint32_t current_ticks;
	__disable_irq();
	current_ticks=ticks;
	__enable_irq();
	/*Return the counter value*/
	return current_ticks;
}

Since we need to return a volatile variable, it is recommend to do the following:

  • Disable global variable.
  • Store the volatile variable in local variable.
  • Enable the global variable.
  • Return the local variable.

This way, you will eliminate whats called race condition.

For delay function:

void BSP_Delay(uint32_t delay_ms)
{

	uint32_t ticks_start=BSP_Get_Ticks();

	while(BSP_Get_Ticks()-ticks_start<delay_ms);
}

This delay will spin lock the CPU for doing nothing to achieve the delay.

Thats all for the source file.

In main.c file:

#include "bsp.h"

GPIO_Output_Typedef LED;


Clock_Config_Typedef clockConfig;



int main()
{



	GPIOA_CLOCK_ENABLE();

	GPIO_Configure_Typedef LED_Config;

	LED_Config.PinNumber=pin5;
	LED_Config.Mode=OUTPUT;

	LED.pinNumber=pin5;

	GPIO_Initialization(GPIOA,&LED_Config);

	clockConfig.PLL_M= 4;
	clockConfig.PLL_N= 200;
	clockConfig.PLL_P= 4;

	clockConfig.AHB1Prescaler=AHB1_Prescaler1;
	clockConfig.APB1Prescaler=APB1_Prescaler2;
	clockConfig.APB2Prescaler=APB2_Prescaler1;

	clockConfig.clockSourc=External_Oscillator;
	clockConfig.flash_latency= Three_wait_state;

	Clock_Confgiuration(&clockConfig);

	BSP_Ticks_Init(100000000);


	while(1)
	{

		GPIO_TogglePin(GPIOA, &LED);
		BSP_Delay(1000);
	}

}


3. Code:

You may download the source code from here:

4. Results:

By testing the delay function, we can make sure that everything related to systick is working:

By using 1000ms delay, we shall get toggle rate of 1Hz.

Happy coding 🙂

Add Comment

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