2016-06-20 02:21 PM
Hello Forum,
I've been reading on the forums about custom bootloaders stored in flash and I was wondering if there was another possibility (possibly because I want to avoid messing with stack pointers, reset vectors etc.) In my main app, I have a bootloader function, that copies the new app stored in external flash to processor flash. This bootloader function contains a number of inline functions to read from external flash and copy to processor flash. Checking the .map file, this bootloader function looks to be all located in one place. My thought process is to copy this bootloader function into RAM at say 0x20000100 and then jump to that address as shown below void CopyLoaderToRam(void) { // uint32_t *Ram = (uint32_t *)RAM_ADDR; char *Ram = (char *)RAM_ADDR;///////////// Byte Alignment test typedef void (*pFunction)(void); pFunction RunCode; ptr_bootloader_fn = &bootloader; // Find the address of the bootloader function. // memcpy(Ram, (void *)ptr_bootloader_fn, LOADER_FLASH_SIZE); // Copy bootloader into ram char *boot_byte; boot_byte = (char *)&bootloader; int i; for (i=0; i<= 4*LOADER_FLASH_SIZE; i++) { Ram[i] = *(boot_byte+i); } RunCode = (pFunction)Ram[1]; // ResetHandler (PC in second vector) RunCode(); } Well the first issue is it doesnt seem to work as I get a hard fault.My fears are that I am overwriting some necessary data in Ram or some alignment issue. I'm not sure. However, is it even technically feasible in the first place and if not, why? If it is a non-starter, I would rather know at this stage. Device is a STM32F051. Kind Regards Bob2016-06-28 04:06 PM
It's not going to be *that* different, I'd have to code something specific as that's not how I solve this kind of problem, and I'm not using M0's
Use a debugger to understand the fault. Make sure the base address of the function into the memcpy() is EVEN, as is the destination address. Make sure it copies the entire function and any literals it references. Make sure it doesn't have any external references, relative address references only work when they all remain in scope.2016-06-28 05:04 PM
int TestFunc(void)
{
return(123);
}
#define FUNC_SIZE 64
typedef int (*pFunction)(void);
int RamFunc(void)
{
uint8_t Buffer[FUNC_SIZE];
pFunction RunFunc;
memcpy(Buffer, (void *)((uint32_t)&TestFunc & ~1), FUNC_SIZE); // Copy code
RunFunc = (pFunction)&Buffer[1]; // +1 for Thumb code
return(RunFunc()); // sourcer32@gmail.com
}
2016-06-29 12:16 PM
Clive,
Thank you. That works. However if I add a puts statement into the TestFunc, then its back to the HardFault. I thought I could get away with.. int TestFunc(void) { char messg[21] = ''Hello from Bootloader''; puts(messg); return(789); } but alas no luck. It looks like I'm not including all the function literals and references. Getting there though. Much appreciate your help. Bob .2016-06-29 12:44 PM
As I said, I'd approach this differently..
In terms of understand what's going on in your situation I'd recommend reviewing a .LST file or a disassembly of the code in question. Keil's FROMELF has a disassembly option2016-06-30 01:25 AM
Thanks Clive,
Will give that a go. Many thanks for your help.Bob2016-07-01 01:55 AM
Hi Clive,
It looks as if you're correct. I do need different strategy. The bootloader calls some nested functions that interact with flash. I was able to place these functions in the .data section of memory. However, these in turn call some other nested function,...too many so that it still doesnt work. Is it possible to place one object file (bootloader.o) in the .data section so that the whole thing resides in Ram? If so, do you thing this is a reasonable option for a bootloader strategy or should I use the general method of moving the custom bootloader to a separate location in flash and manipulate the vector table as seems to be the preferred solution out there? I'd prefer not to waste any more time trying methods that take a lot of time without much success.Bob2016-07-01 02:45 AM
What I would do is to compile the minimal bootloader as a standalone application. That gives you ''everything you need'' in the bootloader. Also you can for example link it to be run from the 0x20000100 address where you're going to put it.
Next you convert that to raw binary, and that in turn you convert intoconst char bootloader[] = {0x1a, 0x.... };
which you put into a ''bootloader.c'' file and you link with your main application.
2016-07-01 03:34 AM
As Roger indicates, you could make a small applet as a stand-alone project, and stuff that as the payload for the copy.
Trying to have one C file, and keep the name-space/sections separate and the library dependencies in check, is a bit of a challenge. The M0 makes it worse due to it's use of functions to very basic tasks.A technique I've used successfully to work with a single source file/project is to code the flashing in assembler, where everything is address agnostic, and all the dependencies are kept internal. This code can then be copied into RAM and run from any valid address. This comes from a clear understanding of the Assembler and Linker, and a register level perspective to the CPU and FLASH Controller.2016-07-01 05:25 AM
Hi Roger,
I can certainly give that a go. My main app will call these bootloader functions. The linker should take care of this though ???RegardsBob2016-07-01 05:28 AM
Hi Clive,
Yes..another way to go. I will try Rogers method first as there is less necessity for me to write assembler. Depending on how, I get on, I may have to revert to your suggestion. A bit of work for the weekend. Greatly appreciate all the suggestions and helpBob