Skip to main content
Visitor II
March 10, 2022
Question

STM32F072CBT6 - Entering bootloader from application and USB (DFU) flasher

  • March 10, 2022
  • 3 replies
  • 1957 views

I have been able to use the below function to enter the bootloader from the Application and successfully flash a new firmware from the UART interface.

/**
 * @brief Resets the microcontroller entering into the embedded bootloader
 * to allow for upgrading the application's firmware
 * @param run Safety variable
 * @arg @ref TRUE To enable execution of the bootloader
 * @retval None
 */
void Bootloader_Start(uint32_t run) {
 void (*SysMemBootJump)(void);
 
 /**
 * Set system memory address.
 *
 * For STM32F072, system memory is on 0x1FFF C800
 * For other families, check AN2606 document table 155 with descriptions of memory addresses
 */
 volatile uint32_t addr = 0x1FFFC800;
 
 if (run == TRUE)
 {
 // De-initialize all peripherals configured for this Application
 HAL_TIM_Base_DeInit(&htim1);
 HAL_TIM_Base_DeInit(&htim6);
 HAL_TIM_Base_DeInit(&htim7);
 HAL_TIM_Base_DeInit(&htim14);
 
 HAL_TIM_PWM_DeInit(&htim15);
 HAL_TIM_Base_DeInit(&htim15);
 
 HAL_CRC_DeInit(&hcrc);
 
 HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
 HAL_NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);
 HAL_NVIC_DisableIRQ(DMA1_Channel4_5_6_7_IRQn);
 HAL_DMA_DeInit(&hdma_memtomem_dma1_channel2);
 
 HAL_PCD_DeInit(&hpcd_USB_FS);
 HAL_UART_DeInit(&huart2);
 HAL_UART_DeInit(&huart1);
 
 HAL_ADC_DeInit(&hadc);
 
 // Disable GPIO interrupts
 HAL_NVIC_DisableIRQ(EXTI0_1_IRQn);
 HAL_NVIC_DisableIRQ(EXTI2_3_IRQn);
 HAL_NVIC_DisableIRQ(EXTI4_15_IRQn);
 
 
 // Disable RCC, set it to default (after reset) settings
 // Internal clock, no PLL, etc.
 HAL_RCC_DeInit();
 
 // Disable SysTick timer and reset it to default values
 SysTick->CTRL = 0;
 SysTick->LOAD = 0;
 SysTick->VAL = 0;
 
 // Disable all interrupts
 __disable_irq();
 
 // Remap system memory to address 0x0000 0000 in address space
 __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
 
 // Set jump memory location for system memory
 // Use address with 4 bytes offset which specifies jump location where program starts
 SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
 
 /**
 * Set main stack pointer.
 * This step must be done last otherwise local variables in this function
 * don't have proper value since stack pointer is located on different position
 *
 * Set direct address location which specifies stack pointer in SRAM location
 */
 __set_MSP(*(uint32_t *)addr);
 
 /**
 * Call our function to jump to set location
 * This will start system memory execution
 */
 SysMemBootJump();
 }
}

However, in this new application, I require to use the USB interface for flashing the firmware. This application implements a USB CDC, so I modified the above code as follows:

void Bootloader_Start(uint32_t run) {
 void (*SysMemBootJump)(void);
 
 /**
 * Set system memory address.
 *
 * For STM32F072, system memory is on 0x1FFF C800
 * For other families, check AN2606 document table 155 with descriptions of memory addresses
 */
 volatile uint32_t addr = 0x1FFFC800;
 
 if (run == TRUE)
 {
 // De-initialize all peripherals configured for this Application
 HAL_TIM_Base_DeInit(&htim6);
 HAL_TIM_Base_DeInit(&htim7);
 USBD_DeInit(&hUsbDeviceFS);
 
 // Disable RCC, set it to default (after reset) settings
 // Internal clock, no PLL, etc.
 HAL_RCC_DeInit();
 
 // Disable SysTick timer and reset it to default values
 SysTick->CTRL = 0;
 SysTick->LOAD = 0;
 SysTick->VAL = 0;
 
 // Disable all interrupts
 __disable_irq();
 
 // Remap system memory to address 0x0000 0000 in address space
 __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
 
 // Set jump memory location for system memory
 // Use address with 4 bytes offset which specifies jump location where program starts
 SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
 
 /**
 * Set main stack pointer.
 * This step must be done last otherwise local variables in this function
 * don't have proper value since stack pointer is located on different position
 *
 * Set direct address location which specifies stack pointer in SRAM location
 */
 __set_MSP(*(uint32_t *)addr);
 
 /**
 * Call our function to jump to set location
 * This will start system memory execution
 */
 SysMemBootJump();
 }
}

When running this function microcontroller does disconnect from the computer, but it never loads the DFU, and the computer shows unknown device, so I am not able to see it listed on the SMT32CubeProgrammer.

Am I missing something?

Thanks in advance for your support.

    This topic has been closed for replies.

    3 replies

    Super User
    March 10, 2022

    > __disable_irq()

    Don't do this. The DFU bootloader requires interrupts to be enabled.

    If it still doesn't work, the problem likely that the chip is not in its default reset state. Consider setting a magic flag, resetting, and jumping to the bootloader immediately after startup. This will circumvent issues during deinitialization.

    ERODR.1Author
    Visitor II
    March 16, 2022

    Thanks!

    Removing the line that disables the interrupts worked. Now the STM32CubeProgrammer is able to detect the DFU device. However when connecting to it, it says the Read Protection is enabled. After connecting with the "Read Unprotect (MCU) option ticked", it says it disabled the protection. Then after disconnecting and reconnecting it gives the same error back...

    0693W00000KciCvQAJ.png 

    Any ideas? I flashed the firmware in debugger mode for testing purposes. But I also tried in Run mode and kept the ST-Link disconnected.

    Thanks again for your support!

    Super User
    March 16, 2022

    Not really. I believe removing RDP requires a chip erase/reset and I'm not sure how the DFU would handle that. I don't have much experience using the DFU bootloader.

    Why not just keep RDP off during development?

    ERODR.1Author
    Visitor II
    March 15, 2022

    Thanks!

    Removing the line that disables the interrupts worked. Now the STM32CubeProgrammer is able to detect the DFU device. However when connecting to it, it says the Read Protection is enabled. After connecting with the "Read Unprotect (MCU) option ticked", it says it disabled the protection. Then after disconnecting and reconnecting it gives the same error back...

    0693W00000KciCvQAJ.png 

    Any ideas? I flashed the firmware in debugger mode for testing purposes. But I also tried in Run mode and kept the STLink disconnected.

    Thanks again for your support!

    ERODR.1Author
    Visitor II
    March 15, 2022

    I also tried as suggested, setting up a flag to run the Bootloader_Start function after reset just before the initialization of peripherals begin.

    But I still get the same issue. The STM32CubeProgrammer is able to connect but says the device is read protected:

    0693W00000Kcjm6QAB.pngAnd when connecting with the "Read Unprotect (MCU)" option enabled, then I'm asked for confirmation to disable.

    0693W00000KcjmLQAR.pngAfter confirmation, I get that it is disabled successfully:

    0693W00000KcjnOQAR.pngBut then when I try to Download a new firmware I get the same warning saying it is under Read out protection:

    0693W00000KcjoWQAR.png 

    Is there a way to disable this RDP during runtime before I call the Bootloader function?

    Thanks for your time and input.