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 - edited 2025-09-09 11:02 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
Edit: I just noticed the word f o o l is censored. This seems a bit much. I would even call it foolish.
Edit2: ***
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.
2025-09-09 9:00 AM
Thanks TDK, these things are never straight forward are they !
I used the example from the link you sent, the only modification I made was to enable the USB CDC so that I can call JumpToBootloader when 0xAA is received via USB.
However, when the bootloader is called the computer does not see the USB DFU device.
If I pause the debugger, it shows the following...
My code is below...
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define BOOT_ADDR 0x1FFF0000 // my MCU boot code base address
#define USB_RX_BUF_SIZE 512
#define DFU_BOOT_REQ 0xAA
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint8_t usb_rx_buffer[USB_RX_BUF_SIZE];
volatile uint32_t usb_rx_count = 0; // number of bytes in buffer
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
void JumpToBootloader(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
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;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @PAram None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : STATUS_LED_Pin */
GPIO_InitStruct.Pin = STATUS_LED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(STATUS_LED_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
struct boot_vectable_ {
uint32_t Initial_SP;
void (*Reset_Handler)(void);
};
#define BOOTVTAB ((struct boot_vectable_ *)BOOT_ADDR)
void JumpToBootloader(void)
{
/* Disable all interrupts */
__disable_irq();
// Reset USB
// USB->CNTR = 0x0003;
/* Disable Systick timer */
SysTick->CTRL = 0;
/* Set the clock to the default state */
HAL_RCC_DeInit();
// HAL_DeInit();
/* Clear Interrupt Enable Register & Interrupt Pending Register */
for (uint8_t i = 0; i <= 7; i++)
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
/* Re-enable all interrupts */
__enable_irq();
// Set the MSP
__set_MSP(BOOTVTAB->Initial_SP);
// Jump to app firmware
BOOTVTAB->Reset_Handler();
}
void USB_CDC_RxHandler(uint8_t* Buf, uint32_t Len)
{
// accumulate incoming USB data into the buffer
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)
{
JumpToBootloader();
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @PAram file: pointer to the source file name
* @PAram line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
In JumpToBootloader, I did add a few lines that people in the comments had mentioned but it still did not work...
// Reset USB
// USB->CNTR = 0x0003;
// HAL_DeInit();
This was from the response by EThom.3 who was also using the STM32L4
2025-09-09 9:21 AM
The JumpToBootLoader() function I use in an L4 device:
void JumpToBootloader(void)
{
#define conBootloadAddress 0x1FFF0000
void (*SysMemBootJump)(void);
uint8_t i;
__disable_irq();
// Reset USB
USB->CNTR = 0x0003;
//De-init all peripherals
HAL_ADC_DeInit(&hadc1);
HAL_DMA_DeInit(&hdma_i2c2_rx);
HAL_DMA_DeInit(&hdma_i2c2_tx);
HAL_I2C_DeInit(&hi2c2);
HAL_LPTIM_DeInit(&hlptim1);
HAL_LPTIM_DeInit(&hlptim2);
HAL_SPI_DeInit(&hspi1);
HAL_SPI_DeInit(&hspi2);
HAL_SPI_DeInit(&hspi3);
HAL_TIM_PWM_DeInit(&htim1);
HAL_TIM_Base_DeInit(&htim1);
HAL_TIM_Base_DeInit(&htim6);
HAL_TIM_PWM_DeInit(&htim15);
HAL_TIM_Base_DeInit(&htim15);
HAL_TIM_PWM_DeInit(&htim16);
HAL_TIM_Base_DeInit(&htim16);
HAL_UART_DeInit(&huart1);
HAL_DMA_DeInit(&hdma_usart2_tx);
HAL_UART_DeInit(&huart2);
// Disable Systick
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
// Reset clock to default
HAL_RCC_DeInit();
// Clear all interrupt bits
for (i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++)
{
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
__enable_irq();
SysMemBootJump = (void (*)(void)) (*((uint32_t *) (conBootloadAddress + 4)));
__set_MSP(*(uint32_t *)conBootloadAddress);
SysMemBootJump();
while (1); // Just in case...
}
2025-09-09 10:28 AM - edited 2025-09-09 10:29 AM
Thanks EThom.3,
I am using a simple application to call the bootloader for the moment, so dont have any peripherals enabled other than USB CDC (virtual comm port).
When I send 0xAA via USB to call the bootloader, it still does not show up as a DFU USB device.
If I disable the USB CDC and call the bootloader from main, the DFU USB device does appear.
However, when I flash a simple LED flashing application using the DFU USB bootloader, the program does not run (LED does not flash).
This is the code to call the bootloader (I had to remove the HAL_xxxx_Deinit as those peripherals were not being used)....
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define USB_RX_BUF_SIZE 512
#define DFU_BOOT_REQ 0xAA
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint8_t usb_rx_buffer[USB_RX_BUF_SIZE];
volatile uint32_t usb_rx_count = 0; // number of bytes in buffer
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
void JumpToBootloader(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
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;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : STATUS_LED_Pin */
GPIO_InitStruct.Pin = STATUS_LED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(STATUS_LED_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
void JumpToBootloader(void)
{
#define conBootloadAddress 0x1FFF0000
void (*SysMemBootJump)(void);
uint8_t i;
__disable_irq();
// Reset USB
USB->CNTR = 0x0003;
// Disable Systick
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
// Reset clock to default
HAL_RCC_DeInit();
// Clear all interrupt bits
for (i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++)
{
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
__enable_irq();
SysMemBootJump = (void (*)(void)) (*((uint32_t *) (conBootloadAddress + 4)));
__set_MSP(*(uint32_t *)conBootloadAddress);
SysMemBootJump();
while (1); // Just in case...
}
void USB_CDC_RxHandler(uint8_t* Buf, uint32_t Len)
{
// accumulate incoming USB data into the buffer
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)
{
JumpToBootloader();
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* file: pointer to the source file name
* line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
2025-09-09 10:48 AM
Hi your primary mistake is idea after init half MCU jump into app. No this not work.
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 ui
one way is deinit all inited before jump, but better is jump before init = setup marker and reset MCU in bootloader code.
int main(void)
{
if (((*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFC0000) == 0x20000000)
{
JumpAddress = *(__IO ui
....
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)
{
second is app code require right build and place... I dont check all.
For jumping condition exist more ways , but RTC isnt best...
But primary work your app coe if you loaded over stlink on right place and simply jump to it over stlink?
2025-09-09 10:59 AM
void USB_CDC_RxHandler(uint8_t* Buf, uint32_t Len) { // accumulate incoming USB data into the buffer 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) { JumpToBootloader();
You can't jump to the bootloader from within an IRQ context. That IRQ will not be able to fire again and pre-empt itself. The USB bootloader relies on USB interrupts to function correctly.
Instead, set a flag in the IRQ handler and jump to the bootloader in the main thread.