DFU bootloader in F4

victor_pv
Mon Aug 21, 2017 5:18 pm
Since the STM32F4xx MCUs have a DFU bootloader included in ROM, I’m thinking on adding code so when the board is rebooted to upload a sketch it goes to system rom, to show as DFU device, rather than just doing a hard reset.
The idea is to be able to reboot to DFU without using boot1 pin (as long as the reboot is triggered thru the sketch using the magic packet).
Currently the libmaple F4 doesn’t implement that, just does a hard reset:
https://github.com/rogerclarkmelbourne/ … vcp.c#L290

Not sure if the Generic core does it, haven’t looked at it, but if it doesn’t we should be able to do it the same way.
I am thinking on a modified version of this code:
https://community.st.com/thread/36971-h … -stm32f417


RogerClark
Mon Aug 21, 2017 9:26 pm
Steve is already investigating this.

I think I posted about it as well.

Perhaps we can move the posts scattered throughout the forum to one central post


RogerClark
Tue Aug 22, 2017 6:14 am
I can’t seem to move my post about it.. (in fact I think I’ve accidently deleted it when trying to move it)

So here is the link to STM’s community forum

https://community.st.com/thread/40238-s … m-software

The final code posted on that site is

typedef void (*pFunction)(void);
pFunction JumpToApplication;
uint32_t JumpAddress;

HAL_RCC_DeInit();

SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;

/**
* Step: Disable all interrupts
*/
__disable_irq();

/* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
__DSB();

__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();

/* Remap is bot visible at once. Execute some unrelated command! */
__DSB();
__ISB();

JumpToApplication = (void (*)(void)) (*((uint32_t *)(0x1FFF0000 + 4)));

/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) 0x1FFF0000);

JumpToApplication();


stevestrong
Tue Aug 22, 2017 6:41 am
Here is the code I was testing:
#include <Arduino.h>

void RCC_DeInit()
{
/* Set HSION bit */
RCC->CR |= (RCC_CR_HSION | RCC_CR_HSITRIM_4);

/* Reset CFGR register */
RCC->CFGR = 0;

/* Reset HSEON, CSSON, PLLON, PLLI2S */
RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON| RCC_CR_PLLI2SON);

/* Reset PLLCFGR register */
RCC->PLLCFGR = 0;
RCC->PLLCFGR = (RCC_PLLCFGR_PLLM_4 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLQ_2);

/* Reset PLLI2SCFGR register */
RCC->PLLI2SCFGR = 0;
RCC->PLLI2SCFGR = (RCC_PLLI2SCFGR_PLLI2SN_6 | RCC_PLLI2SCFGR_PLLI2SN_7 | RCC_PLLI2SCFGR_PLLI2SR_1);

/* Reset HSEBYP bit */
RCC->CR &= ~(RCC_CR_HSEBYP);

/* Disable all interrupts */
RCC->CIR = 0;
}

void JumpToBootloader(void) __attribute__((optimize("-O0")));
void JumpToBootloader(void)
{
void (*SysMemBootJump)(void);

/**
* Step: Set system memory address.
*
* For STM32F407, system memory is on 0x1FFF 0000
* For other families, check AN2606 document table 110 with descriptions of memory addresses
*/
volatile register uint32_t addr = 0x1FFF0000;

/**
* Step: Disable RCC, set it to default (after reset) settings
* Internal clock, no PLL, etc.
*/
RCC_DeInit();

/**
* Step: Disable systick timer and reset it to default values
*/
SYSTICK->CTRL = 0;
SYSTICK->LOAD = 0;
SYSTICK->VAL = 0;

/**
* Step: Disable all interrupts
*/
noInterrupts();
//delay(10000);
/**
* Step: Remap system memory to address 0x0000 0000 in address space
* For each family registers may be different.
* Check reference manual for each family.
*
* For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0])
* For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0])
* For others, check family reference manual
*/
SYSCFG->MEMRMP = 0x01;

/**
* Step: Set jump memory location for system memory
* Use address with 4 bytes offset which specifies jump location where program starts
*/
SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));

/**
* Step: Set main stack pointer.
* This step must be done last otherwise local variables in this function
* don't have proper value since stack pointer is located on different position
*
* Set direct address location which specifies stack pointer in SRAM location
*/
asm volatile ("mov r3, %0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : "r" (addr) : "r3", "sp");

/**
* Step: Actually call our function to jump to set location
* This will start system memory execution
*/
SysMemBootJump();

/**
* Step: Connect USB<->UART converter to dedicated USART pins and test
* and test with bootloader works with STM32 Flash Loader Demonstrator software
*/
}

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(3000);
Serial.println("This is a test how to jump to the system bootloader without setting BOOT0 pin to 1.\n");
Serial.println("Type any key to jump to ROM bootloader...\n");
// wait for user input
//while (!Serial.available()) ;
// read all serial input data
//while (Serial.available()) Serial.read();

//Serial.println("The system will now jump to ROM bootloader...");
//delay(100); // let time for serial to output message
// jump to bootloader
JumpToBootloader();
}

void loop() {
// put your main code here, to run repeatedly:
}


RogerClark
Tue Aug 22, 2017 7:31 am
Thanks

BTW. I know you were debugging the code… Does it work ?


stevestrong
Tue Aug 22, 2017 9:30 am
No, I’m still fighting with Eclipse debugging for F4 (as presented in another topic).

RogerClark
Tue Aug 22, 2017 10:02 am
OK
Perhaps someone using a HAL core on the F4 can try it to prove it works

RogerClark
Wed Aug 23, 2017 10:19 pm
Victor

Thinking about using the F4 internal DFU bootloader, I can see this could be problematic, because there is no timeout on the DFU and also the sketch would need to work perfectly so that it was able to jump to the bootloader

In may cases we all have problems were the code crashes etc, in which case the only option would be to move the jump links and press reset

We can’t even make the sketch always jump to the bootloader when it starts, because there isn’t a timeout on the built in bootloader.

I think we need to write a F4 version of the bootloader, probably using LibOpenCM3.

I did see some code on a Chinese website where someone had ported the Maple bootloader to the F4, but it was one of those sites where you have to pay a small fee to download the code and there was no way I was giving some unknown website my credit card details !


victor_pv
Thu Aug 24, 2017 1:45 am
I believe STM may have a boot loader application note with a sample bootloader code for DFU. We could probably take that, and modify to our liking.
I had been thinking too in the problem of the sketch crashing or something and needing to reboot the board with the boot1 jumper set.

RogerClark
Thu Aug 24, 2017 2:55 am
I cant find any STM code for a bootloader, but I have found a bootloader written using LibOpenCM3 for the F1
The repo says the F1 build is compatible with my F1 repo, which is interesting

https://github.com/devanlai/dapboot

It is probably worth trying that and if its any good, then see if it can be ported to the F4


devan
Thu Aug 24, 2017 7:27 am
Hi Roger,

dapboot is only compatible in the sense that it uses the same application offset as the STM32duino bootloader and uses the same RTC backup register values to force the bootloader to enumerate (in case you were wondering where those magic values came from…). It’s not really compatible with the normal STM32duino bootloading process.

It has the same behavior as the STM32F4 DFU bootloader, where it only enumerates if requested by the application or if the right pins are asserted at bootup. Personally, I prefer this behavior since there’s no fiddly PC-specific startup delay to contend with.

Recovering to the bootloader via jumper after flashing bad code is not an ideal workflow, but it’s not so bad – it’s not like you have to break out a hardware debugger or serial dongle or solder any new pins/wires to your board. I think using the USB DFU ROM bootloader will simplify support, since the board ships ready to accept sketches (assuming the vendors are not shipping F4 boards with random demo firmware).


RogerClark
Thu Aug 24, 2017 7:41 am
Hi Devan

Thanks. I thought I recognised the author’s name ;-)

I thought I could modify your code to behave in a similar way to the Maple bootloader

BTW. The LibMaple core currently does not set the Backup registers so the PC has to be ready quickly as the bootloader only stays in DFU for about 1 second.
When I was debugging some other code the other day, I did investigate setting the magic numbers in the Backup reg but I didn’t get it to work at the time, and I didnt have time to debug it.

The only change to your code would be to always enter DFU, but then exit after 1 second and jump to the Application sketch if the sketch is present (using the same validation code from the Maple bootloader)


devan
Thu Aug 24, 2017 8:24 am
It’s possible, though it would require ripping out some features to make space (I’ve currently got about 80 bytes to spare). I briefly looked into making it compatible awhile ago, but it started to look like it would require more time than I wanted to spend since I’m pretty happy with my current dfu-util workflow.

For setting the backup registers in the magic-reset-sequence from libmaple, the code that I used was:

// Write a magic flag into the RTC register 10 to ensure we reboot
// into persistent bootloader mode
bkp_init();
bkp_enable_writes();
bkp_write(10, 0x424C);
bkp_disable_writes();


RogerClark
Thu Aug 24, 2017 10:34 am
Thanks devan

Its interesting that LibOpenCM3 creates a larger binary than the Maple bootloader.

The backup registers code is not essential, so that would make some space.

Thanks

Roger


RogerClark
Fri Aug 25, 2017 9:50 pm
Perhaps porting the F1 bootloader to F4 may also be an option, but I don’t know how different the F4 and F1 USB subsystems are.

victor_pv
Sat Aug 26, 2017 2:27 am
CubeMX includes a DFU example, and I remembered Chris Barr mentioned he used it, so I went to his github and there it is. He made some small modifications so it runs more like the one we use on the F1s (it waits a few seconds and reboots, it checks if there is a sketch loaded…)
It’s already done and he used it with a 446 and the Generic core (which follows the same method as libmaple to reboot).
I’m sure it doesn’t need much to make it run in other MCUs. We also need to change the usb enumeration method to ours (pulling the usb pin down), but those changes should be small.
I think perhaps the major changes are in making it work with several F4 with differen flash sizes, but that may have been taken in account already by STM.

Do you see any problem in using the STM code? is part of the CubeMX.
I hope Chriss wouldn’t mind using his bits and pieces since they are small changes, but we can check with him.
It takes about 16KB, which I guess is alright on an F4, and may be possible to optimize it further.


RogerClark
Sat Aug 26, 2017 3:07 am
Hi Victor

I don’t see any problem with using the Cube. AFIK its license is not too restrictive.

Do you have a link to Chris’s bootloader ?

FYI
I built @devan’s bootloader this morning, but had to do it on my linux VM as on windows it needs msys, which I don’t currently have installed

PS.
Strangely I can build libopencm3 in the BMP repo on Windows without needing msys, and it uses libopemcm3, but Blacksphere must have changed the build process on libopencm3 to make it work on Windows.. But unfortunately the BMP version does not work with @davan’s code, as there appear to be differences in the API versions


victor_pv
Sat Aug 26, 2017 3:26 am
His coded is here:
https://github.com/chrissbarr/PicoPrint-Bootloader

its based on the 446, but I think the cube code is almost the same for all F4 since the use and the flash work the same way.
You can see the code he added on main to manage the usb discovery pin, 3 seconds time out, etc.


fpiSTM
Sat Aug 26, 2017 6:41 am
FYI, Dfu for F4 was implemented for the Otto:
https://github.com/arduino-org/arduino-core-stm32f4

To enter in dfu, no need user action, set seialusb config to 1200:
https://github.com/arduino-org/arduino- … _if.c#L261
Then, set a dedicated magic code at a dedicated @:
https://github.com/arduino-org/arduino- … _if.c#L436
Finally, during init:
https://github.com/arduino-org/arduino- … ds.cpp#L70
Call entersysrom:
https://github.com/arduino-org/arduino- … sROM.S#L11


RogerClark
Sat Aug 26, 2017 7:00 am
@fpstm

Thanks

I will look at those repo’s


victor_pv
Sat Aug 26, 2017 12:53 pm
But that is the ROM bootloader, the one you were mentioning that would not timeout, and that in case the sketch doesn’t work (for setting the magic word), then the user will have to use the boot pin to get the board to load a sketch again.
That is the same method that I mentioned in the first post.

logd32
Fri Dec 22, 2017 12:29 pm
[fpiSTM – Sat Aug 26, 2017 6:41 am] –
FYI, Dfu for F4 was implemented for the Otto:
https://github.com/arduino-org/arduino-core-stm32f4

To enter in dfu, no need user action, set seialusb config to 1200:
https://github.com/arduino-org/arduino- … _if.c#L261
Then, set a dedicated magic code at a dedicated @:
https://github.com/arduino-org/arduino- … _if.c#L436
Finally, during init:
https://github.com/arduino-org/arduino- … ds.cpp#L70
Call entersysrom:
https://github.com/arduino-org/arduino- … sROM.S#L11

@fpiSTM
Has any bootloader or POC been tried? This uses the read only ROM bootloader of F3/F4 core right?


fpiSTM
Sat Dec 23, 2017 6:01 am
For Otto it was functional.
Yes, no dedicated bootloader

edogaldo
Sat Dec 23, 2017 7:51 am
Hi all, I was wondering if it could be enough to set the system bootloader address in the reset handler to do the trick.

Best & merry Xmas, E.


logd32
Sun Dec 24, 2017 3:34 pm
@fpiSTM
OK, thanks, i tested the same mecanism for STM32F303, only replacing SRAM flag by RTC backup register since the F303CC doesnt have backup SRAM (so it was not working as is), the STM32F303 now resets on CDC 1200bps touch and can detect the DFU mode after reset.However, i still have a problem for jumping to bootlader (sysROM.s), it falls into usageFault when reaching line 19
https://github.com/arduino-org/arduino- … sROM.S#L19

Is SYSCFG_CFGR1 (+0x00) specific to STM32F4? i havent found any info on how to jump to the internal DFU bootlaoder on STM32F303 in datasheet and DM00046982. If anyone has a clue.


victor_pv
Sun Dec 24, 2017 7:08 pm
[edogaldo – Sat Dec 23, 2017 7:51 am] –
Hi all, I was wondering if it could be enough to set the system bootloader address in the reset handler to do the trick.

Best & merry Xmas, E.

Sorry I edited Edogaldo post by mistake before, this part was mine:

There is a bit more than that, you need to set the NVIC VTOR register so the NVIC can find the vector table.
This video shows it and shows sample code, very minimal. You just set a couple of registers and jump to it:
https://www.youtube.com/watch?v=cvKC-4tCRgw


victor_pv
Sun Dec 24, 2017 7:10 pm
[logd32 – Sun Dec 24, 2017 3:34 pm] –
Is SYSCFG_CFGR1 (+0x00) specific to STM32F4? i havent found any info on how to jump to the internal DFU bootlaoder on STM32F303 in datasheet and DM00046982. If anyone has a clue.

Generally the F3 peripherals are more similar to the F1 than the F4. It has a cortexM4 core, but with F1 peripherals (mostly), vs the F2 which has F4 peripherals with a cortex M3 like the F1.

So the SYSCFG_CFGR1 register may be very different between the F3 and F4, check the datasheet.


Leave a Reply

Your email address will not be published. Required fields are marked *