This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

RAM variables exchange between bootloader and application

Hello,

I wish to exchange variables (16 bytes) between bootloader and application in RAM.

What i have to modify please ?

Both LD file ?

Thank you

Parents
  • Hi,

    There are three options:

     

    1)  using SVC interface

    Either use the Buttonless DFU as an example of using SuperVisor Calls to exchange data between app and bootloader. This would require storage in the Bootloader Settings page which has automatic deletion available when you go back to the application

    This implementation is however too complex to write anything about in this answer and it may have some security considerations since you need to update the format of the bootloader settings page to do so.

     

    2) using a named section

    The alternative method is just allocating a page to use for data exchange and use a named section to refer to this from code.

    Edit linker script for main app and bootloader

    MEMORY

    {

      FLASH (rx) : ORIGIN = 0x78000, LENGTH = 0x6000

      RAM (rwx) :  ORIGIN = 0x200057b8, LENGTH = 0xa848

      uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4

      mbr_params_page (r) : ORIGIN = 0x0007E000, LENGTH = 0x1000

      bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000

      dfu_exchange_page(r) : ORIGIN = 0x00067000, LENGTH = 0x1000 // Add this and set to what page to use

      uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4

    }

     

    Add this in linker script sections

    SECTIONS

    {

      .dfu_exchange_page(NOLOAD) :

      {

        PROVIDE(__start_ dfu_exchange_page = .);

        KEEP(*(SORT(.dfu_exchange_page *)))

        PROVIDE(__end_dfu_exchange_page = .);

      } > dfu_exchange_page

    }

     

    Create a structure type

    typedef struct

    {

          uint32_t version;                    //  Ensure you aren’t handling illegal version

          uint32_t crc;                               // CRC of the rest of the structure to ensure to not act on invalid data

          uint32_t some_shared_data;

          uint32_t some_other_shared_data;

    } dfu_exchange_data_t;

     

    Create an instance of this type in the named section in both projects, set it to used to ensure that it is not optimized away

    dfu_exchange_data_t  m_dfu_exchange  

        __attribute__((section(".bootloader_settings_page")))

        __attribute__((used));

    Use Flash API to write/erase from app/bootloader (don’t know if you need to go both ways)

    Notes:

    • It is generally simplest to just use a structure type to read out in the bootloader, as this does not cost a lot of code space If you needed to add flash API and erase and so forth it just adds to the code-size (of which you may be limited)
    • We allocate a full page in memory since this is the smallest to erase
    • Section must be no-load on both app and bootloader to ensure it is not part of the hex-files to program the device
    • You must use flash API to clear out and set this structure
    • You can define your own structure type if you know what to exchange. Then you don't need to copy it out
    • Use a CRC-32 value to ensure that the exchanged data is correct
    • Use a version (uint32_t) in the structure in the beginning to ensure that you can update the format later on

     

    3) Using an absolute address – The simplest, brute force method

     

    As long as you have a structure type known to both bootloader and application it is also a possibility to skip the linker scripts altogether and just make an absolute address into a structure type

     

    typedef struct

    {

          uint32_t version;                    //  Ensure you aren’t handling illegal version

          uint32_t crc;                               // CRC of the rest of the structure to ensure to not act on invalid data

          uint32_t some_shared_data;

          uint32_t some_other_shared_data;

    } dfu_exchange_data_t;

     

    dfu_exchange_data_t   * p_dfu_exchange = (dfu_exchange_data_t*)0x67000;

     

    Note: This is the simplest one but it will not be protected against the code growing into this area. You don’t have any assurances what will be in this page so you my end up erasing your code if you aren’t keeping track of what is at the address you are casting (and potentially are erasing). Method 2 is much safer in that regard.

     

    Ketil

  • Thank you for your response.

    Your proposal works in flash right ? Do you have any equivalent in RAM please ? (i will be limited by the number of flash cycle during product life)

  • Hi,

    Yes, these suggestions are for Flash memory. You can use option 3 with a named section of an absolute address that work for RAM with some additional modification.

    • Limit the size of the RAM available to the app/bootloader to one page less than the total available space. You can do this by editing the linker script

    // Example code
    RAM (rwx) :  ORIGIN = 0x200057b8, LENGTH = 0xa848 // before
    RAM (rwx) :  ORIGIN = 0x200057b8, LENGTH = 0x9848 // after

    • You also need to add memory retention on the reserved RAM page that you are going to use (in both Bootloader and APP) according to Fig 1. Memory Layout RAM 7 Section 1.
    • Set the section to use RAM retention according to the information about the RAM[7].POWERSET register. See POWER_RAM_POWERSET_S1RETENTION_Msk.

    NRF_POWER->RAM[7].POWERSET = POWER_RAM_POWERSET_S1RETENTION_Msk;

    The reason for reserving the top-page is that the stack is placed on the highest address in the memory layout in GCC. If this is reserved (not used) in both app and bootloader there will be no risk of invalid data being written to that location. This will however make 1 page of RAM unavailable in the system.

    Note that you will not have absolute assurances on the content in cases of power failures. This might be an issue if your bootloader needs to do multiple iterations of updates before the full firmware update process is finished (e.g. updating SoftDevice+Bootloader and then app). This is the reason why the buttonless DFU uses flash to store peer-data.. If we lost power during the firmware upgrade (which will reboot multiple times) we are never put in a bricked scenario (where the peer data is unavailable). You need to consider this with regards to your FW update process.

    Ketil

Reply
  • Hi,

    Yes, these suggestions are for Flash memory. You can use option 3 with a named section of an absolute address that work for RAM with some additional modification.

    • Limit the size of the RAM available to the app/bootloader to one page less than the total available space. You can do this by editing the linker script

    // Example code
    RAM (rwx) :  ORIGIN = 0x200057b8, LENGTH = 0xa848 // before
    RAM (rwx) :  ORIGIN = 0x200057b8, LENGTH = 0x9848 // after

    • You also need to add memory retention on the reserved RAM page that you are going to use (in both Bootloader and APP) according to Fig 1. Memory Layout RAM 7 Section 1.
    • Set the section to use RAM retention according to the information about the RAM[7].POWERSET register. See POWER_RAM_POWERSET_S1RETENTION_Msk.

    NRF_POWER->RAM[7].POWERSET = POWER_RAM_POWERSET_S1RETENTION_Msk;

    The reason for reserving the top-page is that the stack is placed on the highest address in the memory layout in GCC. If this is reserved (not used) in both app and bootloader there will be no risk of invalid data being written to that location. This will however make 1 page of RAM unavailable in the system.

    Note that you will not have absolute assurances on the content in cases of power failures. This might be an issue if your bootloader needs to do multiple iterations of updates before the full firmware update process is finished (e.g. updating SoftDevice+Bootloader and then app). This is the reason why the buttonless DFU uses flash to store peer-data.. If we lost power during the firmware upgrade (which will reboot multiple times) we are never put in a bricked scenario (where the peer data is unavailable). You need to consider this with regards to your FW update process.

    Ketil

Children
Related