cancel
Showing results for 
Search instead for 
Did you mean: 

STM32C011F6 I²C Bootloader Jump from Application — NACK on SYNC

Anees1
Associate

Dear STMicroelectronics Support Team,

I am currently working with the STM32C011F6 microcontroller and attempting to enter the built-in system bootloader via software from my application. My goal is to flash the device over I²C from an external processor (RFSoC running Linux), without toggling the BOOT0 or RESET pins.

I followed the STM32 application notes AN2606 and AN4221 closely and implemented the bootloader jump using the standard approach:

1. Disabling all interrupts (NVIC->ICER / ICPR)
2. De-initializing peripherals (HAL_DeInit, HAL_RCC_DeInit)
3. Stopping SysTick
4. Setting the MSP from address 0x1FFF0000
5. Jumping to the bootloader reset handler at 0x1FFF0004

From the external I²C master, I send the `0x7F` SYNC byte, and I **consistently receive a NACK (0x1F)** instead of the expected ACK (0x79). I confirmed the I²C lines (PA9 and PA10), 100kHz speed, correct pull-ups, and that the STM32 is not held in reset or debug mode. I also verified that the bootloader jump function is being called properly by printing debug messages over UART before the jump.

I suspect the STM32 is not correctly initializing the bootloader I²C peripheral or is exiting bootloader mode prematurely, even though I send the SYNC immediately after the jump.

Could you please help confirm:

- Whether STM32C011F6 supports jumping to system bootloader (0x1FFF0000) from application for I²C?
- Are there additional steps or constraints (option bytes, flash size, peripheral clock resets, etc.) specific to the C0 series that may be preventing I²C bootloader activation via software?
- Any known limitations or errata for bootloader use in STM32C011F6?

This is the function I used to jump from application to STM32 system bootloader.

void jump_to_bootloader(void)
{
__disable_irq();

for (int i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}

SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;

HAL_RCC_DeInit();
HAL_DeInit();

__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
__HAL_RCC_I2C1_CLK_DISABLE();
__HAL_RCC_USART1_CLK_DISABLE();

uint32_t bootloader_msp = *(volatile uint32_t *)0x1FFF0000;
uint32_t bootloader_reset = *(volatile uint32_t *)(0x1FFF0000 + 4);
void (*bootloader_entry)(void) = (void (*)(void))bootloader_reset;

__set_MSP(bootloader_msp);
bootloader_entry();

while (1);
}

Thank you for your support.

Best regards,
Anees A.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

> From the external I²C master, I send the `0x7F` SYNC byte, and I **consistently receive a NACK (0x1F)** instead of the expected ACK (0x79).

The I2C bootloader doesn't have a SYNC byte. There is no reason to expect 0x79 after sending 0x7F.

I2C protocol used in the STM32 bootloader - Application note

 

Just send the command you want. The ACK on the address bit indicates the bootloader is listening.

 

You should do __enable_irq before jumping to the bootloader.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

2 REPLIES 2
TDK
Super User

> From the external I²C master, I send the `0x7F` SYNC byte, and I **consistently receive a NACK (0x1F)** instead of the expected ACK (0x79).

The I2C bootloader doesn't have a SYNC byte. There is no reason to expect 0x79 after sending 0x7F.

I2C protocol used in the STM32 bootloader - Application note

 

Just send the command you want. The ACK on the address bit indicates the bootloader is listening.

 

You should do __enable_irq before jumping to the bootloader.

If you feel a post has answered your question, please click "Accept as Solution".
Anees1
Associate

Thanks for the reply,
i have removed the "sync" stage from my code and now able to flash the controller through i2c.

But one issue is still there, even after the bootloader acknowledging the "Go" command, i have to powercycle or manually press the reset button the run the new firmware.