2025-09-17 1:01 AM
I’m running into a strange issue when trying to jump into the STM32 bootloader.
I’ve built an FDCAN bootloader flasher using an STM32H7 along with a Windows host program. This setup allows me to reprogram both virgin and already-programmed. To do this, I set the BOOT pin high and reset the MCU (controlled by another MCU via test pads). This method works flawlessly every time, and it’s just as fast as using an ST-Link V3.
Now, I want to achieve the same result without using the BOOT pin (on already programmed MCU) —by sending a CAN message to trigger a jump into the STM32U5 internal bootloader. However, when I switch my programmer MCU to FDCAN mode and attempt communication, the bootloader does not respond....
My hardware is designed so that, by default, the CAN transceiver and all required circuitry are active and ready. But once I perform the jump, the MCU simply won’t respond to FDCAN messages.
Here’s what I’ve tried so far:
Resetting all pins back to default input with pull-ups
Disabling and enabling I/D caches
Testing multiple jump-to-bootloader code examples found online
Unfortunately, the result is always the same.
At the moment, my jump code looks like this:
void FDCAN_JUMP_STM32_BOOTLOADER(struct FDCAN_RECIEVE MESSAGE)
{
uint8_t RESPONSE[2]={COMMAND_STM32_BOOTLOADER_JUMP,0};
if(MESSAGE.FRAME1[1]==0xAA)
{
RESPONSE[1]=0xAA;
CAN_MESSAGE(2,0,FRAME_TYPE_SINGLE_FRAME,RESPONSE);
}
else
{
RESPONSE[1]=0xFF;
CAN_MESSAGE(2,0,FRAME_TYPE_SINGLE_FRAME,RESPONSE);
return;
}
uint32_t pending_Tx = 0xFFFF;
while(FDCAN_Pending_Tx()==1)
{
pending_Tx--;
if(pending_Tx==0)
{
break;
}
}
LL_AHB1_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
LL_AHB1_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
LL_AHB1_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
LL_AHB1_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD);
LL_AHB1_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE);
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_14, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_13, LL_GPIO_AF_0);
LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_14, LL_GPIO_AF_0);
LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_14, LL_GPIO_SPEED_FREQ_VERY_HIGH);
LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_13, LL_GPIO_PULL_UP);
LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_14, LL_GPIO_PULL_DOWN);
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pin = LL_GPIO_PIN_ALL & ~(LL_GPIO_PIN_13 | LL_GPIO_PIN_14);
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_ALL;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_ALL;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_ALL;
LL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_ALL& ~(LL_GPIO_PIN_1);
LL_GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_1|LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
LL_GPIO_Init(GPIOE, &GPIO_InitStruct);
DCMI_RESET_L; //JUST in case, these pins are not defined as boot related)
FDCAN_OE_H; //JUST in case, these pins are not defined as boot related)
void (*SysMemBootJump)(void);
volatile uint32_t addr = 0x0BF90000; //STM32U5 Bootloader
__disable_irq();
/* Disable Systick timer */
SysTick->CTRL = 0;
/* Set the clock to the default state */
LL_RCC_DeInit();
/* Clear Interrupt Enable Register & Interrupt Pending Register */
for (uint8_t i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++)
{
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
/* Re-enable all interrupts */
__enable_irq();
SysMemBootJump = (void (*)(void)) (*((uint32_t*)(addr + 4)));
__set_MSP(*(uint32_t*)addr);
SysMemBootJump();
}
Any idea why I can jump with RESET+BOOT High but not from code?