Skip to main content
McNickel
Associate
May 22, 2020
Solved

STM32 Enter DFU from VCP

  • May 22, 2020
  • 11 replies
  • 5266 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.

11 replies

Uwe Bonnes
Uwe BonnesBest answer
Chief
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.

McNickel
McNickelAuthor
Associate
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.

Davorin
Associate III
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;

TDK
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();

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