Trouble entering DFU on STM32F401 (B)
I am attempting to enter the system memory bootloader and reload my microcontroller via DFU on USB. I am having great difficulty getting it to work - I will detail the things I've tried below:
I have tried entering the bootloader via software and also by holding the BOOT0 pin low and resetting the part. I can enter the bootloader by both methods, but in neither case does the HSE start, nor the USB enumerate properly. When connected to a windows PC, I get "Device Descriptor Request Failed" if I check in the device manager.
When attempting to enter the bootloader via software, I use the following method: In the program below, I set _BOOTLOADER_TOKEN to BOOTLOADER_MAGIC_CODE and perform an NVIC_Reset - BOOTLOADER_TOKEN is reserved in my linker definition file, so it is not cleared by startup code, and I check for it at startup. This code executes in main() after HAL_Init() but before I have initialized any peripherals or clocks or anything. The behavior is the same even if I call this code before HAL_Init():
// Check the magic address
if (_BOOTLOADER_TOKEN == BOOTLOADER_MAGIC_CODE)
{
// Clear the magic code to prevent re-entering the bootloader after reset
_BOOTLOADER_TOKEN = 0;
// Jump to the system bootloader
// First, disable all global interrupts
__disable_irq();
// The system bootloader address for STM32F407
void (*SysMemBootJump)(void) = (void (*)(void)) (*((uint32_t *) 0x1FFF0004));
SYSCFG->MEMRMP = 0x01;
// Set the main stack pointer to the bootloader's stack pointer
__set_MSP(*(uint32_t *) 0x1FFF0000);
// Jump to bootloader
SysMemBootJump();
// Should never reach here
while (1);
}
When I use either method to enter the bootloader, I can attach and see that the program is indeed running, and it appears to be running "real" code in the bootloader section of memory. I get addresses such as (for example) 0x1fff07b2, 0x1fff05e2, 0x1fff0672, 0x1fff07e2 - this feels like it's running "real" program and not just spinning in a hardfault handler or something. I have no debug information for this area of code, so without decompiling it, or stepping through assembly instructions, I don't really know what it's doing.
Per AN2606, once it's done the detection phase of determining whether it should be listening on other peripherals, the bootloader is supposed to check for a USB cable (not clear what method it uses) and then start the HSE and enter DFU mode if a cable is present. I don't think it is doing this, because I don't see so much as a blip on the HSE output when I plug in the USB cable, or indeed any time after booting into the reloader. If the HSE was "trying" to start but didn't have the startup time necessary per the RCC configuration, I feel like I would at least see an attempted start. I have my scope setup to trigger at a fairly low voltage, and have disabled glitch filtering, etc.
There's always the chance that the bootloader is mistakenly deciding to listen on one of the other interfaces for reload. I don't know how to definitively determine if it is doing this, but I have reduced the chance of this, by strapping all of the pins indicated in the application note that it is listening on. Namely:
- PA7 (SPI1 MOSI) is actually tied to a SPI peripheral, but I have added a pull-down resistor and confirmed on the scope that there is no chatter or traffic at boot.
- PB15 (SPI2 MOSI) is a gpio in my application, with a pullup
- PC12 (SPI3 MOSI) is also a gpio in my application, with a pulldown
- PD6 (USART2 RX) is not a pin on my micro variant
- PA10 (USART1 RX) is a LCD select signal in my application that floats, but I have added a 10k pulldown to keep it in a known state when reset
- PB6/PB7 (I2C1 SCL/SDA) are connected to the UART of another micro in my application. I have put this micro into a state of the UART transceiver being initialized but it not sending or reciving anything
- PB3/PB10 (I2C2 SCL/SDA) - PB10 is a GPIO which I have strapped to ground. PB3 is UNCONNECTED (is this possibly my issue?) - I have yet to confirm its state at startup
- PA8/PB4 (I2C3 SCL/SDA) - These are actually connected to an I2C accelerometer, but the micro is the master in this relationship - (is this possibly my issue?)
Finally, the application note indicates that it is important that the USB be unconnected during the initial detection phase for the other peripherals. I have ensured this (tried it both ways) and it doesn't seem to make a difference.
I've spent a day on this - almost at wits end! What could it be?! Is there any way I can more thoroughly determine what the bootloader is actually doing internally (what peripheral it thinks it is listening on) or anything else I can easily try to get it to behave properly?
Thank you for any help
