stm32 input capture measures the frequency of pwm wave

1. The concept of input capture

In STM32 microcontrollers, input capture is a function used to measure external signal parameters. It is implemented through the timer module and can measure the frequency, duty cycle, pulse width, etc. of the signal.

Input capture timer based counter and capture compare unit. When the capture trigger condition is met, the value of the timer’s counter is captured and stored in the relevant registers of the capture comparison unit, and then the capture value can be obtained by reading these registers.

2. Principle and circuit

every capture
/
Compare channels are captured around a
/
Compare registers (including a shadow register), a capture input stage

sections (digital filtering, multiplexing and prescaler) and an output stage (comparator and output control).

The figure below provides an overview of a capture
/
Compare channels.

The input stage pairs the corresponding
TIx
The input is sampled and a filtered signal is generated.
f
. Then, with polarity selection function

An edge detector capable of generating a signal
(TIxFPx)
, this signal can be used as the trigger input of the slave mode controller or as

capture command. The signal is first pre-divided
(ICxPS)
, and then enter the capture register.

Capture
/
The compare module consists of a preload register and a shadow register. Preloads are always accessible through read and write operations

register.

In capture mode, the capture actually occurs in the shadow register, and then the contents of the shadow register are copied to the preload register

in the vessel.

In compare mode, the contents of the preload register are copied to the shadow register, and then the contents of the shadow register are compared with the calculated

Counter for comparison.

3. Input capture mode features

In input capture mode, when the corresponding
ICx
After the signal detects a transition edge, a capture
/
compare register
(TIMx_CCRx)

to latch the counter value. When a capture event occurs, the corresponding
CCXIF
flag (
TIMx_SR
register) set
1
,

and can send an interrupt or
DMA
request (if enabled). If a capture event occurs
CxI
The flag is already at a high level,

will duplicate the capture flag
CxO
(
TIMx_SR
register) set
1
. Available through software
CxI
write
0
Come and give

CxI
cleared, or read stored in
TIMx_CCRx
Captured data in register. Towards
CxO
write
0
will be discussed later

Its cleared.

4. Code

1. Use timer 14 to generate a square wave with a fixed frequency

void TIM14_PWM_Init(u32 arr,u32 psc)
{
//This part requires manual modification of the IO port settings
\t
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
\t
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM14 clock enable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //Enable PORTF clock
\t
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9 multiplex bit timer 14
\t
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIOF9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//Multiplex function
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Speed 100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull multiplexing output
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //Pull-up
GPIO_Init(GPIOF, & amp;GPIO_InitStructure); //Initialize PF9
\t
TIM_TimeBaseStructure.TIM_Prescaler=psc; //Timer frequency division
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //Up counting mode
TIM_TimeBaseStructure.TIM_Period=arr; //Automatically reload value
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
\t
TIM_TimeBaseInit(TIM14, & amp;TIM_TimeBaseStructure);
\t
//Initialize TIM14 Channel1 PWM mode
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //Select timer mode: TIM pulse width modulation mode 2
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Compare output enable
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //Output polarity: TIM output has higher polarity
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM14, & TIM_OCInitStructure); //Initialize the peripheral TIM3 OC2 according to the parameters specified by T

TIM_OC2PreloadConfig(TIM14, TIM_OCPreload_Enable); //Enable the preload register of TIM3 on CCR2
 
  TIM_ARRPreloadConfig(TIM14,ENABLE);
\t
TIM_Cmd(TIM14, ENABLE); //Enable TIM14

} 

Input capture initialization

#define TIMx TIM3
#define TIMx_CLK RCC_APB1Periph_TIM3
#define TIMx_IRQn TIM3_IRQn
#define TIMx_IRQHandler TIM3_IRQHandler

#define TIMx_CHANNEL TIM_Channel_1
#define TIMx_GPIO_PORT GPIOA
#define TIMx_GPIO_CLK RCC_AHB1Periph_GPIOA
#define TIMx_PIN GPIO_Pin_6
#define TIMx_SOURCE GPIO_PinSource6
#define TIMx_AF GPIO_AF_TIM3


volatile uint32_t capture1 = 0;
volatile uint32_t capture2 = 0;
volatile uint32_t timeDifference = 0;


void PWM_Capture_Init()
{
GPIO_InitTypeDef gpioInitStruct;
TIM_ICInitTypeDef icInitStruct;
    NVIC_InitTypeDef nvicInitStruct;
TIM_TimeBaseInitTypeDef timeBaseInitStruct;
    
    RCC_AHB1PeriphClockCmd(TIMx_GPIO_CLK, ENABLE);//GPIO enable
RCC_APB1PeriphClockCmd(TIMx_CLK, ENABLE);//TIM clock enable
    
    gpioInitStruct.GPIO_Pin = TIMx_PIN;
    gpioInitStruct.GPIO_Mode = GPIO_Mode_AF; //Multiple functions
    gpioInitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    gpioInitStruct.GPIO_OType = GPIO_OType_PP;
    gpioInitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(TIMx_GPIO_PORT, & amp;gpioInitStruct);

    GPIO_PinAFConfig(TIMx_GPIO_PORT, TIMx_SOURCE, TIMx_AF);//Port multiplexing timer 5
    timeBaseInitStruct.TIM_Period = 65535; //1MHZ/10=100kHZ
    timeBaseInitStruct.TIM_Prescaler = 84-1; //High frequency does not divide by 0 // Assume that the CPU frequency is 84 MHz 84000000/84=1MHZ
    timeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    timeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//up counting mode
    timeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIMx, & timeBaseInitStruct);

    icInitStruct.TIM_Channel = TIMx_CHANNEL;
    icInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//rising edge capture
    icInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//Mapped to TI1
    icInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//Configure input frequency division, no frequency division
    icInitStruct.TIM_ICFilter = 0x0;//IC1F=0000 configure input filter without filtering
    TIM_ICInit(TIMx, & icInitStruct);
    
    TIM_ClearITPendingBit(TIMx, TIM_IT_CC1);//Clear flag bit
    TIM_ITConfig(TIMx, TIM_IT_CC1, ENABLE); //Allow update interrupt

    nvicInitStruct.NVIC_IRQChannel = TIMx_IRQn;
    nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 2;//Preemption priority
    nvicInitStruct.NVIC_IRQChannelSubPriority = 0;//Sub priority
    nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;//IRQ channel enable
    NVIC_Init( & amp;nvicInitStruct);//Initialize the VIC register according to the specified parameters

    TIM_Cmd(TIMx, ENABLE);//Enable timer
}



uint32_t PWM_Capture_GetFreq()
{
if(capture1>capture2)
{
timeDifference=(65535-capture1) + capture2;
}
return (int)1000000/timeDifference;

}


void TIMx_IRQHandler(void) {
    if (TIM_GetITStatus(TIMx, TIM_IT_CC1) != RESET) {
        if (capture1 == 0) {
            capture1 = TIM_GetCapture1(TIMx);
        } else if (capture2 == 0) {
            capture2 = TIM_GetCapture1(TIMx);
            timeDifference = capture2 - capture1;
        }
        TIM_ClearITPendingBit(TIMx, TIM_IT_CC1);
    }
}

Called in main function

int main(void)
{
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//Set system interrupt priority group 2

 TIM14_PWM_Init(50000-1,84-1); //The counting frequency of 84M/84=1Mhz counts to 500, and the PWM frequency is 1M/500=2Khz
PWM_Capture_Init();
uart_init(115200);
TIM_SetCompare1(TIM14,30000);
printf("Initialization successful\
");
\t
\t
while(1)
{
printf("The captured frequency is: %dhz\
",PWM_Capture_GetFreq());
delay_ms(500); //delay 500ms
}
}