cancel
Showing results for 
Search instead for 
Did you mean: 

How to Modify USB DFU firmware examples to work with STM32CubeProgrammer

MCU Support TD
ST Employee
Within the Cube firmware packages, there are examples of in-application USB DFU that were originally created for use with the DFuse software utility. DFuse is now not recommended for new designs, so the purpose of this article is to show how these examples can be tailored to work with STM32CubeProgrammer.

How to Modify USB DFU firmware examples to work with STM32CubeProgrammer

 

1. Summary

  • This process will be demonstrated on the STM32L476-Discovery board using STM32CubeIDE and STM32CubeProgrammer. The goal of the article is to use the DFU_Standalone firmware example found in the CubeL4 firmware package with STM32CubeProgrammer to upload an application binary to the board. The application binary used in this article is the GPIO_IOToggle, which can also be found the CubeL4 firmware package.
  • Since the DFU_Standalone example was originally designed to work with a deprecated tool, DFuse, this article intends to show the process of making this example work our more current tool, STM32CubeProgrammer.
  • This same process can be adapted to work with other boards and firmwares.

2. Modification of the USB DFU firmware

  • Open STM32CubeIDE. Navigate to File -> Open Projects from File System…
  • Open the project found at the default location:
    C:\Users\your_username\STM32Cube\Repository\STM32Cube_FW_L4_V1.17.2\Projects\32L476GDISCOVERY\Applications\USB_Device\DFU_Standalone\SW4STM32\STM32L476G_Discovery_USBD-FS
  • This project is the USB DFU program. Since this was originally created to work with DFuse, it will need to be modified to work with STM32CubeProgrammer. The original firmware has a check to indicate that the firmware has been uploaded. In main.c, lines 76 - 90
  •   if(BSP_JOY_GetState() == JOY_NONE)
      {
        /* Test if user code is programmed starting from address 0x0800C000 */
        if(((*(__IO uint32_t*)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFE0000 ) == 0x20000000)
        {
          /* Jump to user application */
          JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);
          JumpToApplication = (pFunction) JumpAddress;
          
          /* Initialize user application's Stack Pointer */
          __set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
          JumpToApplication();
        }
      }  
    
    
  • This check only works assuming the code was uploaded via DFuse. This will instead be modified to use the user joystick button to jump to the user application address. This solution is intentionally not robust to keep things simple, but in your own application you can add whatever proprietary solution you like to indicate that the user firmware has been downloaded. Please replace the above code with the code below:
  • /* Check if the KEY Button is pressed */
      if(BSP_JOY_GetState() == JOY_SEL)
      {
    	
          /* Jump to user application */
          JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);
          JumpToApplication = (pFunction) JumpAddress;
          
          /* Initialize user application's Stack Pointer */
          __set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
          JumpToApplication();
      }  
    
  • This code will make it so that the USB DFU bootloader jumps to the application when the user joystick button on the board is held down during reset. 
  • Build the firmware now. Make sure the project is selected in the explorer and hit the hammer icon in the toolbar

                      1320.png
 

3. Modification of the Application Firmware

  • For application firmware to upload via USB DFU, we will use the firmware example GPIO_IOToggle. This is just for example; the same process can be used for any firmware.
  • Navigate to File -> Open Projects from File System…
  • Open the project found at the default location:
    C:\Users\your_username\STM32Cube\Repository\STM32Cube_FW_L4_V1.17.2\Projects\32L476GDISCOVERY\Examples\GPIO\GPIO_IOToggle\SW4STM32\STM32L476G-Discovery
  • First, we will need to modify the linker file of the project. The default linker expects the application to be at the beginning of flash: 0x08000000. From the file STM32L476VGTx_FLASH.ld lines 41-46:
  • /* Specify the memory areas */
    MEMORY
    {
    FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
    RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 96K
    }
    
  • We just need to change the starting flash address to where the DFU firmware expects the application to be ( 0x800C000 ) and adjust the length accordingly.
    0xC000 = 48K              1024K – 48K  = 976
  • Replace the above code with the code below.
  • /* Specify the memory areas */
    MEMORY
    {
    FLASH (rx)      : ORIGIN = 0x800C000, LENGTH = 976K
    RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 96K
    }
    
  • Lastly, we just need to relocate the address of the vector table to be at the beginning of the new firmware. In the application firmware, at the beginning of main.c, add the relocation as the first line of main():
  • int main(void)
    {
    	SCB->VTOR = 0x800C000;
    ...
    
    }
  • Build the firmware now. Make sure the project is selected in the explorer and hit the hammer icon in the toolbar.

                      1321.png
 

4. DFU Process with STM32CubeProgrammer

  • With both firmwares built, it’s time to load the USB DFU firmware onto the board. Connect the STM32L476-DISCOVERY board the your computer via the CN1 ST Link USB connector with a USB type A to mini cable. In CubeIDE, select the USB DFU project in the explorer and upload the firmware to the board with Run As… -> STM32 Cortex-M C/C++ application:

                     1322.png
                       1324.png
  • Keep the run configurations at the default settings and select OK. This will load the USB DFU firmware to the board. Now connect USB USER CN7 connector to the PC via a USB A to micro cable. This cable handles the USB DFU data transfer.
  • Now open STM32CubeProgrammer.  In the right panel, select USB in the drop down menu next to the connect button. Now press the refresh button next to the port field, and you should see the USB DFU port show USB1. Press Connect.
                       1326.png
 
  • Once connected, navigate to the erasing and programming section:

                      1329.png
 
  • Now we need to browse to the file path of the binary created by the GPIO_IOToggle application. This can be found in the Debug folder within the project folder. Select the Browse button next to the file path field and navigate to the binary:
    GPIO_IOToggle\SW4STM32\STM32L476G-Discovery\Debug\STM32L476G-Discovery.bin
  • Set the Start address to 0x800C000 and click Start Programming.
     
                       1331.png
 
  • Once it has finished downloading, disconnect STM32CubeProgrammer. While holding the joystick center button down on the board, press the reset button. This will cause the DFU firmware to jump to the GPIO_IOToggle application, and you should see the user LEDS LD4 and LD5 starting to flash. If the reset button is hit without the joystick button being pressed down, the board will once again be in USB DFU mode.
  • This example is meant to demonstrate a bare bones USB DFU bootloader. In practice, it is recommended to implement a more robust means of managing and checking uploaded firmwares.
     

 
Comments
EMUAN
ST Employee

Should be C:\Users\your_username\STM32Cube\Repository\STM32Cube_FW_L4_V1.17.2\Projects\32L476GDISCOVERY\Applications\USB_Device\DFU_Standalone\SW4STM32\STM32L476G_Discovery_USBD-FS , isn't it. in 2. Modification of the USB DFU firmware

Pavel A.
Evangelist III

Which driver is needed for the CubeProgrammer to detect devices in DFU mode? Please post a link?

Version history
Last update:
‎2022-05-27 07:30 AM
Updated by: