cancel
Showing results for 
Search instead for 
Did you mean: 

basic bootloader for M0

stenasc
Senior
Posted on June 20, 2016 at 23:21

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

Bob
43 REPLIES 43
Posted on June 20, 2016 at 23:34

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
stenasc
Senior
Posted on June 21, 2016 at 00:22

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.

Bob

Posted on June 21, 2016 at 01:21

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();
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
stenasc
Senior
Posted on June 22, 2016 at 01:54

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)

Posted on June 22, 2016 at 02:36

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
stenasc
Senior
Posted on June 26, 2016 at 22:57

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);

}

Posted on June 26, 2016 at 23:16

uint32_t *Ram = (uint32_t *)RAM_ADDR;// NO, NO, Not uint32_t, uint8_t

&Ram[1] for the 32-bit word case is +4 bytes, &Ram[1] for the 8-bit case is +1 bytes, you want the latter.

You'd want to ensure &bootloader is the EVEN address, I'd build a list of hex bytes rather than copy a subroutine in-situ

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 26, 2016 at 23:36

#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
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
stenasc
Senior
Posted on June 29, 2016 at 00:39

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