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-20 02:34 PM
It is faulting because in this context you are loading a byte and jumping to whatever that is.
You'd really want the vector table at the base of RAM, as you can remap that, whereas you can't redefine the address of the vector table as you could with the M3/M4 designs. Assume therefore that SCB->VTOR = ZERO, always.2016-06-20 03:22 PM
Hi Clive,
Appreciate you getting back. How can I execute the code stored at that location in Ram, which is really what is required? In this context, do I need to move the vector table to the base of RAM? My aim is for the bootloader to overwrite the existing app code with the new firmware. Bob2016-06-20 04:21 PM
For a self contained function...
void CopyLoaderToRam(void)
{
char *Ram = (char *)RAM_ADDR;// You want this word aligned
typedef void (*pFunction)(void);
pFunction RunCode;
memcpy(Ram, (void *)&bootloader, LOADER_FLASH_SIZE); // Copy bootloader into ram
RunCode = (pFunction)&Ram[1]; // *ADDRESS* of the second byte, ie ODD to indicate 16-bit Thumb
RunCode();
}
2016-06-21 04:54 PM
Thanks for that Clive. However tried it and it hard faulted. One thing that did confuse me is whether I should copy from address
0x0800b600 to ram of from 0x0800b601. Printing the pointer address of bootloader function gives me the latter and it is from 0x0800b601 that I copy from. However, the map file below gives two values. Which is correct? Regards Bob Base Addr Size Type Attr Idx E Section Name Object 0x0800b600 0x000000d0 Code RO 1297 i.bootloader loader.o Symbol Name Value Ov Type Size Object(Section) bootloader 0x0800b601 Thumb Code 204 loader.o(i.bootloader)2016-06-21 05:36 PM
The memory is going to be at 0x0800B600, the PC sets to 0x0800B601 and the core flags that as being Thumb code pulling the instruction word from 0x0800B600
You should be able to run the function in its normal location. The function should not call external dependencies. These in the M0 case might include basic MATH functions, like division. Review the code. Start with a function that just returns a value.2016-06-26 01:57 PM
Hi Clive,
Apologies, only getting back to this now. Still no joy, I tried as you said to just return a value, but still get a hard fault. int8_t bootloader() { return 8; } void CopyLoaderToRam(void) { uint32_t *Ram = (uint32_t *)RAM_ADDR;// You want this word aligned typedef int8_t (*pFunction)(void); pFunction RunCode; memcpy(Ram, (void *)&bootloader, LOADER_FLASH_SIZE); // Copy bootloader into ram RunCode = (pFunction)&Ram[1]; // *ADDRESS* of the second byte, ie ODD to indicate 16-bit Thumb int8_t test_boot; test_boot = RunCode(); printf(''Bootloader returns %d'', test_boot); } I also tried other snippets of code that I found while browsing the forum (below) but it does not work. I can see the code is copied to the location in RAM ok, so I'm really stuck on this one. There must be something quite fundamental that I've missed. Appreciate any help. Bob uint32_t *Ram = (uint32_t *)RAM_ADDR;// You want this word aligned typedef int8_t (*pFunction)(void); uint32_t JumpAddress = *(__IO uint32_t*) (RAM_ADDR + 4); pFunction Jump_To_Boot = (pFunction)JumpAddress; memcpy(Ram, (void *)&bootloader, LOADER_FLASH_SIZE); // Copy bootloader into ram __set_MSP(*(__IO uint32_t*)RAM_ADDR); int8_t test_boot; test_boot = Jump_To_Boot(); printf(''Bootloader returns %d'', test_boot); }2016-06-26 02:16 PM
2016-06-26 02:36 PM
#define SRAM_ADDR 0x20000F00
typedef int (*pFunction)(void);
int RamCode(void)
{
static const uint16_t Code[] = { 0x4800, 0x4770, 0x007B, 0x0000 }; // payload
uint8_t *Buffer = (uint8_t *)SRAM_ADDR;
pFunction RunCode;
memcpy(Buffer, Code, sizeof(Code)); // Copy code
RunCode = (pFunction)&Buffer[1]; // +1 for Thumb code
return(RunCode()); // sourcer32@gmail.com
}
2016-06-28 03:39 PM
Hi Clive,
Thank you. Yes that works, but it is slightly different than copying a function into Ram and executing it. Even though the function only returns a value, I still get a hardfault. Really stuck here. Have you an example of actually copying a simple function into Ram? Bob Bob