Skip to main content
stenasc
Associate III
June 20, 2016
Question

basic bootloader for M0

  • June 20, 2016
  • 43 replies
  • 5346 views
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
    This topic has been closed for replies.

    43 replies

    stenasc
    stenascAuthor
    Associate III
    July 19, 2016
    Posted on July 19, 2016 at 09:42

    Hi Clive,

    Will give that a go.

    Yes, the 0x08001000 stuff is based on the IAP flash loader. I was considering implementing it that way. However, I will use the RAM loader, as I've completed a lot of it already.

    Regards

    Bob 

    stenasc
    stenascAuthor
    Associate III
    August 8, 2016
    Posted on August 08, 2016 at 23:33

    The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6kP&d=%2Fa%2F0X0000000buY%2FdbwivSiFjtZB05IBw6czz60hV_Hoay4KgRR6_C6S0ig&asPdf=false
    Tesla DeLorean
    Guru
    August 8, 2016
    Posted on August 09, 2016 at 01:55

    One of your key problems is you take simple concepts and then add a layer of unnecessary complications. Understand and apply the basic concepts, and it will be much simpler.

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);     // Enable the SYSCFG peripheral clocks ** CLOCK not RESET **

    The remapping can map FLASH 0x08000000 at zero, or RAM 0x20000000 at zero. If you have vectors already at 0x08000000 they don't need to be copied. They need to be copied if they are at 0x08001000 etc, because you can't relocate the vector table with a VTOR register.

    Yes, both your projects need their own main(), they are separate projects, they don't share the same name-space, and your main() function is called by the __main code after it has initialized the statics for the C runtime environment.

     

    The value for the initial SP is stored in the first vector word. The way I'd handle this is to have the first instructions in the RAM based code to load SP for you.

      LDR R0,__initial_sp

      MOV SP, R0

    I can write an example in under an hour, framing in an app note would take longer.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    August 9, 2016
    Posted on August 09, 2016 at 06:01

    Ok, so you have to adapt the code to match what you are doing. You can't call this like it is a function anymore, as what you have built is a firmware image, with a vector table. You are going to transfer control to this loader, and it isn't going to come back to you.

    To copy and call the loader image you're going to want something like this

    void RamLoader(void)
    {
    static const uint8_t Loader[] = {
    0x40, 0x44, 0x00, 0x20, 0xd5, 0x00, 0x00, 0x20, 0x01, 0x04, 0x00, 0x20,
    0x25, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    // ........................... etc 
    };
    pFunction RunLoader;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // Enable the SYSCFG peripheral clocks 
    memcpy(0x20000000, Loader, sizeof(Loader)); // Copy loader image to SRAM
    SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM); // Remap SRAM at 0x00000000
    RunLoader = (pFunction)*((uint32_t *)0x20000004); // Pull Initial PC 
    RunLoader(); // Isn't going to return here
    } // sourcer32@gmail.com

    For startup.s

    ...
    ; Reset handler routine
    Reset_Handler PROC
    EXPORT Reset_Handler [WEAK]
    IMPORT __main
    IMPORT SystemInit
    LDR R0, =__initial_sp ; Ensure SP set as expected
    MOV SP, R0 
    LDR R0, =SystemInit ; Setup clocks and buses
    BLX R0
    LDR R0, =__main ; Initialize C runtime, and then go to main()
    BX R0
    ENDP ; Reset_Handler
    ...

    If you want to read up on the mechanics at work here, I'd strongly recommend Joseph Yiu's book on the Cortex-M0, and the ARM TRM for the core.
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    August 9, 2016
    Posted on August 09, 2016 at 15:37

    Hi Clive,

    Thanks very much. That worked a treat. Thats a big step for me and I will purchase Joseph's book. I should be able to make decent progress from here, but I likely will be back with more questions at some stage. A big thanks to you Clive for your patience and expertise.

    Bob

    stenasc
    stenascAuthor
    Associate III
    August 14, 2016
    Posted on August 14, 2016 at 20:48

    Hi Clive,

    A quick question to ask you about programming processor flash on the M0

    My bootloader is required to overwrite the old app beginning at 0x08000000. is this a restricted area, as any of the other bootloaders (e.g. IAP) I've seen always program flash away from this address at 0x08003000 for example.

    While looking through the IAP app code, I've also noticed that the flash address increments by 16. I would have expected it to increment by 4.

    *FlashAddress += 1 increments the address by 4. Any ideas?

    Regards

    Bob

    uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint16_t DataLength)

    {

      uint32_t i = 0;

      for (i = 0; (i < DataLength) && (*FlashAddress <= (USER_FLASH_END_ADDRESS-4)); i++)

      {

        /* the operation will be done by word */

        if (FLASH_ProgramWord(*FlashAddress, *(uint32_t*)(Data+i)) == FLASH_COMPLETE)

        {

         /* Check the written value */

          if (*(uint32_t*)*FlashAddress != *(uint32_t*)(Data+i))

          {

            /* Flash content doesn't match SRAM content */

            return(2);

          }

          /* Increment FLASH destination address */

          *FlashAddress += 4;

        }

        else

        {

          /* Error occurred while writing data in Flash memory */

          return (1);

        }

      }

      return (0);

    }

    Tesla DeLorean
    Guru
    August 14, 2016
    Posted on August 14, 2016 at 22:12

    You are passing a pointer to a 32-bit variable, you are then adding to the variable, not the pointer.

    ie

    uint32_t Addr = 0x08000000;

    FLASH_If_Write(&Addr, ... );

    You should be able to write the entire flash array, starting from 0x08000000. You should be able read/write protect specific sectors, but I haven't reviewed the F0 models.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    August 14, 2016
    Posted on August 15, 2016 at 00:23

    Hi Clive,

    That was the original IAP code from app note AN4065. I didn't modify it at all.

    However, now when I try to write a word into Address 0x08000000, I get a flash error...

    FLASH_ERROR_PROGRAM. I have successfully erased the flash so I'm not sure why I can't write to this location.

    I've traced it to the following where the flash programming error flag is set

          if((FLASH->SR & (uint32_t)(FLASH_SR_PGERR)) != (uint32_t)0x00)

          {

            FLASHstatus = FLASH_ERROR_PROGRAM;

          }

    I read at the following that it was caused by ROM being mapped over the page that was being flashed.

    http://www.keil.com/forum/61044/stm32f030-read-write-flash-throwing-hardfault/

    I know I am doing this as I'm trying to overwrite the original app, but is there any way around it.

    Bob

    Tesla DeLorean
    Guru
    August 14, 2016
    Posted on August 15, 2016 at 00:47

    Point is you are adding 4 to the variable via the pointer, you are not advancing the pointer by 16

    If you don't want to get into a situation where the FLASH doesn't contain any executable code, then have a sector or two committed to be a loader and don't erase them, ever.

    I would generally avoid stepping this kind of thing in the debugger. Instrument it, and check that the memory is blank, in-line

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    August 15, 2016
    Posted on August 15, 2016 at 10:12

    Hi Clive,

    As the bootloader runs from memory, I would have thought that there should be no requirement to maintain a separate area and that all flash could be overwritten. Am I wrong in this assumption?

    Bob