2020-05-21 10:16 PM
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
Solved! Go to Solution.
2020-05-22 12:45 AM
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.
2020-05-22 12:45 AM
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.
2020-05-22 03:57 AM
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();
2020-05-22 01:54 PM
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.
2020-06-04 02:38 AM
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;
2020-06-05 01:26 AM
Still no luck with your code...
It does reset and the switchToBootloader is still set to 0x11....but after USB_BootloaderInit() the device is gone.
Guess something to do with the SYSCFG remapping....
SYSCFG->MEMRMP doesn't exist for the STM32F0 family...
Guess it must be SYSCFG_CFGR1_MEM_MODE then...
2020-06-05 09:54 AM
Check out AN2606, read the section for the device you are using and also read section 64 to get the system memory address for that device (set “addr�? to the first address listed in the system memory column for the device)
AN2606:
2020-06-08 02:33 AM
The appnote only tells that BOOT0 pin has to be set high.....and I already had the sys mem address correct with 0x1FFFC800.
Now hooked up my Nucleo-G431 board and used your code here....and connected USB via PA11/PA12...
When it hits USB_BootloaderInit() after reset....I don't even see a message then trying to enumerate the bus...
int main(void)
{
......
......
if(switchToBootloader == 0x11)
{
HAL_Delay(2000);
char text[20] = "Switching to DFU\n\r";
CDC_Transmit_FS((uint8_t *)text, 18);
USB_BootloaderInit();
}
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(send_usb)
{
HAL_RTC_GetTime(&hrtc, &currTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &currDate, RTC_FORMAT_BIN);
sprintf(buffer,"%02d.%02d.20%02d %02d:%02d:%02d\n\r", currDate.Date, currDate.Month, currDate.Year, currTime.Hours, currTime.Minutes, currTime.Seconds);
CDC_Transmit_FS((uint8_t *)buffer, 21);
send_usb = 0;
counter++;
if(counter > 10)
USB_TriggerBootloader();
}
}
}
/* USER CODE BEGIN 4 */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
// HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
send_usb = 1;
}
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
}
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);
}
/* USER CODE END 4 */
2020-06-08 11:35 AM
I will take a deeper look at your code in a bit, but the first thing i notice: try removing lines 7 - 9 ( The delay and CDC transmit). I had to add the whole reset part because I was only seeing an error when it was triggered by USB, so i presume there is maybe an interrupt or a task that hasn't been cleared that is causing the issue.
Do the CDC functions work correctly? Are you getting data to/from the computer?
EDIT: also make sure the if switchToBootloader statement, line 5, is the absolute first piece of code in your main function, prior to all of the initializations.
2020-06-08 11:53 AM
Okay...will have a deeper look tomorrow morning (o;
Well for the CDC functions...it sends every second the RTC date/time out without problems....though there is no code yet for receiving...
You mean that switchToBootloader part has to come even before the pre-defined HAL initializations?
Ah that might cause the problem...
Well would be great if that was it so I can soon publish my programmable thermocouple USB logger hard/software project on github for everyone (o;
Will keep you updated...
many thanks
richard