cancel
Showing results for 
Search instead for 
Did you mean: 

INPUT CAPTURE - FREQUENCY MEASUREMENT

Khansokhua
Associate III

Hello, STM32F407G DISC-1, STMCubeIDE

I configured timer3 for generating PWM signal which is 1kHz with %70 duty cycle. I connected its pin(PB4)  to input capture channel(PA1). I use default HSI clock 16Mhz. 

I can measure this PWM signal using logic analyzer. However, when I try to calculate its duty cycle with timer5 input capture mode, I always receive those values firstRise = 15559, secondRise = 31300. My expected value, difference of them should have been 100.Since one tick is 10us , and the period the PWM signal 1ms. 100 / 100000 = 1ms. What did I misunderstand? What might be the problem?

Thank you for your assistance..

Have a nice day.

 

 


#include <stdint.h>
#include "stm32f4xx.h"
#include <stdbool.h>
#include "gpio.h"
#include "utility.h"
#include "armcortexm4.h"
#include "timer.h"


volatile uint32_t firstRise, secondRise;
volatile bool captureDone = false;
void TIM5_IRQHandler(void)
{
    if (TIMER5->TIMx_SR & (1 << 2))  // Check if capture event occurred
    {
        static bool flag = false;

        if (!flag)
        {
            firstRise = TIMER5->TIMx_CCR2;
            flag = true;
        }
        else
        {
            secondRise = TIMER5->TIMx_CCR2;
            captureDone = true;
            flag = false;

        }

        TIMER5->TIMx_SR &= ~(1 << 2);  // Clear interrupt flag
    }
}
int main(void)
{
			   GPIO_Handle_t PWM_TIMER3_CH1_PB4 = {  .PORTNAME = GPIOB,
													.PINCONF.PIN = GPIO_PIN_4,
													.PINCONF.MODE = GPIO_MODE_ALTARNATE,
													.PINCONF.OTYPE = GPIO_OTYPE_PP,
													.PINCONF.OSPEED = GPIO_OSPEED_HIGH,
													.PINCONF.PUPD = GPIO_PUPD_PU,
													.PINCONF.AF = AF2
			   	   	   	   	   	   	   	   	   	   };

			   GPIO_Handle_t CCP_TIMER5_CH2_PA1 = {  .PORTNAME = GPIOA,
													.PINCONF.PIN = GPIO_PIN_1,
													.PINCONF.MODE = GPIO_MODE_ALTARNATE,
													.PINCONF.OTYPE = GPIO_OTYPE_PP,
													.PINCONF.OSPEED = GPIO_OSPEED_HIGH,
													.PINCONF.PUPD = GPIO_PUPD_PD ,
													.PINCONF.AF = AF2
												   };

				gpioInit(&PWM_TIMER3_CH1_PB4);
				gpioInit(&CCP_TIMER5_CH2_PA1);

				timerxConfig(TIMER3, 160 - 1, 100 - 1);   	// (100kHz) 10us counting, 1ms PWM period	1kHz PWM freq
				timer3PwmEnable(DUTY_CYCLE_70);
				timerxPeripheralEnable(TIMER3);




				timerxConfig(TIMER5, 160 - 1, 0xFFFFFFFF);   	 
				timerxPeripheralEnable(TIMER5);
				timer5InterruptEnable();
				TIMER5->TIMx_CCER &= ~(1u << 4); // Disable capture on CH2
				TIMER5->TIMx_CCMR1 |= (0b01 << 8);  // TI2  capture input
				TIMER5->TIMx_CCER &= ~(1u << 5); // Ensure CC2P = 0 (rising edge capture)
				TIMER5->TIMx_CCER  |= (1u << 4);	//enable capture


				while (1)
				{
				    if (captureDone)
				    {
				        uint32_t periodTicks = secondRise - firstRise;
				       float periodMs = periodTicks * 10.0f / 1000.0f; // 10µs per tick (100kHz clock)
				        float frequency = 1.0 / periodMs;

				        captureDone = false; // Reset flag

				        // Debug: Print or check frequency
				    }
				}
}

 

 

4 REPLIES 4
SofLit
ST Employee

Hello,

Why don't use the PWM input to measure the dusty cycle?

Refer to the example from github.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
PS:
1 - This is NOT an online support (https://ols.st.com) but a collaborative space.
2 - Please be polite in your reply. Otherwise, it will be reported as inappropriate and you will be permanently blacklisted from my help.

You did not show us the timers setup (probably in timerxConfig()), but my guess is, that you don't take into cosideration the fact that prescaler is preloaded. That means, that within the first period of TIM5 (up to 0xFFFF'FFFF) it countes at its raw input clock, 16MHz.

JW

PS. Don't use RMW to clear the TIMx_SR flag, and clear it early in the ISR (as you correctly qualify the interrupt source, it's not a problem here, just that there may be one extra unnecessary ISR invocation there).

Khansokhua
Associate III

@waclawek.jan Spot  on!! Thank you very much. You are my hero.

void timerxConfig(Timer_RegDef_t* selectTimer,uint16_t prescaler, uint32_t autoReload )
{
	timerxClockEnable(selectTimer);
	selectTimer->TIMx_PSC = prescaler - 1;
	selectTimer->TIMx_ARR = autoReload - 1;
	 //selectTimer->TIMx_EGR |= (1 << 0); 
}

After including  the comment line, new values are 97 and 196. Also, I reconfigured the code  according to the your suggestion

 TIMER5->TIMx_SR = ~(1 << 2);  // Clear interrupt flag

As soon as program get into the if statement , interrupt flag is cleared as in the above.

How can I do the difference exact 100?

Thanks in advance.

In your code, timers are likely not enabled before configuration. If so, nothing is configured and both timers use the default prescaler of 1 and maximum period.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice