cancel
Showing results for 
Search instead for 
Did you mean: 

Firmware behaves differently after programming with RESET from the ST-Link, and with RESET from the board push button.

GBron.1
Associate

Summary of the problem:

Basically, the firmware seems to "skip" some lines of code when I run directly after programming, while if I perform a hard reset through the board button I get the firmware behaving as expected.

My setup:

My test board is the STM32F746G-DISCO. I am using Keil 5 for some simple app tests. I am not using the STM32CubeMX, instead I am generating just startup code from Keil GUI and programming the registers directly instead of using HAL Libs.

Board

  • STM32F746G-DISCO (Cortex M7)

IDE

  • Keil v5 (Windows 10 x64)

The problem:

A few days ago I ran into a problem that let me baffled, but as I am starting with the STM32 mcu I chose to ignore the issue and I thought I was missing something. But then yesterday it happened again in a very different scenario, which took me more than a whole day to figure out.

I experienced the same problem in two very different scenarios:

Problem #1:

Using Keil, and C++ project, I created an infinite loop in main, that I use to toggle two LEDs. I implemented some very crude delay using a long for(); so I could see two LEDs blink.

I also would write the LED state to the serial port using the ST-Link VCP.

After programming the board, Keil IDE will RESET the board through the ST-Link.

Then I notice that only 1 of the two LEDs would blink, and only the state of that one would be reported to the Serial port. However all initialization was correct and the function calls were correct. For my surprise, after presseing the RESET button in the board, the program would restart but this time everything would work fine.

Code for Problem #1:

main.cpp

#include "led.h"
 
int main(void){
 
	for (uint32_t i=0;i<4000000;i++);
 
	Led led1(RED, LED_ON);
	Led led2(GREEN, LED_ON);
	
	while(1){
	
		led1.SetState(LED_ON);
		led2.SetState(LED_ON);
		
		for (uint32_t i=0;i<1000000;i++);
	
		led1.SetState(LED_OFF);
		led2.SetState(LED_OFF);
		
		for (uint32_t i=0;i<1000000;i++);
		
	}
 
}

led.h

#ifndef LED_H
#define LED_H
 
#define LED_GREEN_PORT GPIOI
#define LED_GREEN_PIN (1U<<1)			// BIT MASK
#define LED_RED_PORT GPIOA
#define LED_RED_PIN (1U<<15)			// BIT MASK
 
#include "stm32f7xx.h"                  // Device header
 
typedef enum {
	GREEN = 0,
	RED = 1	
} LedColor_Type;
 
typedef enum {
	LED_OFF=0,
	LED_ON=1
} LedState_Type;
 
class Led{
 
	private:
		LedColor_Type color;
		LedState_Type state;
	public:
		Led(LedColor_Type color, LedState_Type state);
		void SetState(LedState_Type state);
		LedState_Type GetState();
};
 
#endif

led.cpp

#include "led.h"
 
Led::Led(LedColor_Type color, LedState_Type state) : color(color), state(state)
{
	// enable GPIO port clock
	RCC->AHB1ENR |= (1U << 8);		// GPIO I
	RCC->AHB1ENR |= (1U << 0);		// GPIO A
	
	switch(color)
	{
		case GREEN:
			LED_GREEN_PORT->MODER &=~ (1U << 3);		// bit 3 = 0
			LED_GREEN_PORT->MODER |=  (1U << 2);		// bit 2 = 1
		
			if (this->state == LED_ON){
				LED_GREEN_PORT->ODR |= LED_GREEN_PIN;
			}else{
				LED_GREEN_PORT->ODR &=~ LED_GREEN_PIN;
			}
			break;
		case RED:
			LED_RED_PORT->MODER &=~ (1U << 31);			// bit 31 = 0
			LED_RED_PORT->MODER |=  (1U << 30);			// bit 30 = 1
			if (this->state == LED_ON){
				LED_RED_PORT->ODR |= LED_RED_PIN;
			}else{
				LED_RED_PORT->ODR &=~ LED_RED_PIN;
			}
			break;
	}
}
 
void Led::SetState(LedState_Type state)
{
	this->state = state;
	
	switch(this->color)
	{
		case GREEN:	
			if (this->state == LED_ON){
				LED_GREEN_PORT->ODR |= LED_GREEN_PIN;
			}else{
				LED_GREEN_PORT->ODR &=~ LED_GREEN_PIN;
			}
			//printf("The GREEN Led is set to: %d\n\r", this->state);
			break;
		case RED:
			if (this->state == LED_ON){
				LED_RED_PORT->ODR |= LED_RED_PIN;
			}else{
				LED_RED_PORT->ODR &=~ LED_RED_PIN;
			}
			//printf("The RED Led is set to: %d\n\r", this->state);	
			break;
	}
	
}
 
LedState_Type Led::GetState()
{
	return this->state;
}

Problem #2:

I am starting a course on FreeRTOS. I setup a Keil with only startup code generation and manually added the latest FreeRTOS sources to the project. I created two Tasks with same priority to blink the two LEDs again. After compiling and downloading the software to the board, guess what, only 1 task would run. After many and many hours of testing and code changes, for my surprise If I reset the device through the RESET push button on-board I got both tasks running correctly.

Code for Problem #2:

main.c

#include "stm32f7xx.h"                  // Device header
#include "board.h"
 
// FreeRTOS includes
#include "FreeRTOS.h"
#include "task.h"
 
// task functions prototypes
void taskHandler_Task1(void * param);
void taskHandler_Task2(void * param);
 
int main(void)
{
	// essential board initializations
	SystemInit();  // generated by Keil, I can remove and the result will be the same
	
	// initialize and setup peripherals for board specific circuit
	BoardInit();   // this line only initializes GPIO ports and the AHB 1 BUS
	
	// Create one of the two tasks.
	xTaskCreate(	taskHandler_Task1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
 
	// Create the other task in exactly the same way.
	xTaskCreate( taskHandler_Task2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 1, NULL );
	
	// Start the scheduler so our tasks start executing.
	vTaskStartScheduler();
	
	// If all is well we will never reach here as the scheduler will now be running
	for( ;; );
}
 
void taskHandler_Task1(void * param)
{
	while(1){
		volatile uint32_t cnt;
		for (cnt=0; cnt<2000000; cnt++);
		LED_Toggle();		
	}	
}
 
void taskHandler_Task2(void * param)
{
	while(1){
		volatile uint32_t cnt;
		for (cnt=0; cnt<1000000; cnt++);
		LED2_Toggle();
	}
}

I hope someone can give me some hint about this behavior.

Thanks.

1 REPLY 1
Piranha
Chief II

For delays use vTaskDelay(), not busy-loops. For atomic pin setting use BSRR/BRR registers, not ODR.

https://community.st.com/s/question/0D50X0000B0xtmuSQA/halgpiotogglepin-bugs