cancel
Showing results for 
Search instead for 
Did you mean: 

faliing to migrate trivial example from TIM6 to TIM5

arro239
Senior
Posted on April 15, 2014 at 15:23

I have a snippet which works, it blinks blue LED on stm32f4discovery:

void TIM6_DAC_IRQHandler() {
if (TIM6->SR)
GPIOD->ODR ^= (1 << 
15
); // Toggle D15
TIM6->SR &= ~1; // Interrupt has been handled
}
int main(void) {
TIM_TypeDef *TIM = TIM6;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER15_0; // Enable output mode for D15
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Enable TIM6 clock
NVIC_EnableIRQ(TIM6_DAC_IRQn); // Enable TIM6 IRQ
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->PSC = 41999; // Set prescaler to 41999
TIM->ARR = 999; // Set auto-reload to 999
TIM->CR1 |= TIM_CR1_CEN; // Enable TIM counter
while (1) {
// do nothing
}
}

I am trying to move this logic to TIM5 - I want to use 32 bit counter. Well, it's embarrassing - this snipped does not work. What am I missing?

void TIM5_IRQHandler() {
if (TIM5->SR)
GPIOD->ODR ^= (1 << 
15
); // Toggle D15
TIM5->SR &= ~1; // Interrupt has been handled
}
int main(void) {
TIM_TypeDef *TIM = TIM5;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER15_0; // Enable output mode for D15
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM5 clock
NVIC_EnableIRQ(TIM5_IRQn); // Enable TIM5 IRQ
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->PSC = 41999; // Set prescaler to 41999
TIM->ARR = 999; // Set auto-reload to 999
TIM->CR1 |= TIM_CR1_CEN; // Enable TIM counter
while (1) {
// do nothing
}
}

8 REPLIES 8
chen
Associate II
Posted on April 15, 2014 at 15:35

Hi

A quick check of the data sheet for STM32F4 shows that gpio D15 is not accessible for Tim5

To use Tim5 - you will have to move IO pin

arro239
Senior
Posted on April 15, 2014 at 16:01

Wait a second, what do you mean not accessible? I am not using D15 as one of timer channels - I am controlling it manually from the callback. I was under an impression that I can do whatever I want to do and there is no connection between the TIM and GPIO in this snipped.

Do I miss something?
chen
Associate II
Posted on April 15, 2014 at 17:14

Hi

''Do I miss something?''

No, I did. I did not check your code.

Not sure what you are missing. Will have o look at the reference manual.

Posted on April 15, 2014 at 17:54

TIM6->SR &= ~1; // Interrupt has been handled

This is NOT how to clear a timer interrupt, just write the mask! Also be aware there is a race condition on the NVIC. I would clear it before toggling the LED
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
arro239
Senior
Posted on April 15, 2014 at 20:24

void TIM5_IRQHandler() {
if (TIM->SR) {
TIM->SR = ~1; // Interrupt has been handled
schedulerCallback();
}
}

Would this be a proper way to clear the flag? If not, what would be the best way to do that? With this change, the code now works on TIM5 - thank you clive1!
frankmeyer9
Associate II
Posted on April 15, 2014 at 20:36

Would this be a proper way to clear the flag?

When in doubt, just copy the method of the peripheral library (stm32f4xx_tim.c):

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
/* Clear the IT pending Bit */
TIMx->SR = (uint16_t)~TIM_IT;
}

arro239
Senior
Posted on April 15, 2014 at 20:39

Episode #2, now I am trying one pulse mode and variable ARR

This code works with TIM6 - the LED blinks three times:

int globalCounter = 0;
static TIM_TypeDef *TIM = TIM6;
static void setTimer(int arr) {
TIM->ARR = arr;
TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value
TIM->CR1 |= TIM_CR1_CEN; // restart timer
}
void TIM6_DAC_IRQHandler() {
if (TIM->SR) {
GPIOD->ODR ^= (1 << 
14
); // Toggle D14
globalCounter++;
if (globalCounter < 6) {
setTimer(499 * globalCounter);
}
TIM->SR = ~1; // Interrupt has been handled
}
}
int main(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER14_0; // Enable output mode for D14
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Enable TIM6 clock
NVIC_EnableIRQ(TIM6_DAC_IRQn); // Enable TIM6 IRQ
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop
TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */
TIM->PSC = 41999; // Set prescaler to 41999
setTimer(999);
// TIM->ARR = darr; // Set auto-reload to 999
// TIM->CR1 |= TIM_CR1_CEN; // Enable TIM counter
while (1) {
// do nothing
}
}

but it would not work if I move the flag reset:

void TIM6_DAC_IRQHandler() {
if (TIM->SR) {
TIM->SR = ~1; // Interrupt has been handled
GPIOD->ODR ^= (1 << 14); // Toggle D14
globalCounter++;
if (globalCounter < 6) {
setTimer(499 * globalCounter);
}
}
}

and probably because of that this would not work on TIM5. Please advise.
arro239
Senior
Posted on April 15, 2014 at 20:49

I guess the condition check was also wrong, here is the code which seems to be doing what I wanted:

int globalCounter = 0;
static TIM_TypeDef *TIM = TIM5;
static void setTimer(int arr) {
TIM->ARR = arr;
TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value
TIM->CR1 |= TIM_CR1_CEN; // restart timer
}
static void callback(void) {
GPIOD->ODR ^= (1 << 
15
); // Toggle D15
globalCounter++;
if (globalCounter < 6) {
setTimer(499 * globalCounter);
}
}
void TIM5_IRQHandler() {
if ((TIM->SR & 0x0001 != 0) && (TIM->DIER & 0x0001 != 0)) {
callback();
}
TIM->SR = ~TIM_IT_Update; // Interrupt has been handled
}
int main(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER15_0; // Enable output mode for D15
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM6 clock
NVIC_EnableIRQ(TIM5_IRQn); // Enable TIM6 IRQ
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop
TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */
TIM->PSC = 41999; // Set prescaler to 41999
setTimer(999);
while (1) {
}
}