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