Building Board Support Package (BSP) for STM32F411-Nucleo64 Part15.1: Timers in basic mode

In this 15th part of board support package, we shall develop timer driver that will overflow each 1 second and toggle LED accordingly.

In this guide, we shall cover the following:

  • Developing the header file.
  • Developing the source file.
  • Main code.
  • Results.

1. Developing the header file:

We start off by creating new header file with name of tim_bsp.h.

Within the header file:

Include the header guard as following:

#ifndef TIM_BSP_H_
#define TIM_BSP_H_



#endif /* TIM_BSP_H_ */

Within the header guard, include the following header files:

#include "stm32f4xx.h"
#include "stdint.h"

We need the main stm32f4xx header file and stdint library to handle data types of uint32_t.

Since STM32F411 has multiple timers as shown below:

We shall create macros for enabling clock for each timer as following:

/*APB2 Timers*/
#define __BSP_TIM1_CLK_ENABLE()			RCC->APB2ENR|=RCC_APB2ENR_TIM1EN
#define __BSP_TIM9_CLK_ENABLE()			RCC->APB2ENR|=RCC_APB2ENR_TIM9EN
#define __BSP_TIM10_CLK_ENABLE()		RCC->APB2ENR|=RCC_APB2ENR_TIM10EN
#define __BSP_TIM11_CLK_ENABLE()		RCC->APB2ENR|=RCC_APB2ENR_TIM11EN

/*APB1 Timers*/
#define __BSP_TIM2_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM2EN
#define __BSP_TIM3_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM3EN
#define __BSP_TIM4_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM4EN
#define __BSP_TIM5_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM5EN

Since we are interested in the checking if the timer has elapsed or not, we shall declare an enum to handle this as following:

typedef enum
{
	Counting=0,
	Elapsed=1

}Timer_Update_StatusTypedef;

You have two states:

  • Counting which means the timer has not yet elapsed.
  • Elapsed which means the timer has overflow and started over again.

Declare the following function:

void BSP_TIM_Start_Basic(TIM_TypeDef *tim, uint16_t prescaler, uint32_t max_value);

The function shall start the timer in basic mode as counter. The functions takes the three argument as following:

  • TIM_Typedef to indicate which timer to be used.
  • Prescaler to set the prescaler value.
  • max_value to set the maximum value of the timer by setting the ARR value.

And the function shall return nothing.

The second function:

Timer_Update_StatusTypedef BSP_TIM_Elapsed(TIM_TypeDef *tim);

This function will return the status of either counting or elapsed and take TIM_Typedef as argument.

Third function as following:

void BSP_TIM_Stop(TIM_TypeDef *tim);

This function will stop the timer and it takes TIM_Typedef as argument and returns nothing.

Hence, the entire header file as following:

#ifndef TIM_BSP_H_
#define TIM_BSP_H_

#include "stm32f4xx.h"
#include "stdint.h"

/*APB2 Timers*/
#define __BSP_TIM1_CLK_ENABLE()			RCC->APB2ENR|=RCC_APB2ENR_TIM1EN
#define __BSP_TIM9_CLK_ENABLE()			RCC->APB2ENR|=RCC_APB2ENR_TIM9EN
#define __BSP_TIM10_CLK_ENABLE()		RCC->APB2ENR|=RCC_APB2ENR_TIM10EN
#define __BSP_TIM11_CLK_ENABLE()		RCC->APB2ENR|=RCC_APB2ENR_TIM11EN

/*APB1 Timers*/
#define __BSP_TIM2_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM2EN
#define __BSP_TIM3_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM3EN
#define __BSP_TIM4_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM4EN
#define __BSP_TIM5_CLK_ENABLE()			RCC->APB1ENR|=RCC_APB1ENR_TIM5EN


typedef enum
{
	Counting=0,
	Elapsed=1

}Timer_Update_StatusTypedef;


void BSP_TIM_Start_Basic(TIM_TypeDef *tim, uint16_t prescaler, uint32_t max_value);

Timer_Update_StatusTypedef BSP_TIM_Elapsed(TIM_TypeDef *tim);

void BSP_TIM_Stop(TIM_TypeDef *tim);

#endif /* TIM_BSP_H_ */

2. Developing the source file:

We start off by creating new source file with name of tim_bsp.c file.

Within the source file, include the following header file:

#include "tim_bsp.h"

Now, we shall populate the functions:

For the timer start in basic mode:

void BSP_TIM_Start_Basic(TIM_TypeDef *tim, uint16_t prescaler, uint32_t max_value)
{
	tim->PSC=prescaler;
	tim->ARR=max_value;
	tim->CNT=0;
	tim->CR1|=TIM_CR1_CEN;
}

For timer if elapsed or not:

Timer_Update_StatusTypedef BSP_TIM_Elapsed(TIM_TypeDef *tim)
{
	if ((tim->SR & TIM_SR_UIF)==TIM_SR_UIF)
	{
		tim->SR &=~(1<<TIM_SR_UIF_Pos);
		return Elapsed;
	}

	else
	{
		return Counting;
	}
}

For timer stop:

void BSP_TIM_Stop(TIM_TypeDef *tim)
{
	tim->CR1&=~TIM_CR1_CEN;
}

Hence, the entire source file as following:

#include "tim_bsp.h"

void BSP_TIM_Start_Basic(TIM_TypeDef *tim, uint16_t prescaler, uint32_t max_value)
{
	tim->PSC=prescaler;
	tim->ARR=max_value;
	tim->CNT=0;
	tim->CR1|=TIM_CR1_CEN;
}

Timer_Update_StatusTypedef BSP_TIM_Elapsed(TIM_TypeDef *tim)
{
	if ((tim->SR & TIM_SR_UIF)==TIM_SR_UIF)
	{
		tim->SR &=~(1<<TIM_SR_UIF_Pos);
		return Elapsed;
	}

	else
	{
		return Counting;
	}
}

void BSP_TIM_Stop(TIM_TypeDef *tim)
{
	tim->CR1&=~TIM_CR1_CEN;
}

3. Main code:

Within main.c file:

#include "bsp.h"
#include "tim_bsp.h"

void clock_config(void);

GPIO_Output_Typedef PA5_LED;

int main()
{


	#if FPU_EN
		SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));
	#endif

	clock_config();

	BSP_Ticks_Init(100000000);

	GPIO_Configure_Typedef PA5_LED_Config;

	GPIOA_CLOCK_ENABLE();

	PA5_LED_Config.PinNumber=pin5;

	PA5_LED_Config.Mode=OUTPUT;

	PA5_LED.pinNumber=pin5;

	GPIO_Initialization(GPIOA,&PA5_LED_Config);

	__BSP_TIM2_CLK_ENABLE();

	BSP_TIM_Start_Basic(TIM2,10000,10000);




	while(1)
	{
		if(BSP_TIM_Elapsed(TIM2)==Elapsed)
		{
			GPIO_TogglePin(GPIOA,&PA5_LED);
		}

	}
}

void clock_config(void)
{
	Clock_Config_Typedef clockConfig;

	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_Configuration(&clockConfig);
}

Since the SMT32F411 is set to run at 100MHz and the APB2 is running at 100MHz, we used prescaller of 10000 and max value of 10000 which will give us 1 second toggle rate.

4. Results:

After uploading the code, you should get the following results:

Happy coding 🙂

2 Comments

  • andrei Posted March 7, 2024 8:09 am

    Thank you. That’s a lot of work you’ve done. I’ve learnt a lot. Looking forward to the sequel. Timers are particularly interesting, especially the complex modes of setting them up.

    • Husamuldeen Posted March 9, 2024 2:39 pm

      Wait for advanced section of timers in upcoming weeks.

Add Comment

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