2025-02-10 07:31 AM - last edited on 2025-02-10 07:36 AM by SofLit
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
}
}
}
2025-02-10 07:39 AM
Hello,
Why don't use the PWM input to measure the dusty cycle?
Refer to the example from github.
2025-02-10 09:52 AM
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).
2025-02-10 11:42 AM
@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.
2025-02-10 11:53 AM
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.