Skip to main content
john
Associate III
March 28, 2008
Question

calling boot/flash loader from user code

  • March 28, 2008
  • 12 replies
  • 1775 views
Posted on March 28, 2008 at 11:28

calling boot/flash loader from user code

    This topic has been closed for replies.

    12 replies

    john
    johnAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    Hi,

    Can anyone show me how to call/use the buit-in bootloader code

    (in System Memory at 0x1ffff000) from my own user code ?

    For my own development use, it would be useful it we could

    trigger the bootloader from within our own application (on the

    push of a button...), rather than have to change the boot pins

    and re-boot the chip.

    If anyone can point me in the correct direction - ie. jump to

    address ???, please let me know.

    If it can be done, please also point me at some example code,

    of how to do a JMP in C, or include the assembler code needed...

    Thanks,

    John.

    john
    johnAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    Hi,

    Thanks Giles - I pretty much had that, but in seeing your post and

    then double-checking things, I found a couple of mistakes...

    It now works !

    There is one big difference - the entry point for the code.

    Taken from this post :-

    http://www.st.com/mcu/forums-cat-6520-23.html

    At the start of the bootloader ROM at 0x1ffff000 we have;-

    20000200 (initial SP )

    1FFFF749 (initial PC=start of CODE in system boot mode ROM)

    So I changed the entry point to be 1FFFF749 and it worked.

    My code looks like :-

    typedef void *(*ARM_FlashLoader_Fn)

    (

    void

    );

    ARM_FlashLoader_Fn FlashLoader = (ARM_FlashLoader_Fn)0x1FFFF749;

    and when I want to start the flash loader :-

    FlashLoader();

    And here's how to use it :-

    The arm is running with both boot pins at 0 - run from FLASH.

    My app is running, then trigger the FlashLoader() some way (eg. key press).

    Then use the ''STMicroelectronics Flash Loader Demonstrator'' PC app to

    download a new hex file, and tick the 'jump to the user program'.

    NB. this hex file needs to be built in release mode,

    ie. with STARTUP_FROM_RESET defined for the build.

    Upon download completion, it starts my new app running.

    Done.

    This does leave me with a question, about that little table at the start

    of the flash loader memory, and what the ARM normally does on bootup...

    Do you know where this might be documented ?

    What I want to know is - what exactly does the ARM chip do on booting ?

    I understand the BOOT pins effect the area of memory to use, but it

    can't simply jump to that address - it must use that table in some

    way...

    Any pointers/suggestions ?

    Yours,

    John.

    lanchon
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    (this was discussed earlier.)

    giles
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    in C this is how to cast an address as a void function and call it

    (*(void (*) (void))(0x1ffff000))();

    i cant remember the assembler equivalent for sure but its roughly

    ldr r1 0x1ffff000

    blx r1

    if the boot loader remaps the memory and uses absolute addressing the function you're jumping to won't work thought but as i don't know the boot loader code i haven't a clue.

    john
    johnAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    Hi,

    Thanks Lanchon - I understand what your saying, and most of the details,

    but I just don't know enough to understand it all.

    I've been doing some more reading, thinking and code testing...

    When you say :-

    -set SCB->VTOR to the sys mem start (0x1ffff000?) (this is to more or less emulate the reset behavior; on reset VTOR = 0, but when booting the bootloader the sys mem is aliased to adr 0, so the vectors are available.)

    I understand that setting SCB->VTOR (0xE000ED08) is setting the address of

    the vector table - and you are saying that to enter the bootloader, this

    needs to be 0x1ffff000 - OK.

    But I don't understand what you mean about the memory aliasing ?

    Do you mean memory addresses are re-mapped or paged in some way ?

    and for :-

    -SP = *((int*) 0x1ffff000);

    -PC = *((int*) 0x1ffff004);

    I can do this with some inline assembly.

    My resulting code is :-

    SCB->VTOR = 0x1ffff000;

    __asm__(

    /* Initialise the stack pointer */

    '' ldr r0, =0x1ffff000 \n\t''

    '' ldr r1, [r0] \n\t''

    '' mov sp, r1 \n\t''

    /* Jump to FlashLoader entry point */

    '' ldr r0, =0x1ffff004 \n\t''

    '' ldr r1, [r0] \n\t''

    '' blx r1 \n\t''

    );

    Does that look better ?

    NB. I know I've not included all the resetting of the peripherals,

    but that should be a simple matter of calling the DeInit() functions.

    It certainly is still working, and just to note, the SP is reset to

    the value of 0x20000200, and the flashloader code entry point is

    0x1FFFF749.

    John.

    lanchon
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    jumping to the loader like that is dangerous since the stack pointer could be at a ram area used for storage in the loader.

    at a minimum you should:

    -reset all RCC-resetable peripherals (see RCC_APBxPeriphResetCmd())

    -safer if you also reset DMA and NVIC

    -reset the RCC to HSI without PLL and other default stuff (see RCC_DeInit())

    -set SCB->VTOR to the sys mem start (0x1ffff000?) (this is to more or less emulate the reset behavior; on reset VTOR = 0, but when booting the bootloader the sys mem is aliased to adr 0, so the vectors are available.)

    -SP = *((int*) 0x1ffff000);

    -PC = *((int*) 0x1ffff004);

    some post I made on the thread you mention sort of explains the last items.

    [ This message was edited by: lanchon on 27-03-2008 16:26 ]

    john
    johnAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    Lanchon,

    I've been trying the following code :-

    NVIC_SETFAULTMASK();

    SCB->VTOR = 0x1ffff000;

    NVIC_GenerateSystemReset();

    But I can't get it to work.

    First mistake (by me) was not compiling it with STARTUP_FROM_RESET,

    so the software reset did fire, but then just sat in the wait state.

    Then I tried it with and without the NVIC_SETFAULTMASK() call, but

    both ways the software reset comes back into the FLASH code area,

    because my BOOT pins are 0,0 I guess ?

    So it looks like I have to manually invoke the flashloader code

    with the assembly - but that does work, so it's fine by me.

    Just looking into the 'reset' code needed before entering the

    flashloader, I can't find a decent description of NVIC_SETFAULTMASK().

    If its just a case of stopping all interrupts, could that be done

    with :-

    nvic[INT_ENA] = 0;

    as in the Tech. Ref. Man. example reset routines ?

    And then is it necessary to reset the peripherals ?

    Thanks,

    John.

    john
    johnAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    Thanks Lanchon - after I had this sorted, I was going to ask if there

    might be a simpler way, by setting the VTOC and then doing a reset.

    After all, thats what the vector table is there for !

    I'll give it a try tomorrow.

    John.

    lanchon
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    > But I don't understand what you mean about the memory aliasing ?

    when the stm32 is out of reset one of the mems (flash, sys mem, or ram) is aliased to address zero, depending on the BOOT0/1 pins. and VTOR is zero, so vectors work without initing VTOR. since you can't clear VTOR and change the aliased range by software (i think), the closest thing you can do is to set VTOR so that it points to the same content (ie, the start of the sys mem range).

    > I can do this with some inline assembly.

    looks right but I don't remember much about assembler.

    > I know I've not included all the resetting of the peripherals,

    > but that should be a simple matter of calling the DeInit() functions.

    you can reset almost all peripherals with one pair of calls, see RCC_APBxPeriphResetCmd(). (that function is used in DeInit() of almost all peripherals, take a look.) but DMA and NVIC have to be reset differently.

    also, you may need to set or clear things like PRIMASK and clear the processor registers to be completely compatible. you'd have to look for that info in the cortex manual.

    but come to think of it, there's a much better way of doing all this, simply:

    -call NVIC_SETFAULTMASK() to assure the vector table won't be used,

    -set VTOC to 0x1ffff000,

    -and cause a software reset.

    the reset will init all peripherals, registers and processor flags, and set SP and PC from the vector table. so it should be that simple. (only ''incompatibility'' is that the target code can know that this is not a power-on reset.)

    lanchon
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:27

    > friendly with STOne-32 - please can you let him know

    only contact with her or him is via this forum. in fact if I could contact him some other way I'd be bugging him like crazy over a FOC library that I desperately need for yesterday.

    but I can understand why ST chose not to allow invocation of the loader:

    -they want the freedom to change the loader (say, make it usb) or remove it completely (which i find most logical, we'll see what happens when the new parts come out on Q2).

    -using the loader like you are is not robust, it requires a working flash image. what if the update process is interrupted? still think the BOOT pins are not a good idea?

    the right way to do it is to lock 4K of the flash and use it to hold a constant and debugged bootloader. the trigger (equivalent of the BOOT pins) is what's ideal for your application and the result is robust:

    -independent of ST code

    -can recover from a failed update

    -can verify the integrity of the rest of the flash before invoking the main program and potentially raising havoc and destruction. (think of a multikilowatt motor controller with a corrupted firmware...)

    that is not to say that ST should do nothing! in fact IMHO ST should provide a ready-made bootloader application (not a fragile example) that is compatible with sys mem loading (actually it'd be almost the same code) but with these added functions:

    -customizable the trigger

    -checking and launching of app if no trigger

    -checking by crc or optionally by shared-secret ''signing'' (hash of firmware plus secret)

    -customizable check-failed handler