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

nRF52840 SDK16 S140 - How to put in RAM retention

Hi everyone,

I am working on a project where I have to enter the system into System OFF mode and RAM retention. What I actually want is to retain the value of some variables.

How could I do that in terms of software? Are there any specific functions I have to use? I also read that I have to make a no-init/zero_init section in order to ensure that the firmware does not clear the values at boot up but I don't even know what is this and how to implement it.

Could someone guide me? Or is there a similar example I could follow?

Thanks in advance

Nick

Parents Reply
  • Hi haakonsh,

    Ok, what I have understood so far is that in order to keep retention in RAM you have to write on RAM[n].POWERSET register and if you are using a softdevice you have to use the sd_power_ram_power_set() API. right?

    By default the POWER field (bits A-P) is set while the RETENTION field (bits Q-f) of RAM[n].POWERSET register is unset. So in my case I have to configure only the RETENTION field (as I want RAM ON on system ON mode). What I have understand is that the RAM has 9 sections and you can select which of the sections to retain during system OFF..

    How can I find the memory section (n=0..8) that my variable is located?

    How do I know what bit positions (Q-f) I have to set?

    Moreover, RAM retention is not enough when you enter the system OFF mode, because the system restarts after waking up and the variables are initialized to zero. So you have to add the variables into the non_init section in order to avoid initialization during restart. This is done by using the zero_init attribute. However  I am a little confused regarding the syntax.. Taking for example the "state" variable, which of the following expression is correct?

    uint8_t state __attribute__((section(".zero_init"),zero_init));
    uint8_t state __attribute__((section(".zero_init")));
    uint8_t state __attribute__((zero_init));

    Also, should I include anything into the flash_placement.xml file?

    In flash_placement.xml there is the .non_init section. This is the same as the .zero_init?

    Maybe, I could use the expression uint8_t state __attribute__((section(".non_init"),zero_init))?

    Sorry for the big post.. I an new to this and I try to learn..

    Thanks in advance 

    Nick

Children
  • Nikosant03 said:
    Ok, what I have understood so far is that in order to keep retention in RAM you have to write on RAM[n].POWERSET register and if you are using a softdevice you have to use the sd_power_ram_power_set() API. right?

     Yes, that's correct. 

    Nikosant03 said:

    By default the POWER field (bits A-P) is set while the RETENTION field (bits Q-f) of RAM[n].POWERSET register is unset. So in my case I have to configure only the RETENTION field (as I want RAM ON on system ON mode). What I have understand is that the RAM has 9 sections and you can select which of the sections to retain during system OFF..

    How can I find the memory section (n=0..8) that my variable is located?

    How do I know what bit positions (Q-f) I have to set?

    See Memory: RAM0-9 and the sections within each RAM block. The sections correspond to the Q-F bit positions. (S[i]RETENTION (i=0..15)). F.ex. if the variable is at address 0x2002 8420 that will be RAM8, section 3. 
     

    #Define RAM_SECTION_3 (1 << 19)
    #Define RAM_INSTANCE 8
    #Define RAM_ON_SYSTEMON 0xFFFF //All sections ON in SystemON
    
    err_code = sd_power_ram_power_set(RAM_INSTANCE, RAM_ON_SYSTEMON | RAM_SECTION_3);
    
    //There's also bitmasks and bitfield definitions in nrf_power.h:
    err_code = sd_power_ram_power_set(RAM_INSTANCE, NRF_POWER->RAM[RAM_INSTANCE].POWER | NRF_POWER_RAMPOWER_S3RETENTION_MASK);
    



     

    Nikosant03 said:
    Taking for example the "state" variable, which of the following expression is correct?

    From https://developer.arm.com/documentation/dui0472/m/compiler-specific-features/--attribute----zero-init---variable-attribute:

    uint8_t state __attribute__((zero_init)); will place the variable state in the .bss section.

    uint8_t state __attribute__((section("zero_init"), zero_init)); will place the variable state in the user-defined .zero_init section

    If you declare a user-defined section then you will most likely need to add it to the flash placement file in order to let the linker know that such a section exists. 

  • See Memory: RAM0-9 and the sections within each RAM block. The sections correspond to the Q-F bit positions. (S[i]RETENTION (i=0..15)). F.ex. if the variable is at address 0x2002 8420 that will be RAM8, section 3. 

    Perfect explanation!! Thanks a lot!! The address of a global variable during program execution and when I rebuild the application (say that I did some code changes) it remains constant?

    Should I declare the variable with a special type in order to retain its address?

    Nick

  • Nikosant03 said:
    The address of a global variable during program execution and when I rebuild the application (say that I did some code changes) it remains constant?

    I don't think that's a safe assumption. I assume the linker can choose freely wherein the given Section a variable will be placed. Probably it depends on when the variable is processed by the build system, ie if it is the 4th variable to be placed in a section it will probably be placed on top of the previous three, so if you change the number of (or size of) the variables the addresses changes. 

    Nikosant03 said:
    Should I declare the variable with a special type in order to retain its address?

     If you declare a user-defined section that only contains your special variable, and the address of that section is constant, then I think it's safe to assume the address of the variable is constant across builds. 
    see https://www.google.com/search?newwindow=1&sxsrf=ALeKk03Rot_MBgmYBmeqylePyUzOOpxPoQ:1597063079918&q=arm+gcc+section+placement&spell=1&sa=X&ved=2ahUKEwjCvr_M05DrAhVHxIsKHaPUDDEQBSgAegQIDBAo&biw=1080&bih=1777 

  • See Memory: RAM0-9 and the sections within each RAM block. The sections correspond to the Q-F bit positions. (S[i]RETENTION (i=0..15)). F.ex. if the variable is at address 0x2002 8420 that will be RAM8, section 3. 

    You mean RAM0-8? I found that my variable is at address 0x200041E0, that means RAM2, section 0 isn't it?

    Is this correct?

    #define RAM_AHB_slave 2
    
    ret_code_t err_code;
    err_code = sd_power_ram_power_set(RAM_AHB_slave, POWER_RAM_POWER_S2RETENTION_On << POWER_RAM_POWER_S2RETENTION_Pos);
    APP_ERROR_CHECK(err_code);

Related