1
votes

I am trying to run a simple blink program on a STM32 board based on STM32F413RG. The led lights up and only toggles when stepping through, not when continuing without breakpoint or running freely on Release mode.

I have setup the eclipse(4.11) to debug the program using a J-link hardware debugger. The code uploads and the LED programmed lights up, but I can see it toggle only when manually stepping through. It does not run without breakpoints.

Sharing my code below where I have setup the clock to be sourced from PLL running on 32 MHz and trying to blink the LED connected to Port B pin 1 every 0.5 second.

One more interesting thing is, Even if I am able to set a breakpoint to see inside the delay() method, the debugger never stops at it / seems to jump across that line of code when single-stepping. Why does it so?

void setupClocks()
{
    // we want to use the 24000000 HSE clock (xtal) as the base
     RCC->CR |= RCC_CR_HSEON;
    // so wait for it to be ready
    while ((RCC->CR & RCC_CR_HSERDY) == 0) {}
    enter code here


    // now configure the PLL (HSE / 12 * 96 /6) gives 32 MHz
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
    RCC->PLLCFGR |= (12)<< RCC_PLLCFGR_PLLM_Pos;
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_Msk;
    RCC->PLLCFGR |= (96)<< RCC_PLLCFGR_PLLN_Pos; // 32 MHz

    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_Msk;

    RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_1; // 6

    RCC->CR |= RCC_CR_PLLON;

 // wait for PLL to be ready
    while ((RCC->CR & RCC_CR_PLLRDY) == 0) {}

    // now setup the AHB1
    // 1/2 of system clock (48 MHz)
    RCC->CFGR |= RCC_CFGR_PPRE1_2;

    // select PLL (clocked from HSE)
    RCC->CFGR |= RCC_CFGR_SW_1;

    //reset the ones we use
    RCC->AHB1RSTR = RCC_AHB1RSTR_GPIOARST;
    RCC->AHB1RSTR = RCC_AHB1RSTR_GPIOBRST;
    RCC->AHB1RSTR = RCC_AHB1RSTR_GPIOCRST;
    RCC->AHB1RSTR = RCC_AHB1RSTR_GPIODRST;
    RCC->AHB1RSTR = 0;

    SystemCoreClockUpdate();
}

void initLED()
{
    // enable port B clock
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;

    // set as output for Port B pin 1
    GPIOB->MODER |= GPIO_MODER_MODER1_0;

   // start with MP10 LED on

   GPIOB->ODR = GPIO_ODR_ODR_1;
}

void delay(uint32_t microsec)
{
    // wait a bit
    uint32_t counter =  (microsec * (SystemCoreClock / 1000000U));
    while(counter != 0U)
    {
      counter--;
    }
}
void blinkCount(int count)
{
    for (int i = 0; i < count; ++i)
    {
        GPIOB->ODR = ~GPIO_ODR_ODR_1 ;
        delay(500000);
        GPIOB->ODR = GPIO_ODR_ODR_1;
        delay(500000);
    }
    delay(1000000);
}

int main()
{
     setupClocks();
     initLED();

     while(1)
     {
         blinkCount(1);
         delay(1000000);
     }

    return 0;
}

Expecting to blink the led as per desired frequency when the program is run without breakpoints or release mode, but the led activity is only visible when stepping through during debug mode.

2
Your delay is doing nothing meaningful from compiler's point of view and likely getting optimized.Eugene Sh.
Thanks. do you think I should add some optimization flag when building it? or what would be the right approach.Shankar S
The right approach is to use hardware timers.Eugene Sh.
Anyway in function delay() I suggest changing everything to uint64_t, and perform the multiplication before the division. A software loop is a crude solution.Weather Vane

2 Answers

1
votes
  1. Be consistent. If you set the clock using directly registers, do not call HAL cube generated functions like SystemCoreClockUpdate(); it is very likely the SystemCoreClock will not have the value you think it has

  2. When doing blocking delays I advice using volatile variables as they will not be removed by the compiler. There is no need of using the 64 bits variables unless you want many minutes delays. Try to do not block. use SysTick (or any other timer) interrupt to implement delays.

example

void delay(volatile uint32_t delay)
{
    while(delay--);
}

or for more precise control inline assembly:

void delay1(uint32_t delay)
{
    while(delay--)
    {
        asm volatile("" : : "r"(delay) : "memory");
    }
}

which leads to the code:

delay:
  sub sp, sp, #8
  str r0, [sp, #4]
.L2:
  ldr r3, [sp, #4]
  sub r2, r3, #1
  cmp r3, #0
  str r2, [sp, #4]
  bne .L2
  add sp, sp, #8
  bx lr
delay1:
.L6:
  subs r0, r0, #1
  bxcc lr
  b .L6
0
votes

You need a small delay after enabling the GPIO clock. Put a __DSB() call between enabling the clock and accessing the GPIO registers.

See the product errata document for details.