cancel
Showing results for 
Search instead for 
Did you mean: 

How do I modify an stm32f439vitx system workbench stm32 project for use with a bootloader.

DCarr.1
Senior

I have an existing stm32f439vitx custom board project which works fine when flashed at address 0x08000000 which I now need to make runnable from an existing bootloader expecting the program to have been flashed at address 0x8008000.

Is it enough to change the linker script ROM origin and length?

1 ACCEPTED SOLUTION

Accepted Solutions

Try with this in the linker file

/* Sections */
SECTIONS
{
  /* The startup code into ROM memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = 0x200; /* apparently this should be relative to the section start */
    KEEP(*(.mystartup))   /* The reset handler code where the bootloader is expecting it */
    . = ALIGN(4);
  } >ROM
  /* The program code and other data into ROM memory */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */

View solution in original post

26 REPLIES 26
berendi
Principal

Find the line (usually in system_stm32f4xx.c) where SCB->VTOR is assigned to, and change it to the new base address. If the bootloader has left any interrupts enabled, disable them before changing SCB->VTOR.

The bootloader and the application must agree on the state of all peripherals.

Brilliant!

I shall give that a try, thanks.

DCarr.1
Senior

So I gave it a try and it didn't work, no doubt due to a failure on my part.

I've traced through the bootloader source and - after tinkering with various peripherals for its own purposes - it executes this function :

void JumpToApp(void)
{
   DisableInterrupts();
   NVIC_VTOR = 0x8000;
   asm {
           MOVW        R0, #65532
           MOVT        R0, #8192
           MOV         SP, R0
 
           MOVW        R0, #0x8201
           MOVT        R0, #0
           BLX         R0
       }
}/* end JumpToApp() */

Which means basically nothing to me :(

The application binary file itself is copied to flash starting at address 0x08008000 although it's not completely impossible that some checksums and so on have been inserted at the start of the file before the start of the linker.

This inline assember block assumes that the stack pointer should be set to 0x2000FFFC, meaning the static data segment is either much smaller than 64K, or it begins at the 64K mark (0x20001000). Moreover, it assumes that the reset handler function is at 0x08008200.

This bootloader is for a specific system with an unusual memory layout. Are you sure that it's for the STM32F4 series?

A generic bootloader should rather load the stack pointer and the reset address from the vector table, at 0x08008000 and 0x08008004 in your case.

What kind of compiler is it? The syntax looks like Keil, but does Keil work with system workbench?

Seems odd that it wouldn't load the SP/PC dynamically from the vector table, not sure the entire flash maps to zero

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

The bootloader is for a custom board, but I'm as sure as I can be that it's a standard stm32f439vitx without anything really special going on in terms of memory or anything else; the programs I build in system workbench for stm32f439vitx work fine when I flash them directly using an ST-link at a base address of 0x08000000

The bootloader and legacy app which I'm replacing are built in the "mikroelectronica" environment: I'm using system work bench for the replacement app and would have a hard time justifying a new bootloader.

Do you think there could be a fundamental incompatibility here?

As a slight update, ST-link confirms that the device is a stm32f42xxx/f43xxx, device id 0x419, revision id Rev 3, flash size 2Mbytes.

Something that might be relevant is that the bootloader downloads and flashes an "ocf" file via bluetooth, which after much googling seems to be in some way related to "firmware update services" : https://www.st.com/content/ccc/resource/technical/document/application_note/group1/c0/40/e9/04/c6/83/40/70/DM00513965/files/DM00513965.pdf/jcr:content/translations/en.DM00513965.pdf

No fundamental incompatibility, just the bootloader makes some assumptions that are not there.

The first half of the inline assembly sets the stack pointer to 0x2000FFFC (8192=0x2000, 65532=0xFFFC). Replace it with the initial stack pointer of the application. As the initial stack ponter (top of stack) does rarely if ever change, you can assume it's a constant, and simply replace the hard-coded halfword values in MOVW and MOVT.

Then you can replace the second half with standard C code that reads the address stored at 0x08000004, and jumps there with the help of a function pointer.

Thanks a lot, this is all incredibly helpful and is all starting to make sense to me now.

So a generic bootloader would look schematically like this:

uint32_t sp = *(uint32_t*)0x08008000; // get firmware's stack pointer from the firmware
function_t* reset = *(function_t*)0x08008004; // get firmware's reset address from the firmware
 
asm {
      MOVW    R0, #(sp & 0x0000ffff)
      MOVT    R0, #(sp & 0xffff0000)
      MOV     SP, R0
}
 
reset();

Whereas I'm dealing with a bootloader which looks schematically like this:

uint32_t sp = 0x2000FFFC; // assume the firmware's stack pointer
function_t* reset = (function_t*)0x08008200; // assume the firmware's reset address
 
asm {
      MOVW    R0, #(sp & 0x0000ffff)
      MOVT    R0, #(sp & 0xffff0000)
      MOV     SP, R0
}
 
reset();

Although I would dearly love to replace the bootloader with something more generic, I'm going to have to make my app compatible with the legacy behaviour :(

If I understood correctly, this means changing the stack pointer set in the linker script from

_estack = 0x20030000  /* as created by system workbench */

to

_estack = 0x2000FFFC /* as required  by bootloader */

And then somehow force the reset handler to be 0x08008200.

This is very much a subsidiary question, but digging through the bootloader sources, I find that when the firmware is downloaded and copied to flash it is written to 0x08008000 onwards, and then at the end of the programming cycle eight bytes of checksum information are written to the hard-coded adresses 0x081FFE00 to 0x081FFE07:

0x081FFE00 firmware length byte 0

0x081FFE01 firmware length byte 1

0x081FFE02 firmware length byte 2

0x081FFE03 firmware length byte 3

0x081FFE04 firmware CRC

0x081FFE05 firmware CRC

0x081FFE06 0xAA

0x081FFE07 0x55

Then during normal boot these eight bytes are read back from address 0x001FFE00 onwards and the firmware verified from 0x0008000 onwards. Is the address range 0x00xxxxxx automatically mapped onto 0x08xxxxxx?

Once again, thankyou very, very much for all the help.