2025-01-06 09:32 AM
I am a beginner. Please help me figure out why the interrupt is not happening. I want to measure the duty cycle, but the interrupt is not enabled. I am losing hope that this is possible.
#include <stdint.h>
#include <stm32f0xx.h>
#include <stdbool.h>
#include "uart.h"
int cnt = 0;
#define ledPin GPIO_ODR_4
#define baudRate 115200
char receivedString[100];
volatile uint32_t capture_value = 0;
volatile uint32_t frequency = 0;
volatile uint32_t duty_cycle = 0;
volatile bool state = false;
void SystemInit(void);
void TIM14_Config(void);
void TIM14_IRQHandler(void);
void init_PA4_LED(void);
void TIM3_Init(void);
void init_PA6_PWM_In(void);
void TIM3_IRQHandler(void);
int main(void) {
SystemInit();
UART_Init(baudRate);
init_PA4_LED();
TIM14_Config();
TIM3_Init();
init_PA6_PWM_In();
while (1) {
if (state) {
UART_SendString("Counter: ");
UART_SendNumber(cnt);
UART_SendString("\n");
state = false;
}
}
}
void SystemInit(void) {
if ((RCC->CR & RCC_CR_HSIRDY) == 0) {
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) == 0) {
}
}
RCC->CFGR &= ~RCC_CFGR_PLLSRC;
RCC->CFGR &= ~RCC_CFGR_PLLMUL;
RCC->CFGR |= RCC_CFGR_PLLMUL12;
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {
}
}
void init_PA4_LED(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER |= GPIO_MODER_MODER4_0;
GPIOA->MODER &= ~GPIO_MODER_MODER4_1;
}
void TIM14_Config(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
TIM14->PSC = 4799;
TIM14->ARR = 999;
TIM14->DIER |= TIM_DIER_UIE;
TIM14->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM14_IRQn);
NVIC_SetPriority(TIM14_IRQn, 0);
}
void TIM14_IRQHandler(void) {
if (TIM14->SR & TIM_SR_UIF) {
TIM14->SR &= ~TIM_SR_UIF;
GPIOA->ODR ^= GPIO_ODR_4;
state = true;
}
}
void TIM3_IRQHandler(void) {
if (TIM3->SR & TIM_SR_CC1IF) {
capture_value = TIM3->CCR1;
cnt++;
if (capture_value != 0) {
frequency = 48000000 / capture_value;
duty_cycle = (TIM3->CCR1 * 100) / TIM3->ARR;
}
TIM3->SR &= ~TIM_SR_CC1IF;
}
}
void init_PA6_PWM_In(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER &= ~(GPIO_MODER_MODER6);
GPIOA->MODER |= (GPIO_MODER_MODER6_1);
GPIOA->AFR[0] &= ~(GPIO_AFRL_AFSEL6);
GPIOA->AFR[0] |= (0x2 << GPIO_AFRL_AFSEL6_Pos);
}
void TIM3_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->CR1 = 0;
TIM3->PSC = 800 - 1;
TIM3->ARR = 60000 - 1;
TIM3->CR1 |= TIM_CR1_DIR;
TIM3->SMCR &= ~TIM_SMCR_SMS;
TIM3->CCMR1 &= ~TIM_CCMR1_CC1S;
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;
TIM3->CCMR1 &= ~TIM_CCMR1_IC1PSC;
TIM3->CCMR1 &= ~TIM_CCMR1_IC1F;
TIM3->CCER &= ~TIM_CCER_CC1P;
TIM3->CCER |= TIM_CCER_CC1E;
TIM3->CR2 &= ~TIM_CR2_MMS;
TIM3->DIER |= TIM_DIER_CC1IE;
TIM3->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM3_IRQn);
NVIC_SetPriority(TIM3_IRQn, 0);
}
Solved! Go to Solution.
2025-01-07 04:36 AM - edited 2025-01-07 04:37 AM
2025-01-07 01:49 AM
Hello @Wsitc.1
You don't need to re-declare the TIM14_IRQHandler and TIM3_IRQHandler.
Please try with the implementation below:
#include <stdint.h>
#include <stm32f0xx.h>
#include <stdbool.h>
#include "uart.h"
int cnt = 0;
#define ledPin GPIO_ODR_4
#define baudRate 115200
char receivedString[100];
volatile uint32_t capture_value = 0;
volatile uint32_t frequency = 0;
volatile uint32_t duty_cycle = 0;
volatile bool state = false;
void SystemInit(void);
void TIM14_Config(void);
void init_PA4_LED(void);
void TIM3_Init(void);
void init_PA6_PWM_In(void);
int main(void) {
SystemInit();
UART_Init(baudRate);
init_PA4_LED();
TIM14_Config();
TIM3_Init();
init_PA6_PWM_In();
while (1) {
if (state) {
UART_SendString("Counter: ");
UART_SendNumber(cnt);
UART_SendString("\n");
state = false;
}
}
}
void SystemInit(void) {
if ((RCC->CR & RCC_CR_HSIRDY) == 0) {
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) == 0) {
}
}
RCC->CFGR &= ~RCC_CFGR_PLLSRC;
RCC->CFGR &= ~RCC_CFGR_PLLMUL;
RCC->CFGR |= RCC_CFGR_PLLMUL12;
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {
}
}
void init_PA4_LED(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER |= GPIO_MODER_MODER4_0;
GPIOA->MODER &= ~GPIO_MODER_MODER4_1;
}
void TIM14_Config(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
TIM14->PSC = 4799;
TIM14->ARR = 999;
TIM14->DIER |= TIM_DIER_UIE;
TIM14->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM14_IRQn);
NVIC_SetPriority(TIM14_IRQn, 0);
}
void TIM14_IRQHandler(void) {
if (TIM14->SR & TIM_SR_UIF) {
TIM14->SR &= ~TIM_SR_UIF;
GPIOA->ODR ^= GPIO_ODR_4;
state = true;
}
}
void TIM3_IRQHandler(void) {
if (TIM3->SR & TIM_SR_CC1IF) {
capture_value = TIM3->CCR1;
cnt++;
if (capture_value != 0) {
frequency = 48000000 / capture_value;
duty_cycle = (TIM3->CCR1 * 100) / TIM3->ARR;
}
TIM3->SR &= ~TIM_SR_CC1IF;
}
}
void init_PA6_PWM_In(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER &= ~(GPIO_MODER_MODER6);
GPIOA->MODER |= (GPIO_MODER_MODER6_1);
GPIOA->AFR[0] &= ~(GPIO_AFRL_AFSEL6);
GPIOA->AFR[0] |= (0x2 << GPIO_AFRL_AFSEL6_Pos);
}
void TIM3_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->CR1 = 0;
TIM3->PSC = 800 - 1;
TIM3->ARR = 60000 - 1;
TIM3->CR1 |= TIM_CR1_DIR;
TIM3->SMCR &= ~TIM_SMCR_SMS;
TIM3->CCMR1 &= ~TIM_CCMR1_CC1S;
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;
TIM3->CCMR1 &= ~TIM_CCMR1_IC1PSC;
TIM3->CCMR1 &= ~TIM_CCMR1_IC1F;
TIM3->CCER &= ~TIM_CCER_CC1P;
TIM3->CCER |= TIM_CCER_CC1E;
TIM3->CR2 &= ~TIM_CR2_MMS;
TIM3->DIER |= TIM_DIER_CC1IE;
TIM3->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM3_IRQn);
NVIC_SetPriority(TIM3_IRQn, 0);
}
2025-01-07 02:33 AM
Thank you for your reply, but the interruption is still not there. I am using cnt to check. I have experimented a lot, but haven't achieved the desired result. Maybe I missed enabling some required register.
2025-01-07 03:01 AM - edited 2025-01-07 03:02 AM
> GPIOA->AFR[0] &= ~(GPIO_AFRL_AFSEL6);
> GPIOA->AFR[0] |= (0x2 << GPIO_AFRL_AFSEL6_Pos);
JW
PS. Don't RMW TIMx_SR. Make sure variables you share with interrupts (here cnt) are qualified as volatile. Be careful with modifying GPIO_ODR in interrupts; better use GPIO_BSRR.
2025-01-07 04:28 AM
Thank you. I still don't understand how to fix the situation.
2025-01-07 04:36 AM - edited 2025-01-07 04:37 AM
GPIOA->AFR[0] |= (0x1 << GPIO_AFRL_AFSEL6_Pos);
JW
2025-01-07 05:04 AM
Thanks. I seem to be getting timer interrupts. The code still doesn't correctly determine the pulse length. Could it be that the falling edge of the signal is not set correctly?
2025-01-07 05:19 AM
> The code still doesn't correctly determine the pulse length.
For period, you'd need to subtract captured values between two captures.
For pulse length you'd need to capture both edges and subtract them. This is best done on two channels set to opposite polarities, with one of the inputting the "neighbouring channel" - see the "PWM input" subchapter of TIM chapter in RM.
The rather big prescaler limits the granularity of measurement. There's no reason not to use the full possible period of the timer (i.e. set ARR to its maximum), and set prescaler to lowerst possible value for to be able to capture the anticipated longest period.
JW
2025-01-07 06:51 AM
Thanks for the advice and help. I've looked at the manual. RM0360 A.8.5 PWM input configuration code example
/* (1) Select the active input TI1 for TIMx_CCR1 (CC1S = 01),
select the active input TI1 for TIMx_CCR2 (CC2S = 10) */
/* (2) Select TI1FP1 as valid trigger input (TS = 101)
configure the slave mode in reset mode (SMS = 100) */
/* (3) Enable capture by setting CC1E and CC2E
select the rising edge on CC1 and CC1N (CC1P = 0 and CC1NP = 0, reset
value),
select the falling edge on CC2 (CC2P = 1). */
/* (4) Enable interrupt on Capture/Compare 1 */
/* (5) Enable counter */
TIMx->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1; /* (1)*/
TIMx->SMCR |= TIM_SMCR_TS_2 | TIM_SMCR_TS_0
| TIM_SMCR_SMS_2; /* (2) */
TIMx->CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P; /* (3) */
TIMx->DIER |= TIM_DIER_CC1IE; /* (4) */
TIMx->CR1 |= TIM_CR1_CEN; /* (5) */
My code has changed and works very well. I will continue to work on improving the code.
#include <stdint.h>
#include <stm32f0xx.h>
#include <stdbool.h>
#include "uart.h"
volatile int cnt = 0;
#define ledPin GPIO_ODR_4
#define baudRate 115200
char receivedString[100];
volatile uint32_t capture_value = 0;
volatile uint32_t frequency = 0;
volatile uint32_t duty_cycle = 0;
volatile uint32_t gap = 0;
volatile uint32_t counter0 = 0, counter1 = 0;
volatile bool state = false;
void SystemInit(void);
void TIM14_Config(void);
void init_PA4_LED(void);
void TIM3_Init(void);
void init_PA6_PWM_In(void);
int main(void) {
SystemInit();
UART_Init(baudRate);
init_PA4_LED();
TIM14_Config();
TIM3_Init();
init_PA6_PWM_In();
while (1) {
if (state) {
UART_SendString("duty: ");
UART_SendNumber(Counter);
UART_SendString("\n");
state = false;
}
}
}
void SystemInit(void) {
if ((RCC->CR & RCC_CR_HSIRDY) == 0) {
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) == 0) {
}
}
RCC->CFGR &= ~RCC_CFGR_PLLSRC;
RCC->CFGR &= ~RCC_CFGR_PLLMUL;
RCC->CFGR |= RCC_CFGR_PLLMUL12;
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {
}
}
void init_PA4_LED(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER |= GPIO_MODER_MODER4_0;
GPIOA->MODER &= ~GPIO_MODER_MODER4_1;
}
void TIM14_Config(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
TIM14->PSC = 4799;
TIM14->ARR = 999;
TIM14->DIER |= TIM_DIER_UIE;
TIM14->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM14_IRQn);
NVIC_SetPriority(TIM14_IRQn, 15);
}
void TIM14_IRQHandler(void) {
if (TIM14->SR & TIM_SR_UIF) {
TIM14->SR &= ~TIM_SR_UIF;
GPIOA->ODR ^= GPIO_ODR_4;
state = true;
}
}
void TIM3_IRQHandler(void) {
if ((TIM3->SR & TIM_SR_CC1IF) != 0) {
if ((TIM3->SR & TIM_SR_CC1OF) != 0) {
gap = 0;
TIM3->SR &= ~(TIM_SR_CC1OF | TIM_SR_CC1IF);
return;
}
if (gap == 0) {
counter0 = TIM3->CCR1;
gap = 1;
} else {
counter1 = TIM3->CCR2;
if (counter1 > counter0) {
duty_cycle = counter1 - counter0;
}else{
counter0 = counter1 = 0;
}
}
}
}
void init_PA6_PWM_In(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER &= ~(GPIO_MODER_MODER6);
GPIOA->MODER |= (GPIO_MODER_MODER6_1);
GPIOA->AFR[0] &= ~(GPIO_AFRL_AFSEL6);
GPIOA->AFR[0] |= (0x1 << GPIO_AFRL_AFSEL6_Pos);
}
void TIM3_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->CR1 = 0;
TIM3->PSC = 47;
TIM3->ARR = 0xffff;
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1;
TIM3->SMCR |= TIM_SMCR_TS_2 | TIM_SMCR_TS_0 | TIM_SMCR_SMS_2;
TIM3->CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P;
TIM3->DIER |= TIM_DIER_CC1IE;
TIM3->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM3_IRQn);
NVIC_SetPriority(TIM3_IRQn, 0);
}