2020-04-28 08:46 AM
Hi
I am trying to better understand the registers and register manipulation to set up the following scenario:
Toggle LED on PD12 every 1 second via TIM6 and Interrupt Handler.
Below is my code. I enter the interrupt service routine (verified by setting a breakpoint in the ISR) and I toggle the LED (via step by step debugging within the ISR) . However, when I remove the breakpoint and run the code, the LED toggles at a much higher frequency. Could you please double check my code because I believe I have something wrong in my TIM6 setup. Thank you,
#include "stm32f4xx.h"
void funcIntInit();
void funcTimerInit();
void funcGPIOInit();
int main(void)
{
funcIntInit();
funcTimerInit();
funcGPIOInit();
for(;;);
}
void funcIntInit()
{
// Initialize the interrupt
__NVIC_EnableIRQ(TIM6_DAC_IRQn);
EXTI->IMR |= (1<<0);
EXTI->EMR |= (1<<0);
EXTI->FTSR &= ~(1<<0);
EXTI->RTSR |= (1<<0);
// SysCfg not needed for basic timer TIM6???
}
void funcTimerInit()
{
// Peripheral clock
RCC->APB1ENR |= (1<<4); // Enables APB1 bus to use Timer 6
// 2. Init timer
TIM6->CR1 |= (1<<0); // CEN: Enables counter
TIM6->CR1 &= ~(1<<1); // UDIS: Update event enabled
TIM6->CR1 |= (1<<2); // URS: Update request source enabled for overflow/underflow only
TIM6->CR1 &= ~(1<<3); // OPM: One Pulse Mode. Counter continues counting.
TIM6->CR1 &= ~(1<<7); // Auto reload preload enabled
TIM6->DIER |= (1<<0); // UIE: Update interrupt enabled
TIM6->EGR |= (1<<0); // UG: Update generation. Re-initializes the counter and updates registers
//TIM6->CNT = 0x00FA; // Counter goes up to 250 to have 1s timer ???
TIM6->PSC = 0xFA00; // Sets prescaler to 64000. Timer clock is now 16MHz/64000=250Hz
TIM6->ARR = 0x00FA; // Counter goes up to 250 to have 1s timer
}
void funcGPIOInit()
{
// Peripheral clock
RCC->AHB1ENR |= (1<<3); // Enables AHB1 to use GPIOD peripheral
// 2. Init GPIO
GPIOD->MODER |= (1<<24); // Sets GPIOD as Output
GPIOD->MODER &= ~(1<<25); // Sets GPIOD as Output (redundand because bit 25 is already 0 after reset)
GPIOD->OTYPER &= ~(1<<12); // Set PD12 as Push Pull
GPIOD->OSPEEDR &= ~(1<<24); // Sets speed on PD12 to low
GPIOD->OSPEEDR &= ~(1<<25); // Sets speed on PD12 to low
}
void TIM6_DAC_IRQHandler() // Overrides the weak implementation of the IRQ in the startup file
{
// Toggle LED
static uint8_t check = 1;
if(check)
{
GPIOD->ODR |= (1<<12); // Sets PD12
check = 0;
}
else
{
GPIOD->ODR &= ~(1<<12); // Clears PD12
check = 1;
}
__NVIC_ClearPendingIRQ(TIM6_DAC_IRQn);
}
Solved! Go to Solution.
2020-04-28 09:27 AM
You need to clear the timer's update flag, otherwise the interrupt will keep firing. Here's the relevant portion from the default HAL IRQHandler:
/* TIM Update event */
if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->PeriodElapsedCallback(htim);
#else
HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
So do:
TIMx->SR = ~TIM_SR_UIF;
2020-04-28 09:27 AM
You need to clear the timer's update flag, otherwise the interrupt will keep firing. Here's the relevant portion from the default HAL IRQHandler:
/* TIM Update event */
if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->PeriodElapsedCallback(htim);
#else
HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
So do:
TIMx->SR = ~TIM_SR_UIF;
2020-04-28 10:16 AM
Boom! Thank you - that was exactly what I missed.
Thank you very much for your help - much appreciated.
BR,
2020-04-28 10:33 AM
BTW, why are you playing with EXTI0 in the funcIntInit?
PSC and ARR should both be 1 less than the count (period).
2020-04-28 10:51 AM
Hi turboscrew,
because I thought it was a smart idea to play with the EXTI0, although not entirely knowing what I was doing. I went through the ref manual one more time and agree that EXTI0 is not needed for my basic timer, but only for GPIO.
And thank you very much for the hint about PSC and ARR. The code is updated with the correct values.
I have one more question:
What exactly is the register TIMx_CNT used for? The reference manual says Counter value, which I understand as the current counter value that increases with every clock cycle (after prescaler etc). If I am correct with that, then what is the reason that the register is both read and WRITE?
Thank you,
2020-04-28 11:06 AM
> What exactly is the register TIMx_CNT used for? The reference manual says Counter value, which I understand as the current counter value that increases with every clock cycle (after prescaler etc). If I am correct with that, then what is the reason that the register is both read and WRITE?
Your understanding is correct. It's read/write because sometimes you want to change the value, simple as that. Your program doesn't need to, but sometimes it makes sense to start the counter from ARR-1, or from 0, or from the middle. Or if you want to reset the counter to avoid an update event, or whatever.