This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Code runs in line-by-line debugging but not otherwise. Some functions only run if defined as macros

I am writing code for the STM32F031K6T6 MCU using the Keil uVision. The IDE information is shown in the image below: 

Keil info

The C/C++ options for Target are configured as shown here:

C/C++

I started a new project, selected the chip, and configured the run-time environment as below:

Initial config

I initialized the clock and configured the Flash registers for the appropriate latency. I tested the frequency using MCO and it seems correct. I also initialized some GPIOs, UART, and the SysTick. The peripheral registered is modified as expected as seen on the System View for the respective peripheral in the debugging mode.

The problem is that some functions, such as functions for sending and receiving data via UART and some functions that use GPIO ports only work in debugging mode when I run the code line-by-line. If I click the run button the code gets stuck and the chip stops responding. I still see the VAL and CURRENT registers of the SysTick updating.

This is an example of a function that works:

void System_Clock_init(void){
            
    FLASH->ACR &= ~FLASH_ACR_LATENCY;
    FLASH->ACR |= FLASH_ACR_LATENCY | 0x01; 
    
    RCC->CR |= RCC_CR_HSION;
    while((RCC->CR & RCC_CR_HSIRDY) == 0);
    
    
    RCC->CR &= ~RCC_CR_HSITRIM;
    RCC->CR |= 16UL << 3;
        
    RCC->CR &= ~RCC_CR_PLLON;
    while((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY);
    
    RCC->CFGR &= ~RCC_CFGR_PLLSRC;
    RCC->CFGR |= 10UL << 18;
    RCC->CFGR &= ~RCC_CFGR_HPRE;
    RCC->CFGR &= ~RCC_CFGR_PPRE;
    
    RCC->CR |= RCC_CR_PLLON;
    while((RCC->CR & RCC_CR_PLLRDY) == 0);
    
    RCC->CFGR &= ~RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);      
}

This is an example of a function that doesn’t work:

void UV_LED_Driver(uint32_t d){
    for(uint32_t i = 0; i<16; i++){ 
        if(d&(((uint32_t)0x8000)>>i)){
            SDI2_ON;
        }
        else {
            SDI2_OFF;
        }
         CLK2
    }
    LATCH2      
}

The macros used in the function above are defined as below:

// CLK2 -> PA5
// LE2 -> PA4
// SDI2 -> PA6
#define CLK2_OFF   GPIOA->ODR |= (1UL << 5)
#define CLK2_ON    GPIOA->ODR &= ~(1UL << 5)

#define LE2_OFF    GPIOA->ODR |= (1UL << 4)
#define LE2_ON     GPIOA->ODR &= ~(1UL << 4)

#define SDI2_ON    GPIOA->ODR &= ~(1UL << 6)
#define SDI2_OFF   GPIOA->ODR |= (1UL << 6)

#define CLK2       {CLK2_ON; us_Delay(1); CLK2_OFF;}
#define LATCH2     {LE2_ON; us_Delay(1); LE2_OFF;}

The GPIO pins used in the function above are initialized as follows:

// CLK2 -> PA5
// LE2 -> PA4
// SDI2 -> PA6
void UV_LED_Driver_Init(void){
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    
    GPIOA->MODER &= ~((3UL << 8) | (3UL << 10) | (3UL << 12));
    GPIOA->MODER |=  ((1UL << 8) | (1UL << 10) | (1UL << 12));  
    GPIOA->OTYPER &= ~(0x70UL);
    GPIOA->PUPDR &= ~((1UL << 8) | (1UL << 10) | (1UL << 12));      
    GPIOA->OSPEEDR &= ~((3UL << 8) | (3UL << 10) | (3UL << 12));
    GPIOA->OSPEEDR |= ((1UL << 8) | (1UL << 10) | (1UL << 12)); 
    GPIOA->ODR |= (0x70UL);
}

And the us_Delay() function is based on SysTick. These are defined as:

static uint32_t usDelay = 0;

void SysTick_init(uint32_t ticks){
    SysTick->CTRL = 0;
    SysTick->LOAD = ticks - 1;
    NVIC_SetPriority(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
    SysTick->VAL = 0;
    SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;   
}

void SysTick_Handler(void){
    if(usDelay > 0){
        usDelay--;
    }
}

void us_Delay(uint32_t us){
    usDelay = us;
    while(usDelay != 0);
}

Now, this is the same UV_LED_Driver(uint32_t d) function defined as a macro (Runs as expected):

#define UV_LED_DRIVER(d) {for(int i = 0; i<16; i++){if(d&(0x000F>>i)){SDI2_ON;}else {SDI2_OFF;}CLK2}LATCH2}

This is the main():

 #include <stm32f031x6.h>
 #include "clock.h"
 #include "LED_Driver.h"
 #include "UART.h"
 
 int main(void){
    
    System_Clock_init();    
    Color_LED_Driver_Init();
    UV_LED_Driver_Init();
    Nucleo_Green_LED_Init();
    UART_init();
    SysTick_init(47);
    //MCO_Init(); // Check PIN 18 (PA8) for the frequency of the MCO using an Oscilloscope  
    while(1){       
 
        UV_LED_DRIVER(~(0x0000)) // This runs well
        //UV_LED_Driver((uint32_t)~(0x0000)); // If I run this line 
        //the debugger gets stuck here. It works if I run line-by-line
        ms_Delay(100);      
        
        UV_LED_DRIVER(~(0xFFFF)) // This runs well 
        //UV_LED_Driver((uint32_t)~(0xFFFF)); // If I run this line 
        //the debugger gets stuck here. It works if I run line-by-line
        ms_Delay(100);
    }           
}

Interestingly, if I define the functions as macros, they behave as desired. I finally tested the code on a STM32F429ZIT chip and it worked well, given the needed modifications in the initialization of the main clock and the GPIO. Has anyone ever experienced anything similar or happens to know what could be causing this issue? I know that I could walk around this issue using CubeMX but I would like to find out what is causing this problem.

Thank you.