cancel
Showing results for 
Search instead for 
Did you mean: 

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

ERODR.1
Associate III

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.

6 REPLIES 6
TDK
Guru

> __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.

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

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.1
Associate III

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.

ERODR.1
Associate III

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!

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?

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

As a matter of fact, the RDP is not being turned on by the time of loading the firmware. For some reason, the way the DFU bootloader is being executed is what is causing it to say RDP is on...