I am writing code for the STM32F031K6T6 MCU using the Keil uVision. The IDE information is shown in the image below:
The C/C++ options for Target are configured as shown here:
I started a new project, selected the chip, and configured the run-time environment as below:
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.
I asked the same question at the ST Community forum and the user waclawek.jan answered it. The problem is that I was calling the SysTick interrupt too often, not leaving any time for the main() to run. To fix the code, I just called the SysTick_init() function passing "479" as an argument instead of "47".
Thank you!
Thank you for coming back and sharing the solution you found :)