cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4, Weird behavior with TIM6 to blink an LED

upgrdman
Associate II
Posted on June 25, 2012 at 06:08

I'm trying to learn how to use the basic timers, without the benefit of a library, so I have been reading the RM0090 reference manual. As a simple test I want to toggle the blue LED on the dev board (pin D15) once per second.

I wrote the code below, but the LED does not come on. The weird thing is when I run a debugger and setup a brakepoint to print out some information, it actually works. If I remove the brake point it stops working. Any ideas?

Code:

============================================

#include ''stm32f4xx.h''

#include ''core_cm4.h''

unsigned long i = 0;

int main() {

    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

    TIM6->DIER |= TIM_DIER_UIE;   // Enable interrupt on update event

    TIM6->PSC = 41999;   // Set prescaler to 41999

    TIM6->ARR = 999;   // Set auto-reload to 999

    TIM6->CR1 |= TIM_CR1_CEN;   // Enable TIM6 counter

    

    while(1) {

        // do nothing

    }

}

void TIM6_DAC_IRQHandler() {

    i++;

    GPIOD->ODR ^= (1 << 15);   // Toggle D15

    TIM6->SR = 0;   // Interrupt has been handled

}

============================================

Debugger setup:

============================================

$ arm-none-eabi-gdb -silent -ex 'target extended-remote localhost:4242' firmware.elf

Reading symbols from /stm32f4/projects/LED Blinking with TIM6/firmware.elf...done.

Remote debugging using localhost:4242

Reset_Handler () at startup_stm32f4xx.s:69

69      movs  r1, #0

(gdb) break TIM6_DAC_IRQHandler

Breakpoint 1 at 0x8000188: file main.c, line 23.

(gdb) commands

Type commands for breakpoint(s) 1, one per line.

End with a line saying just ''end''.

>print i

>print *(unsigned long*) 0x40020c14

>continue

>end

(gdb) run

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /stm32f4/projects/LED Blinking with TIM6/firmware.elf

Note: automatically using hardware breakpoints for read-only addresses.

TIM6_DAC_IRQHandler () at main.c:23

23        i++;

(gdb) c

Continuing.

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$1 = 1

$2 = 32768

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$3 = 2

$4 = 0

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$5 = 3

$6 = 32768

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$7 = 4

$8 = 0

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$9 = 5

$10 = 32768

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$11 = 6

$12 = 0

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$13 = 7

$14 = 32768

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$15 = 8

$16 = 0

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$17 = 9

$18 = 32768

Breakpoint 1, TIM6_DAC_IRQHandler () at main.c:23

23        i++;

$19 = 10

$20 = 0

^CBreakpoint 1, Quit

(gdb)

============================================

-Farrell
2 REPLIES 2
Posted on June 25, 2012 at 07:21

One potential problem here is that you presuppose the register content, and set arbitrary bits without masking. Another perhaps is the state of the alternate function mux.

Debuggers are invasive, they create an environment that suits them, and it won't look exactly like a normally configured/running chip.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
upgrdman
Associate II
Posted on June 27, 2012 at 06:12

I fixed part of the problem. If I check that TIM6->SR != 0 in my ISR the timer works.

Working ISR:

===========================================

void TIM6_DAC_IRQHandler() {

    if(TIM6->SR)

        GPIOD->ODR ^= (1 << 15);   // Toggle D15

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

}

===========================================

But it seems odd that I would need to. The ISR should only be called when the count overflows or reaches the auto-reload value, right? I wonder if my ISR is getting called when the counter is incremented, not just on an ''update event.''

-Farrell