cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F42xx/3xx USB device DFU within a program

drogovin
Associate II
Posted on February 21, 2016 at 03:02

Hello,

We are working on a migration from the TI Stellaris products to the STM32F42xx.  The one thing I haven't been able to find yet is a way to duplicate how we allow firmware upgrades.  We use the USB-device port to run the DFU protocol.

Is there a way to jump to the bootloader from the application running on the micro?  In other words:

  • Bootloader is at location 0x0800 0000.
  • Application is at location 0x080C 0000.
  • Within the application is a function that--
    • Resets the micro,
    • Jumps to the bootloader, and
    • Starts it in a way that simulates that no application is installed.

The USB-device DFU example provided by ST only allows overwriting an application by performing an action (pressing a button) on starting up the bootloader.  What would be the cleanest way to start the bootloader from the application to allow overwriting of the application?  Maybe set a bit that's read by the bootloader?

Thanks!

#stm32-dfu-bootloader-usb-stm32f4
4 REPLIES 4
Posted on February 21, 2016 at 15:28

This is a highly recurring topic. I'll condensing it here, but there are numerous threads, and a quick Google may provide some additional context.

; On the startup.s side
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =0x2001FFF0 ; End of SRAM for your CPU
LDR R1, =0xDEADBEEF
LDR R2, [R0, #0]
STR R0, [R0, #0] ; Invalidate
CMP R2, R1
BEQ Reboot_Loader
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
Reboot_Loader PROC
EXPORT Reboot_Loader
; Device specific, if in doubt RTFM
LDR R0, =0x40023844 ; RCC_APB2ENR
LDR R1, =0x00004000 ; ENABLE SYSCFG CLOCK
STR R1, [R0, #0]
LDR R0, =0x40013800 ; SYSCFG_MEMRMP
LDR R1, =0x00000001 ; MAP ROM AT ZERO
STR R1, [R0, #0]
LDR R0, =0x1FFF0000 ; ROM BASE
LDR SP,[R0, #0] ; SP @ +0
LDR R0,[R0, #4] ; PC @ +4
BX R0
ENDP ; sourcer32@gmail.com
/* On the C side */
printf(''Entering Boot Loader..

'');
*((unsigned long *)0x2001FFF0) = 0xDEADBEEF; // End of RAM
NVIC_SystemReset();

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
drogovin
Associate II
Posted on February 22, 2016 at 23:34

Hi Clive,

Thank you so much for your help. You are correct, further searching reveals that this question has been answered many times. I will say it's not entirely clear that the System Memory provides a built-in bootloader. My solution is as follows. We're using the IAR Embedded Workbench as our development environment. We've decided to use the built-in bootloader in the STM32F427 micro and connect through the USB FS port. Define a __low_level_init function as follows:

#define C_BL_LOC_TRIG (0x2001FFF0) // location of trigger word (last address in STM32F427 memory)
#define C_BL_TRIGGER (0x0055AAFF) // known trigger value
#define C_BL_TRIGGER_RST (0xAAFF0055) // reset value after it's been used
#define C_BL_SYSMEM_ADDR (0x1FFF0000) // address of on-board bootloader in STM32F427
#define C_BL_SYS_JUMP (C_BL_SYSMEM_ADDR + 4) // system memory reset vector
__interwork 
int
__low_level_init(
void
)
{
void
(*SysMemBootJump)(
void
);
if
(C_BL_TRIGGER == *((unsigned 
long
*)C_BL_LOC_TRIG)) 
// last value in SRAM
{ 
// bootload trigger has been set.
*((unsigned 
long
*)C_BL_LOC_TRIG) = C_BL_TRIGGER_RST; 
// Reset our trigger
__set_MSP(*(__IO uint32_t*) C_BL_SYSMEM_ADDR); 
// set stack pointer to first addr in flash
SysMemBootJump = (
void
(*)(
void
)) (*((uint32_t *) C_BL_SYS_JUMP)); 
// Point the PC to the System Memory reset vector (+4)
SysMemBootJump();
while
(1)
;
}
return
1; 
// run seg_init
}

Include these lines of code in the location the bootloader should be called:

*((unsigned 
long
*)C_BL_LOC_TRIG) = C_BL_TRIGGER; 
// indicate that bootloader should be started
HAL_NVIC_SystemReset(); 
// force system reset; __low_level_int() function will start bootloader

The DFU file with the new target firmware is created using the Dfu File Manager program in the DfuSe package. The address of the target file is 0x0800 0000. DFU files are loaded with the DfuSeDemo program. Set target board into DFU mode, then choose the generated DFU file for upgrade. Thanks.
drogovin
Associate II
Posted on February 25, 2016 at 21:57

Code for implementing a custom bootloader for the STM32F42xx/3xx micro using IAR Embedded Workbench.

I used CubeMX to get the framework for the USB DFU middleware. Then I copied in the functions from the DFU_Standalone example software. Bootloader software starts at location 0x0800.0000:

USBD_HandleTypeDef USBD_Device;
pFunction JumpToApplication;
uint32_t JumpAddress;
#define C_BL_LOC_TRIG (0x2001FFF0) // location of trigger word
#define C_BL_TRIGGER (0x0055AAFF) // known trigger value
#define C_BL_TRIGGER_RST (0xAAFF0055) // reset value after it's been used
__interwork 
int
__low_level_init(
void
)
{
/* Test if (1) bootloader has NOT been entered from the application, and 
(2) user code is programmed starting from address 0x0800C000 */
if
((C_BL_TRIGGER != *((unsigned 
long
*)C_BL_LOC_TRIG)) &&
(0x20000000 == ((*(__IO uint32_t*)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFE0000 )))
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);
JumpToApplication = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
JumpToApplication();
}
return
1; 
// 1 to initialize data segments (0 to skip)
}
int
main(
void
)
{
// ...
if
(C_BL_TRIGGER == *((unsigned 
long
*)C_BL_LOC_TRIG))
*((unsigned 
long
*)C_BL_LOC_TRIG) = C_BL_TRIGGER_RST; 
// Reset our trigger
// ...
}

Application code starts at location 0x0800.C000. Make this change to system_stm32f4xx.c to point to the interrupt vector:

#define VECT_TAB_OFFSET 0x0C000
...
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 
/* Vector Table Relocation in Internal FLASH */

Application code:

#define C_BL_LOC_TRIG (0x2001FFF0) // location of trigger word
#define C_BL_TRIGGER (0x0055AAFF) // known trigger value
#define C_BL_TRIGGER_RST (0xAAFF0055) // reset value after it's been used
#define C_BL_ADDR (0x08000000) // address of our bootloader
#define C_BL_JUMP (C_BL_ADDR + 4) // system memory reset vector
__interwork 
int
__low_level_init(
void
) 
{
void
(*BlBootJump)(
void
);
if
(C_BL_TRIGGER == *((unsigned 
long
*)C_BL_LOC_TRIG)) 
// last value in SRAM
{ 
// bootload trigger has been set.
*((unsigned 
long
*)C_BL_LOC_TRIG) = C_BL_TRIGGER_RST; 
// Reset our trigger
__set_MSP(*(__IO uint32_t*) C_BL_ADDR); 
// set stack pointer to first addr in flash
BlBootJump = (
void
(*)(
void
)) (*((uint32_t *) C_BL_JUMP)); 
// Point the PC to the System Memory reset vector (+4)
BlBootJump();
while
(1)
;
}
return
1; 
// 1 to initialize data segments (0 to skip)
}
// Call this function where bootloader access is required
void
f_start_bootloader(
void
)
{
*((unsigned 
long
*)C_BL_LOC_TRIG) = C_BL_TRIGGER; 
// indicate that bootloader should be started upon reset
HAL_NVIC_SystemReset(); 
// force system reset; __low_level_int() function will start bootloader
}

Thanks.

The forum conversion appears to have butchered the code.

This is a highly recurring topic. I'll condensing it here, but there are numerous threads, and a quick Google may provide some additional context.

; On the startup.s side
 
Reset_Handler   PROC
    EXPORT  Reset_Handler             [WEAK]
    IMPORT  SystemInit
    IMPORT  __main
 
    LDR     R0, =0x2001FFF0 ; End of SRAM for your CPU
    LDR     R1, =0xDEADBEEF
    LDR     R2, [R0, #0]
    STR     R0, [R0, #0] ; Invalidate
    CMP     R2, R1
    BEQ     Reboot_Loader
 
    LDR     R0, =SystemInit
    BLX     R0
    LDR     R0, =__main
    BX      R0
    ENDP
 
Reboot_Loader   PROC
    EXPORT  Reboot_Loader
 
    ; Device specific, if in doubt RTFM, here F2/F4
 
    LDR     R0, =0x40023844 ; RCC_APB2ENR
    LDR     R1, =0x00004000 ; ENABLE SYSCFG CLOCK
    STR     R1, [R0, #0]
    LDR     R0, =0x40013800 ; SYSCFG_MEMRMP
    LDR     R1, =0x00000001 ; MAP ROM AT ZERO
    STR     R1, [R0, #0]
    LDR     R0, =0x1FFF0000 ; ROM BASE
    LDR     SP,[R0, #0]     ; SP @ +0
    LDR     R0,[R0, #4]     ; PC @ +4
    BX      R0
 
    ENDP ; sourcer32@gmail.com
 
/* On the C side */
 
    printf("Entering Boot Loader..\r\n");
 
    *((unsigned long *)0x2001FFF0) = 0xDEADBEEF; // End of RAM
 
    NVIC_SystemReset();

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..