Skip to main content
mfrank9
Associate III
August 9, 2023
Solved

ST-Link starts firmware and aborts it while downloading

Hello,

I am using STM32CubeIDe V1.10.0.

my project is structured as follows:
-CubeMX inits
-HAL_I2C_IsDeviceReady
-HAL_I2C_Mem_Read //Read a large amount from an I2C EEPROM
-while(1)

I have now done a lot of troubleshooting to understand why HAL_I2C_IsDeviceReady very often returns HAL_BUSY.

The problem is that when debugging, the ST-Link restarts the program and then breaks. This interrupts the I2C communication. If SDA is low at this point (because the external EEPROM is pulling the SDA low) the i2c can never be used again. It is always HAL_BUSY.
Only when power is removed will the I2C be re-enabled.

When clicking on "Debug", the ST-Link must not restart the software and interrupt it in an undefined manner.

The J-Link does not have this problem. As a result, the I2C never hangs up here.

This topic has been closed for replies.
mfrank9
mfrank9Best answer
Associate III
August 18, 2023

The following worked for me.
However, there seem to be internal flags that are not reset correctly.
The I2C was still busy but the SDA level was finally high again.
I was only able to fix this with a software reset.

 

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();
/* USER CODE BEGIN 2 */

Toogle_I2C_Clk_Pin(
 &hi2c3,
 MX_I2C3_Init, HAL_I2C_DeInit,
 GPIOA, GPIO_PIN_8,
 0b1010000 <<1);

 

 

static void Toogle_I2C_Clk_Pin(
 I2C_HandleTypeDef *hicPtr,
 void (*MX_I2CX_Init)(void),
 HAL_StatusTypeDef (*HAL_I2C_DeInit)(I2C_HandleTypeDef *hi2c),
 GPIO_TypeDef* clkGPIOx, uint16_t clkGPIO_Pin)
{
 if(clkGPIOx == NULL) return;
 if(MX_I2CX_Init == NULL) return;
 if(HAL_I2C_DeInit == NULL) return;

 HAL_StatusTypeDef state = HAL_I2C_IsDeviceReady(hicPtr, 0b1010000 <<1, 50, 5);

 if(state != HAL_BUSY) return;

 HAL_I2C_DeInit(hicPtr);

 GPIO_InitTypeDef GPIO_InitStruct;

 /* GPIO Ports Clock Enable */
 // __HAL_RCC_GPIOH_CLK_ENABLE();
 // __HAL_RCC_GPIOA_CLK_ENABLE();
 // __HAL_RCC_GPIOC_CLK_ENABLE();
 // __HAL_RCC_GPIOB_CLK_ENABLE();


 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(clkGPIOx, clkGPIO_Pin, GPIO_PIN_SET);


 GPIO_InitStruct.Pin = clkGPIO_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
 GPIO_InitStruct.Pull = GPIO_PULLUP;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(clkGPIOx, &GPIO_InitStruct);

 //9 Flanken ausgeben
 for(uint8_t i =0; i < 9; i++)
 {
 HAL_GPIO_TogglePin(clkGPIOx, clkGPIO_Pin);
 HAL_Delay(1);
 }

 HAL_GPIO_WritePin(clkGPIOx, clkGPIO_Pin, GPIO_PIN_SET);

 MX_I2CX_Init();

 state = HAL_I2C_IsDeviceReady(hicPtr, 0b1010000 <<1, 50, 5);

 NVIC_SystemReset();
}

 

 

 

 

6 replies

TDK
August 9, 2023

At startup, initialize SCL as GPIO output (open drain) and toggle it 9 times in order to reset the slaves on the bus.

 

"If you feel a post has answered your question, please click ""Accept as Solution""."
mfrank9
mfrank9Author
Associate III
August 17, 2023

That would work for sure.
But that would only be a workaround and the actual problem would not be solved.
I'm assuming that this will still be fixed, as this can affect other users and is generally an ugly behavior.

TDK
August 17, 2023

This is how the I2C bus works for slaves, it's not something that can be fixed apart from toggling SCL. Slaves are literally required to behave this way in order to be I2C compliant.

SMBUS implements a timeout which gets around this issue.

> The problem is that when debugging, the ST-Link restarts the program and then breaks.

Okay, I see your complaint now. Yes, it does restart the connection twice which theoretically could be changed. The eclipse framework imposes some challenges with changing how things work. You can add a startup delay as a workaround.

> I'm assuming that this will still be fixed

I would not assume that, personally.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Tesla DeLorean
Guru
August 17, 2023

Consider if the debugger breaks in whilst code is executing, add some significant delay in Reset Handler so control can be gained prior to main code execution.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
August 17, 2023

Watch also if the code could have started a watchdog before the debugger gains control and then starts the MCU code execution over from the beginning.

Low power modes, or pin reconfiguration, can also cause connections to drop.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
mfrank9
mfrank9AuthorBest answer
Associate III
August 18, 2023

The following worked for me.
However, there seem to be internal flags that are not reset correctly.
The I2C was still busy but the SDA level was finally high again.
I was only able to fix this with a software reset.

 

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();
/* USER CODE BEGIN 2 */

Toogle_I2C_Clk_Pin(
 &hi2c3,
 MX_I2C3_Init, HAL_I2C_DeInit,
 GPIOA, GPIO_PIN_8,
 0b1010000 <<1);

 

 

static void Toogle_I2C_Clk_Pin(
 I2C_HandleTypeDef *hicPtr,
 void (*MX_I2CX_Init)(void),
 HAL_StatusTypeDef (*HAL_I2C_DeInit)(I2C_HandleTypeDef *hi2c),
 GPIO_TypeDef* clkGPIOx, uint16_t clkGPIO_Pin)
{
 if(clkGPIOx == NULL) return;
 if(MX_I2CX_Init == NULL) return;
 if(HAL_I2C_DeInit == NULL) return;

 HAL_StatusTypeDef state = HAL_I2C_IsDeviceReady(hicPtr, 0b1010000 <<1, 50, 5);

 if(state != HAL_BUSY) return;

 HAL_I2C_DeInit(hicPtr);

 GPIO_InitTypeDef GPIO_InitStruct;

 /* GPIO Ports Clock Enable */
 // __HAL_RCC_GPIOH_CLK_ENABLE();
 // __HAL_RCC_GPIOA_CLK_ENABLE();
 // __HAL_RCC_GPIOC_CLK_ENABLE();
 // __HAL_RCC_GPIOB_CLK_ENABLE();


 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(clkGPIOx, clkGPIO_Pin, GPIO_PIN_SET);


 GPIO_InitStruct.Pin = clkGPIO_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
 GPIO_InitStruct.Pull = GPIO_PULLUP;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(clkGPIOx, &GPIO_InitStruct);

 //9 Flanken ausgeben
 for(uint8_t i =0; i < 9; i++)
 {
 HAL_GPIO_TogglePin(clkGPIOx, clkGPIO_Pin);
 HAL_Delay(1);
 }

 HAL_GPIO_WritePin(clkGPIOx, clkGPIO_Pin, GPIO_PIN_SET);

 MX_I2CX_Init();

 state = HAL_I2C_IsDeviceReady(hicPtr, 0b1010000 <<1, 50, 5);

 NVIC_SystemReset();
}