cancel
Showing results for 
Search instead for 
Did you mean: 

calling boot/flash loader from user code

john
Associate II
Posted on March 28, 2008 at 11:28

calling boot/flash loader from user code

12 REPLIES 12
john
Associate II
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.

giles
Associate II
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.

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

(this was discussed earlier.)

john
Associate II
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 II
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
Associate II
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 II
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.)

john
Associate II
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.

john
Associate II
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.