
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
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.
Wait for advanced section of timers in upcoming weeks.
Add Comment