cancel
Showing results for 
Search instead for 
Did you mean: 

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

Thiago Cavalcanti
Associate II

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

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

0693W00000YAKYYQA5.png 

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

0693W00000YAKYnQAP.png 

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.

1 ACCEPTED SOLUTION

Accepted Solutions

> SysTick_init(47);

This floods the mcu with systick interrupts. The execution of systick ISR when using -O0 takes more than 48 system ticks.

Leave the systick to run up to its maximum, and base the loopdelay on reading its value.

Additionally, you have to qualify usDelay as volatile.

JW

View solution in original post

5 REPLIES 5
Thiago Cavalcanti
Associate II

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);
	}			
}

> SysTick_init(47);

This floods the mcu with systick interrupts. The execution of systick ISR when using -O0 takes more than 48 system ticks.

Leave the systick to run up to its maximum, and base the loopdelay on reading its value.

Additionally, you have to qualify usDelay as volatile.

JW

Absolutely correct. I just replaced the highlighted line with:

SysTick_init(479);

And all went well.

That explains why the code worked with the STM32F429ZI: that chip can run with a frequency of up to 180 MHz. It is not possible to enter and leave the ISR at the same speed in the SMT32F031. Of course!

Thank you and thanks for the additional tip about the volatile keyword.

Best.

Thiago.

One more thing: don't use GPIO_ODR, use GPIO_BSRR. The performance is the same, but using GPIO_BSRR is safe in interrupt context (atomic).

JW

Interesting. Thanks for that info too. I always used the ODR and didn't know about the atomic feature of the BSRR.