Crash after powerdown if ram is not powered

sdk: 2.5.1

cpu: nrf5340

I have a bootloader which have a big ram block for upgrade purpose (around 250kb) in bss section (I will move it in noinit, but it is not the point here).

I  have an app, that poweroff unused ram with VMC register.

Sometimes, the app will enter in poweroff (using REGULATORS register), and will be awakened by vbus or nfc.

When the cpu is awakened, the bss section and idle stacks are in a part of the ram that is powered off, and this is a unrecoverable crash.

I found a solution with powering ram at early startup, but I would like to check with you if it is correct.

The solution may also be about powering up ram before entering poweroff, but I would like may bootloader to be robust.

I wrapped the method z_arm_reset (with linker argument --wrap), and wrote this method:

extern void __real_z_arm_reset();

__attribute__((naked))
void __wrap_z_arm_reset(void)
{
  NRF_VMC->RAM[0].POWERSET = 0xFFFF;
  NRF_VMC->RAM[1].POWERSET = 0xFFFF;
  NRF_VMC->RAM[2].POWERSET = 0xFFFF;
  NRF_VMC->RAM[3].POWERSET = 0xFFFF;
  NRF_VMC->RAM[4].POWERSET = 0xFFFF;
  NRF_VMC->RAM[5].POWERSET = 0xFFFF;
  NRF_VMC->RAM[6].POWERSET = 0xFFFF;
  NRF_VMC->RAM[7].POWERSET = 0xFFFF;
   __asm__ volatile ("b __real_z_arm_reset");
}

I checked the generated code, and no stack seem to be used:

00002a28 <__wrap_z_arm_reset>:
    2a28:       f64f 72ff       movw    r2, #65535      ; 0xffff
    2a2c:       4b09            ldr     r3, [pc, #36]   ; (2a54 <__wrap_z_arm_reset+0x2c>)
    2a2e:       f8c3 2604       str.w   r2, [r3, #1540] ; 0x604
    2a32:       f8c3 2614       str.w   r2, [r3, #1556] ; 0x614
    2a36:       f8c3 2624       str.w   r2, [r3, #1572] ; 0x624
    2a3a:       f8c3 2634       str.w   r2, [r3, #1588] ; 0x634
    2a3e:       f8c3 2644       str.w   r2, [r3, #1604] ; 0x644
    2a42:       f8c3 2654       str.w   r2, [r3, #1620] ; 0x654
    2a46:       f8c3 2664       str.w   r2, [r3, #1636] ; 0x664
    2a4a:       f8c3 2674       str.w   r2, [r3, #1652] ; 0x674
    2a4e:       f00a b9e7       b.w     ce20 <z_arm_reset>
    2a52:       bf00            nop
    2a54:       50081000        .word   0x50081000

Waiting for your answer.

Regards,

  • (updated)

    I am waiting for the team's help to confirm the solution. I will be back when I get enough information. 

    ----

    Hi, 

    I am working on your case and will update it when the answer is ready.

    Regards,
    Amanda H.  

  • Hi,

    Not yet. 

    We are currently understaffed due to the summer vacation period, so delayed replies must be expected. I am sorry about any inconvenience this might cause.

    -Amanda H.

  • Hi, the following example code will configure the RAM blocks to behave as you describe:

    I created the following zephyr test application (modified main.c and prj.conf of the hello_world sample)

    #include <stdio.h>
    
    #include <hal/nrf_gpio.h>
    #include <zephyr/sys/poweroff.h>
    #include <zephyr/kernel.h>
    
    /*
     * NOTE when running this sample, don't debug it as it can't enter real
     * power off while a debugger is attached. It will just be spinning forever.
     *
     * NOTE also that this is the default RAM behavior, so if you don't
     * wish to retain any RAM blocks or sections of said blocks, you don't
     * need to modify NRF_VMC
     *
     * Last note, this sample requires the following additional Kconfig options:
     *     CONFIG_POWEROFF=y
     *     CONFIG_GPIO=y
     */
    
    int main(void)
    {
    	printf("Hello World! %s\n", CONFIG_BOARD_TARGET);
    
    	/* Before doing anything which disables the debug interface, sleep
    	 * to provide enough time to start a debug session / erase the device.
    	 */
    	k_msleep(10000);
    
    	/* Prepare for power off
    	 *
    	 * The nRF5340 has two RAM blocks, we want the
    	 * entire RAM block to be enabled when system powers on after reset, this
    	 * is done by setting the section power bits (16 sections mapped to the lowest
    	 * 16 bits of the NRF_VMC->RAM registers).
    	 */
    	NRF_VMC->RAM[0].POWERSET = UINT16_MAX;
    	NRF_VMC->RAM[1].POWERSET = UINT16_MAX;
    
    	/* We want all RAM blocks to be powered down in power off mode, to do this, we
    	 * clear the section retain bits (16 sections mapped to the upper 16 bits of
    	 * the NRF_VMC->RAM registers).
    	 */
    	NRF_VMC->RAM[0].POWERCLR = UINT16_MAX << 16;
    	NRF_VMC->RAM[1].POWERCLR = UINT16_MAX << 16;
    
    	/* Enable some wake up source. This is Button1 on the nRF5340DK connected to
    	 * pin 0.23
    	 */
    	nrf_gpio_cfg(
    		23,
    		NRF_GPIO_PIN_DIR_INPUT,
    		NRF_GPIO_PIN_INPUT_CONNECT,
    		NRF_GPIO_PIN_PULLUP,
    		NRF_GPIO_PIN_S0S1,
    		NRF_GPIO_PIN_SENSE_LOW
    	);
    
    	/* Print last message, and wait for it to print to console before power off */
    	printf("Good night!\n");
    	k_msleep(100);
    
    	/* When entering power off, the RAM blocks 0 and 1 will be powered down.
    	 * When the system wakes up again, the RAM blocks come back automatically.
    	 * After power off, press the button
    	 */
    	sys_poweroff();
    	return 0;
    }

    Hopefully we can compare solutions to figure out why it is failing for you :)

  • I think I did not explained the problem correctly.

    At wakeup, the ram of the main stack inside the bootloader was turned off by the app because the main stack of the bootloader is in a part of ram unused for the app. When the reset function of the bootloader is called at wakeup, there is an exception immediately as the stack is used. The main method will never been executed. The purpose of my code was to turn ram on inside the bootloader before any use of ram.

Related