2025-09-08 8:01 AM
I have written a custom bootloader that is running on a Nucleo-L433RC-P board.
The application uses USB CDC to call the bootloader and the bootloader uses USB DFU to download the application.
I wanted to use USB to call the custom bootloader, rather than having to use a physical switch on the BOOT0 pin to call the internal bootloader
I can successfully download a simple application which just flashes an LED using the USB DFU bootloader.
However, when I download my actual project, it appears to download successfully but does not run.
My actual project is more complicated and uses the following peripherals:
I used the following guide to write the custom bootloader and simple application...
The following web tool is used to download the application...
I have spent days trying to debug why my actual project will not work, yet the simple application does.
Now I am at a complete loss and don't know how to proceed.
The implementation is shown below.
Bootloader USB configuration...
Changes to bootloader linker script...
Bootloader main.c...
#include "main.h"
#include "usb_device.h"
typedef void (*pFunction)(void);
#define DFU_BOOT_FLAG 0xDEADBEEF
RTC_HandleTypeDef hrtc;
uint32_t dfu_boot_flag;
pFunction JumpToApplication;
uint32_t JumpAddress;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
MX_RTC_Init();
dfu_boot_flag = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR5);
if (dfu_boot_flag != DFU_BOOT_FLAG)
{
if (((*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFC0000) == 0x20000000)
{
JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);
JumpToApplication = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
JumpToApplication();
}
}
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, 0); // So next boot won't be affected
uint32_t now = 0, next_blink = 100;
while (1)
{
now = uwTick;
if (now >= next_blink)
{
HAL_GPIO_TogglePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin);
next_blink = now + 100;
}
}
}
Changes to bootloader usbd_dfu_if.c....
Changes to bootloader usbd_dfu_if.h....
Changes to application linker script...
Simple application main.c...
#include "main.h"
#include "usb_device.h"
#define DFU_BOOT_FLAG 0xDEADBEEF
#define DFU_BOOT_REQ 0xAA
RTC_HandleTypeDef hrtc;uint32_t *dfu_boot_flag;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
int main(void)
{
uint32_t now = 0, next_blink = 1000;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
MX_RTC_Init();
HAL_PWR_EnableBkUpAccess();
while (1)
{
now = uwTick;
if (now >= next_blink)
{
HAL_GPIO_TogglePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin);
next_blink = now + 1000;
}
}
}
#define USB_RX_BUF_SIZE 512
volatile uint8_t usb_rx_buffer[USB_RX_BUF_SIZE];
volatile uint32_t usb_rx_count = 0; // number of bytes in buffer
void USB_CDC_RxHandler(uint8_t* Buf, uint32_t Len)
{
if ((usb_rx_count + Len) < USB_RX_BUF_SIZE)
{
memcpy((uint8_t *)&usb_rx_buffer[usb_rx_count], Buf, Len);
usb_rx_count += Len;
}
if (usb_rx_buffer[0] == DFU_BOOT_REQ)
{
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, DFU_BOOT_FLAG);
HAL_NVIC_SystemReset();
}
}
Changes to application system_stm32l4xx.c...
Changes to application usbd_cdc_if.c...
2025-09-08 8:23 AM
I think you should reconsider using the internal bootloader. It removes so much code complexity.
You can jump to it directly, rather than reconfiguring any BOOT0 pins. Is there another reason why it can't work?
How to jump to system bootloader from application ... - STMicroelectronics Community
2025-09-08 9:06 AM - edited 2025-09-08 9:06 AM
Thanks TDK
I was wondering if I could call the internal bootloader using USB
Looking at the responses you linked, there appears to be a lot of errors and issues so it still does not seem straight forward, but Ill give it a go.
One question though, can you only use STM32CubeProgrammer when using the internal bootloader ?
Or can any USB DFU tool be used, like the web version I was using ?
2025-09-08 11:12 AM
> Looking at the responses you linked
Don't let the responses *** you. It costs nothing to say something doesn't work and provide no evidence. The most common error (apart from not using the posted code) is that the chip needs to be in an as-reset state.
If you find something isn't working, post enough details and it will get sorted out.
> One question though, can you only use STM32CubeProgrammer when using the internal bootloader?
> Or can any USB DFU tool be used, like the web version I was using ?
You can use any tool that adheres to the DFU protocol. The two sides don't know what's on the other end but they need to speak the same language.
USB DFU protocol used in the STM32 bootloader - Application note
2025-09-08 1:10 PM - edited 2025-09-08 1:11 PM
Does your bootloader relocate the VTOR after the jump?
If you do not modify the startup_stm32xxxx_init.c file or, as I always do, place SCB->VTOR = to the address of the app in memory, any try of using interrupts would fail!
I see you indeed modify the startup file but for sake I would also add the SCB->VTOR = xxx before the call to HAL_Init just to be super sure.