Skip to main content
Visitor II
May 22, 2020
Solved

STM32 Enter DFU from VCP

  • May 22, 2020
  • 2 replies
  • 5163 views

Hello,

I have an application where I would like to switch the STM32G431KB into the built-in bootloader (using USB DFU) by sending a specific byte through the CDC Virtual COM port. I was able to get the unit into DFU mode by running the "USB_BootloaderInit" function below when a button is pressed, however when I try running the function upon reception of data from the CDC port, Windows either does not see the device or gives me a "Device Descriptor Request Failed" notification.

I get the feeling the USB port is still doing some work or there are interrupts still running, but I am not sure how to go about checking what is going on or properly clearing any pending interrupts, or what exactly is going on and I wanted to see if anyone could help point me in the right direction.

This is the function that allows me to enter into the bootloader:

void USB_BootloaderInit()
{
	volatile uint32_t addr = 0x1FFF0000;
	SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));	//Point the PC to the System Memory reset vector
 
	HAL_RCC_DeInit();		//Reset the system clock
	SysTick->CTRL = 0;		//Reset the SysTick Timer
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
 
	__set_MSP(*(uint32_t *)addr);
 
	SysMemBootJump();
 
	while(1);
}

It is being called when the correct character is received through the CDC_Receive_FS function as part of the CubeIDE USB Device Middleware.

Currently, I have tried running the USBD_DeInit and USBD_Stop functions before the USB_BootloaderInit function, along with putting some delay (5ms - 1Second using timers) between the DeInit/Stop and BootloaderInit functions, with no avail.

Any help is appreciated

    This topic has been closed for replies.
    Best answer by Uwe Bonnes

    You need to set VTOR an SYSCFG MEMMODE. But better is to have a switch in early startup code to check for some magicnumber in RAM that you set just before reset when DFU is requested.

    2 replies

    Graduate II
    May 22, 2020

    You need to set VTOR an SYSCFG MEMMODE. But better is to have a switch in early startup code to check for some magicnumber in RAM that you set just before reset when DFU is requested.

    McNickelAuthor
    Visitor II
    May 22, 2020

    Thank you Uwe Bonnes,

    I had been thinking about putting a statement in early startup, but I wasn't sure how to go about it so I was avoiding it, but it worked flawlessly.

    For anyone who is reading this in the future, here is what I did:

    When the correct character is received on the serial port, I run the following function:

    void USB_TriggerBootloader()
    {
    	SYSCFG->MEMRMP &= 0xFFFFFFF9;		//Remap the memory (may not be necessary)
    	SYSCFG->MEMRMP |= 1;
    	switchToBootloader = 0x11;			//Set the noinit variable to be read by startup code
    	NVIC_SystemReset();					//Reset the system
    }

    the switchToBootloader variable is defined as:

    uint8_t switchToBootloader __attribute__ ((section (".noinit")));

    The ".noinit" prevents the variable from being re-initialized upon a reset.

    After a reset, the first lines of code in the main function are an if statement which checks switchToBootloader and, if it is equal to 0x11, runs the following function:

    void (*SysMemBootJump) (void);
     
    void USB_BootloaderInit()
    {
    	switchToBootloader = 0x00;	//Reset the variable to prevent being stuck in the bootloader (since a device reset wont change it)
    	volatile uint32_t addr = 0x1FFF0000;	//The STM32G431KB system memory start address
    	SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));	//Point the PC to the System Memory reset vector
     
    	HAL_RCC_DeInit();		//Reset the system clock
    	SysTick->CTRL = 0;		//Reset the SysTick Timer
    	SysTick->LOAD = 0;
    	SysTick->VAL = 0;
     
    	__set_MSP(*(uint32_t *)addr);	//Set the Main Stack Pointer
     
    	SysMemBootJump();				//Run our virtual function defined above that sets the PC
     
    	while(1);
    }

    And it works reliably!

    EDIT: I added the declaration for SysMemBootJump.

    Visitor II
    June 4, 2020

    How did you define SysMemBootJump?

    Otherwise gives me:

    error: called object 'SysMemBootJump' is not a function or function pointer

     Update: Never mind...fund it (o;

    Super User
    May 22, 2020

    You can reset the USB peripheral using code similar to:

     // disable USB
     __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
     __HAL_RCC_OTGFS_FORCE_RESET();
     __HAL_RCC_OTGFS_RELEASE_RESET();