Input capture principle and configuration

1. General timer input capture overview

1.STM32 input capture process

2.STM32 input capture process (channel 1 as an example)

By detecting the edge signal on TIMx_CHx, when the edge signal jumps (such as rising edge/falling edge), the current timer value (TIMx_CNT) is stored in the corresponding capture/compare register (TIMx_CCRx) to complete a capture .

1) Step 1: Set the input capture filter (channel 1 as an example)

2) Step 2: Set the input capture polarity (channel 1 as an example)

3) Step 3: Set the input capture mapping channel (channel 1 as an example)

4) Step 4: Set the input capture divider (channel 1 as an example)

5) Step 5: When a valid signal is captured, the interrupt can be enabled

6) Take the corresponding pin TIM5 of the timer channel as an example

2. Commonly used registers and library function configuration

1. The file where the basic functions and definitions of general timers are located

Stm32fxxx_hal_tim.c
 Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
Stm32fxxx_hal_tim.h
 Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c - Stm32fxxx_hal_tim.h

2. Common functions of timer input capture function

Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c - Stm32fxxx_hal_tim.h

1) Timer input capture time base parameter initialization function:

HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c

This function is the same as the HAL_TIM_Base_Init/HAL_TIM_PWM_Init function, the difference is that different callback functions are called.

typedef struct
{
	uint32_t Prescaler; 						//Prescale factor
	uint32_t CounterMode; 				//Counting Mode: Up/Down
	uint32_t Period; 							//autoload value
	uint32_t ClockDivision; 				//Clock divider factor: Timer clock to digital filter divider ratio
	uint32_t RepetitionCounter; 		//Repeat count times: Advanced timer use
} TIM_Base_InitTypeDef;

2) Timer input capture time base parameter initialization callback function

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim);
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c

It is mainly used to write timer clock enable, channel IO configuration and interrupt priority setting.

__HAL_RCC_TIM5_CLK_ENABLE();		//Timer 3 clock enable

3) Input capture channel parameter configuration function

HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef htim,TIM_IC_InitTypeDef sConfig, uint32_t Channel);
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c

typedef struct
{
	uint32_t ICPolarity; 			//capture polarity
	uint32_t ICSelection; 		//input mapping
	uint32_t ICPrescaler;		 //input divider
	uint32_t ICFilter; 				//input filter
} TIM_IC_InitTypeDef

4) Enable the timer and enable the input capture channel

HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel);
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c

HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);
Location: Project File - HALLIB - Stm32fxxx_hal_tim.c

This function also enables capture interrupts.

5) Capture interrupt callback function

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c

Similar to the interrupt service function, we can write the function logic related to capture in it

6) Read the captured value

uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef *htim,uint32_t Channel);
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c

3. Enter the general configuration key steps for capture:

①Enable timer clock and channel IO port clock.

②Configure IO port multiplexing mapping: HAL_GPIO_Init();

③Initialize the input capture time base parameters: HAL_TIM_IC_Init();

④Initialize input capture channel parameters: HAL_TIM_IC_ConfigChannel();

⑤Enable the timer (interrupt), set the priority: HAL_TIM_IC_Start_IT();

⑥ Write interrupt service callback function: HAL_TIM_IC_CaptureCallback();

3. Input capture experiment
1. Experimental purpose: measure the pulse width of the signal

Use the wake_up button on the board to simulate the pulse, then use the input capture to measure the duration of the high level and print it out through the serial port

Proceed as follows
①Enable timer clock and channel IO port clock.

②Configure IO port multiplexing mapping: HAL_GPIO_Init();

③Initialize the input capture time base parameters: HAL_TIM_IC_Init();

④Initialize input capture channel parameters: HAL_TIM_IC_ConfigChannel();

⑤Enable the timer (interrupt), set the priority: HAL_TIM_IC_Start_IT();

⑥ Write interrupt service callback function: HAL_TIM_IC_CaptureCallback();

2. Interpretation of the timer.c file

Location: Project File - HARDWARE - timer.c
code show as below:

#include "timer.h"
#include "led.h"

TIM_HandleTypeDef TIM3_Handler;         //Timer 3PWM handle 
TIM_OC_InitTypeDef TIM3_CH4Handler;	    //Timer 3 channels 4 handles

/***************************************************************************
****************************************************************************
  The following is the source code of the PWM output experiment related functions
****************************************************************************
****************************************************************************/
//TIM3 PWM part initialization 
//PWM output initialization
//arr: auto-reload value
//psc: clock prescaler
void TIM3_PWM_Init(u16 arr,u16 psc)
{ 
    TIM3_Handler.Instance=TIM3;            //timer 3
    TIM3_Handler.Init.Prescaler=psc;       //Timer divider
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//count up mode
    TIM3_Handler.Init.Period=arr;          //auto-reload value
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM3_Handler);       //Initialize PWM
    
    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //Mode select PWM1
    TIM3_CH4Handler.Pulse=arr/2;            //Set the comparison value, this value is used to determine the duty cycle,
                                            //The default comparison value is half of the auto-reload value, i.e. a duty cycle of 50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; //The output compare polarity is low 
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//Configure TIM3 channel 4
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//Turn on PWM channel 4
}

//Timer bottom layer driver, clock enable, pin configuration
//This function will be called by HAL_TIM_PWM_Init()
//htim: timer handle
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
		
	__HAL_RCC_TIM3_CLK_ENABLE();			//enable timer 3
    __HAL_RCC_GPIOB_CLK_ENABLE();			//Enable GPIOB clock
	
    GPIO_Initure.Pin=GPIO_PIN_1;           	//PB1
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;  	//Multiplexed push output
    GPIO_Initure.Pull=GPIO_PULLUP;          //pull up
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //high speed
	GPIO_Initure.Alternate= GPIO_AF2_TIM3;	//PB1 is multiplexed as TIM3_CH4
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}

//Set the duty cycle of TIM channel 4
//compare: compare values
void TIM_SetTIM3Compare4(u32 compare)
{
	TIM3->CCR4=compare;
}

//Get TIM capture/compare register value
u32 TIM_GetTIM3Capture4(void)
{
	return  HAL_TIM_ReadCapturedValue(&TIM3_Handler,TIM_CHANNEL_4);
}


/***************************************************************************
****************************************************************************
  The following is the input capture related source code experiment related function source code
****************************************************************************
****************************************************************************/
TIM_HandleTypeDef TIM5_Handler;         //Timer 5 handle

//Timer 5 Channel 1 Input Capture Configuration
//arr: auto-reload value (TIM2,TIM5 are 32 bits!!)
//psc: clock prescaler
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{  
    TIM_IC_InitTypeDef TIM5_CH1Config;  
    
    TIM5_Handler.Instance=TIM5;                         	 //General purpose timer 5
    TIM5_Handler.Init.Prescaler=psc;                    	 //Frequency division factor
    TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;   	 //up counter
    TIM5_Handler.Init.Period=arr;                        	 //autoload value
    TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;	 //clock divider
    HAL_TIM_IC_Init(&TIM5_Handler);							 //Initialize input capture time base parameters
    
    TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING;    	//Rising edge capture
    TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;	//Mapped to TI1
    TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1;          	//Configure input frequency division, no frequency division
    TIM5_CH1Config.ICFilter=0;                          	//Configure input filter, no filter
    HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);//Configure TIM5 channel 1
	
    HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1);  		 //Enable capture channel 1 of TIM5 and enable capture interrupt
    __HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE);   	 //Enable update interrupt
}

//Timer 5 bottom layer driver, clock enable, pin configuration
//This function will be called by HAL_TIM_IC_Init()
//htim: Timer 5 handle
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;				//Initialize GPIO
	if(htim -> Instance == TIM5)				//Determine whether timer 5 triggers an interrupt
	{
		__HAL_RCC_TIM5_CLK_ENABLE();            //Enable TIM5 clock
		__HAL_RCC_GPIOA_CLK_ENABLE();			//Enable GPIOA clock
		
		GPIO_Initure.Pin=GPIO_PIN_0;            //PA0
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;      //Multiplexed push-pull output
		GPIO_Initure.Pull=GPIO_PULLDOWN;        //drop down
		GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //high speed
		GPIO_Initure.Alternate=GPIO_AF2_TIM5;   //PA0 is multiplexed into TIM5 channel 1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);

		HAL_NVIC_SetPriority(TIM5_IRQn,2,0);    //Set interrupt priority, preempt priority 2, sub priority 0
		HAL_NVIC_EnableIRQ(TIM5_IRQn);          //Enable ITM5 interrupt channel  
	}
}

//capture state
//[7]: 0, no successful capture; 1, one successful capture.
//[6]: 0, the low level has not been captured; 1, the low level has been captured.
//[5:0]: The number of overflows after capturing the low level (for 32-bit timers, the 1us counter is incremented by 1, and the overflow time: 4294 seconds)
u8  TIM5CH1_CAPTURE_STA=0;	//input capture state		    				
u32	TIM5CH1_CAPTURE_VAL;	//Input capture value (TIM2/TIM5 are 32 bits)

//Timer 5 interrupt service function
void TIM5_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&TIM5_Handler);//Timer common processing function
}
 
//Timer update interrupt (count overflow) interrupt processing callback function, this function will be called in HAL_TIM_IRQHandler
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//Executed when an update interrupt (overflow) occurs
{
	
	if((TIM5CH1_CAPTURE_STA&0X80)==0)//Not yet successfully captured
	{
			if(TIM5CH1_CAPTURE_STA&0X40)//high level has been captured
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//high level too long
				{
					TIM5CH1_CAPTURE_STA|=0X80;		//Marker successfully captured once
					TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
				}else TIM5CH1_CAPTURE_STA++;
			}	 
	}		
}

//Timer input capture interrupt processing callback function, which will be called in HAL_TIM_IRQHandler
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//Executed when a capture interrupt occurs
{
	if((TIM5CH1_CAPTURE_STA&0X80)==0)//Not yet successfully captured
	{
		if(TIM5CH1_CAPTURE_STA&0X40)		//captured to a falling edge 		
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//The marker successfully captures a high-level pulse width
                TIM5CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&TIM5_Handler,TIM_CHANNEL_1);//Get the current capture value.
                TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);   //Be sure to clear the original settings first! !
                TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//Configure TIM5 channel 1 rising edge capture
			}else  								//Not yet started, first capture rising edge
			{
				TIM5CH1_CAPTURE_STA=0;			//empty
				TIM5CH1_CAPTURE_VAL=0;
				TIM5CH1_CAPTURE_STA|=0X40;		//Flag captures the rising edge
				__HAL_TIM_DISABLE(&TIM5_Handler);        //turn off timer 5
				__HAL_TIM_SET_COUNTER(&TIM5_Handler,0);
				TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);   //Be sure to clear the original settings first! !
				TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//Timer 5 channel 1 is set to capture on falling edge
				__HAL_TIM_ENABLE(&TIM5_Handler);//enable timer 5
			}		    
	}		
}

It can be seen that the code is divided into two parts, the upper part is the PWM part, the following is the input capture related code, and the following focuses on the input capture related code.

1) Timer 5 channel 1 input capture configuration

The settings here are the same as the ordinary timer settings. For details, please refer to the previous notes.
TIM5_Handler.Init.Prescaler=psc; //Frequency division coefficient
This paragraph determines the sampling frequency of input capture, because the fundamental frequency of F429 is 90Mhz,
The sampling frequency of input capture here = base frequency is 90Mhz/(frequency division factor + 1)

TIM5_Handler.Init.Period=arr; //Auto load value
Determine the timer overflow time. After writing the auto-load value, an interrupt will be generated after the counter counts from 0 to the auto-load value.

The following is the input capture channel parameter configuration code:
TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //Rising edge capture
Set the capture polarity, that is, capture the rising edge or the falling edge

TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; //Mapped to TI1
Which channel to map the captured instruction to, F429 has four channels: TI1, TI2, TI3, TI4

TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division
The frequency division here means that several events are captured to trigger an interrupt. The specific corresponding registers are in this article: 1. 2. 4) Set the input capture divider (channel 1 as an example)

TIM5_CH1Config.ICFilter=0; //Configure the input filter without filtering

HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);//Configure TIM5 channel 1

2) Write input capture callback function

Note that PA0 is set to pull-down mode here, that is, it outputs a low level when there is no response to capture.

3) Interrupt service function, timer update interrupt

Because the button is pressed and not released, the counter will continue to count, and the limited value of the counter may cause overflow, so we need to update the timer interrupt, the program is as shown above

3. Interpretation of the main.c file

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"

extern u8  TIM5CH1_CAPTURE_STA;		//input capture state		    				
extern u32	TIM5CH1_CAPTURE_VAL;	//Enter capture value 

int main(void)
{
    long long temp=0;  
    HAL_Init();                     	//Initialize the HAL library   
    Stm32_Clock_Init(360,25,2,8);   	//Set clock, 180Mhz
    delay_init(180);               	 	//Initialize delay function
    uart_init(115200);             		//Initialize USART
    LED_Init();                     	//Initialize the LED s 
    TIM3_PWM_Init(500-1,90-1);      	//90M/90=1M count frequency, auto reload is 500, then PWM frequency is 1M/500=2kHZ
    TIM5_CH1_Cap_Init(0XFFFFFFFF,90-1); //Count at 1MHZ
    while(1)
    {
        delay_ms(10);
		TIM_SetTIM3Compare4(TIM_GetTIM3Capture4()+1); 
		if(TIM_GetTIM3Capture4()==300)TIM_SetTIM3Compare4(0);        
        if(TIM5CH1_CAPTURE_STA&0X80)        //A high level was successfully captured
		{
			temp=TIM5CH1_CAPTURE_STA&0X3F; 
			temp*=0XFFFFFFFF;		 	    //sum of overflow time
			temp+=TIM5CH1_CAPTURE_VAL;      //get the total high time
			printf("HIGH:%lld us\r\n",temp);//Print the total high average time
			TIM5CH1_CAPTURE_STA=0;          //Start the next capture
		}
    }
}

So far, the input capture experiment code is explained

Posted by andrew6607 on Tue, 18 Oct 2022 10:16:46 +0300