implementing noinit section on zephyr

NCS 2.7.0

nrf52840

I'm currently porting software that was originally developed for nrf52832 on NRF5 SDK to run on Zephyr. I am currently on a deadline to delivery a prototype of the manufacturing test firmware to the factory for first PCB validation.  This release will be single image and then I will begin work to implement the bootloader which of course will mean multi-image build.

One of the tests utilized a noinit region to confirm that power to the nrf processor was cut between phases of the test.  The implementation of noinit data was fairly straight forward on nrf5 sdk.  A section was defined in the flash_placement.xml.  This section also had to be coordinated with the bootloader so it wasn't overwritten.

I'm trying to understand the process with zephyr. I will make some statements of my understanding from reading portions of the documentation.  Please correct anything I get wrong.  I also have some questions inline which I will number and bold.

It seems like it may vary depending on whether it is single image or multi-image.  For multi-image it appears the partition manager comes into play.  I'm unclear on how it works for single image. 

A note I found on the partition manager page ( Partition Manager )  

When you build a multi-image application using the Partition Manager, the devicetree source flash partitions are ignored.

Would imply that single image builds take partition definitions from devicetree.  

Alternatively, it seems I can use partition manage with a single image by including the Kconfig variable CONFIG_PM_SINGLE_IMAGE in my prj.conf.  

It also appears with partition manager there is a mechanism for a subsystem to provide a supplemental configuration, however I only find subsys/partition_manager within the nrf module.  

1) Out of general curiosity, Is partition_manager a proprietary element of NCS that is not included with Zephyr itself?

2) Can I add a subsystem pm.yml from my out-of-tree customer/application repository?  

3) Is partition_manager the recommended way to add a noinit section?  Are there any samples that would demonstrate how it should be implemented?

4) Since my project will ultimately be multi-image with a bootloader, is my best choice to develop with partition_manager?  

5) Any change with partition_manager in NCS 2.8.0 or planned for the future?

a*

Parents
  • Hi Anthony, 

    Due to unexpected reason I'm out of office in the next 2 days. I won't be able to answer all your questions but I will try to answer your question about noinit. Let us know if the ticket is urgent. I can try to find another engineer to look into it. 

    1. Correct

    2. Please explain what exactly you want to do . Also please explain how you plan to run the nRF5 SDK image on Zephyr. If your image is a child image/remote image of a zephyr application then pm.yml can be used. 

    3. I assume you are talking about noinit for FLASH, not noinit for RAM, correct ? Please elaborate more on this procedure: One of the tests utilized a noinit region to confirm that power to the nrf processor was cut between phases of the test. 
    If you simply want to define a partition in Flash that partition manager doesn't allocate other child image into,  I believe pm-static.yml is what you need. The easiest way of making the pm-static.yml file is to build your application normaly (without the noinit area defined) then you can copy the content of the partitions.yml file and make your own pm-static.yml file in your project folder. You then can adjust the partitions (if needed) and add your own "noinit" partition. For example here is an "unused" page define after mcuboot_secondary: 

    unused_page:
      address: 0xf7000
      placement:
        after:
        - mcuboot_secondary
      size: 0x1000

    If you are asking about noinit for RAM, I don't think partition manager has anything to do here. It only deal with flash.

    For RAM: 

    It's the RAM retention region in device tree need to be defined (check the chip spec for RAM retention region).
    You can take a look at this sample : https://github.com/nrfconnect/sdk-zephyr/tree/v3.6.99-ncs2/tests/boot/mcuboot_data_sharing

    The noinit ram is configured in nrf52840dk_nrf52840.overlay : 

    / {
    	sram@2003F000 {
    		compatible = "zephyr,memory-region", "mmio-sram";
    		reg = <0x2003F000 DT_SIZE_K(1)>;
    		zephyr,memory-region = "RetainedMem";
    		status = "okay";
    
    		retainedmem {
    			compatible = "zephyr,retained-ram";
    			status = "okay";
    			#address-cells = <1>;
    			#size-cells = <1>;
    
    			boot_info0: boot_info@0 {
    				compatible = "zephyr,retention";
    				status = "okay";
    				reg = <0x0 0x100>;
    			};
    		};
    	};
    
    	chosen {
    		zephyr,bootloader-info = &boot_info0;
    	};
    };
    The data at 0x2003F000 is accessed in https://github.com/nrfconnect/sdk-mcuboot/blob/main/boot/zephyr/shared_data.c  
    See: 
    static const struct device *bootloader_info_dev =
    DEVICE_DT_GET(DT_CHOSEN(zephyr_bootloader_info));
    The rest of the questions we can discuss after we have more info from you. 
  • Hi Hung,

    I'm looking at nrf52840 product specification to understand better the retained RAM region.   As far as I can tell, all RAM regions can be retained.  A retained ram region has the RAM[n].POWER.RETAINED flag set.  Perhaps there are some regions where this flag is automatically set?   

    The effect of this flag is to maintain power to the RAM bank in the SYSTEM OFF state.  It doesn't tell us anything about whether the system initialization like the .bss initialization will overwrite it. 

    I reviewed the retained ram driver API.  It adds a read/write/clear system call API to access the retained memory, which adds significant overhead, from the system call wrappers.

    I'd like to know how I can create a named region that is not-initialized within zephyr.  In the previous sdk we could simply add a new named region to the flash_placement.xml and add an attribute to a variable to tell the compiler/linker where to put it.  Then I could assign  a value to the variable (LHS) and the noinit region would be updated.  Similarly I could use the variable on the right hand side(RHS) of an assignment to read it.

  • Hi Anthony, 
    For a simple non-init could you take a look at this ticket ? non init section 

    (it refers back to the code of the retained driver actually). 

    But I think there is a concern about MCUBoot may overwrite this area if the non init is not configured in MCUBoot as well. 

    Regarding the retained library, if you take a look at the retention library : https://docs.zephyrproject.org/latest/services/retention/index.html

    You can find that it utilize the hardware RAM retention as you mentioned and the non-init configuration of the compiler to ensure the validity of the data. My understanding is that when you use this in device tree as shown in the documentation , the RAM retention hardware will be automatically configured accordingly and non-init will be used when compiling. 
    This solution has been used for sharing data between the application and the MCUBoot bootloader between reboot (and not power reset)


  • The retained memory library approach seems dramatically overkill.  It requires a virtualized driver API, with extra kernel level code, and would require me to rewrite the existing code to use that API.  

    Fundamentally the retained_memory driver (zephyr,retained-memory) itself isn't doing anything with the linker or memory its just creating instance of a driver to access that parent memory region.   The parent memory region (zephyr,memory-region) creates the named linker section, however it doesn't actually mark it as noinit.

    It looks to me that that the way the boot_mode is preserved between app and mcu_boot is actually caused by removing that segment from the sram0..

    essentially this code

    /* Reduce SRAM0 usage by 1 byte to account for non-init area */
    &sram0 {
            reg = <0x20000000 0x3FFFF>;
    };


    The macro __noinit actually puts code into sram0 in a uniquely named section but it doesn't appear to be protected from mcuboot. Also many areas such as the thread stacks are placed in the noinit section simply to avoid initializing them not because retention is desired.  

    I think my best option is to adjust the sram boundaries and create a new zephyr,memory region there.  

    I will create a macro similar to the one used by SEGGER_RTT_PUT_SECTOIN to place my variables into the defined region.

  • There are the changes I made to my boards devicetree:

    / {
    	sram@2003F700 {
    		compatible = "zephyr,memory-region";
    		reg = <0x2003F700 0x400>;
    		zephyr,memory-region = "app_noinit";
    		status = "okay";
    	};
    	sram@2003FB00 {
    		compatible = "zephyr,memory-region";
    		reg = <0x2003FB00 0x500>;
    		zephyr,memory-region = "rtt";
    		status = "okay";
    	};
    };
    /* Reduce SRAM0 to isolate the defined memory regions */
    &sram0 {
            reg = <0x20000000 0x3F700>;
    };

    After building the application with default system build (single image) I get:

    [300/303] Linking C executable zephyr\zephyr.elf
    Memory region         Used Size  Region Size  %age Used
               FLASH:      521340 B         1 MB     49.72%
                 RAM:      125056 B       256 KB     47.71%
          app_noinit:          26 B         1 KB      2.54%
                 rtt:        1208 B       1280 B     94.38%
            IDT_LIST:          0 GB        32 KB      0.00%
    Generating files from D:/Flipperz/flipper_workspace/app.git/mfg_app/build_thomas_c/zephyr/zephyr.elf for board: thomas_c
    [303/303] Generating zephyr/merged.hex

    Will I need to do anything when I switch to static partition file pm_static.yml for this configuration?

Reply
  • There are the changes I made to my boards devicetree:

    / {
    	sram@2003F700 {
    		compatible = "zephyr,memory-region";
    		reg = <0x2003F700 0x400>;
    		zephyr,memory-region = "app_noinit";
    		status = "okay";
    	};
    	sram@2003FB00 {
    		compatible = "zephyr,memory-region";
    		reg = <0x2003FB00 0x500>;
    		zephyr,memory-region = "rtt";
    		status = "okay";
    	};
    };
    /* Reduce SRAM0 to isolate the defined memory regions */
    &sram0 {
            reg = <0x20000000 0x3F700>;
    };

    After building the application with default system build (single image) I get:

    [300/303] Linking C executable zephyr\zephyr.elf
    Memory region         Used Size  Region Size  %age Used
               FLASH:      521340 B         1 MB     49.72%
                 RAM:      125056 B       256 KB     47.71%
          app_noinit:          26 B         1 KB      2.54%
                 rtt:        1208 B       1280 B     94.38%
            IDT_LIST:          0 GB        32 KB      0.00%
    Generating files from D:/Flipperz/flipper_workspace/app.git/mfg_app/build_thomas_c/zephyr/zephyr.elf for board: thomas_c
    [303/303] Generating zephyr/merged.hex

    Will I need to do anything when I switch to static partition file pm_static.yml for this configuration?

Children
No Data
Related