System OFF mode for system power management for nRF54L15

I would like to integrate System OFF mode of operation into idle system hooks in Zephyr (i.e. when the CPU is idle, it goes into OFF power state automatically). As it currently stands, I have a simple multithreaded application and have following power optimizations configured:
```

CONFIG_PM=y
CONFIG_POWEROFF=y
CONFIG_PM_DEVICE=y
```
I measure the consumption to be ~4uA with this configuration, so I'm assuming the MCU is only every getting to one of System ON IDLE states. I can get it to the desired consumption by calling `sys_poweroff` explicitly, but I would like this to be called automatically from the Idle thread(and ideally using the GRTC to wake the system up for appropriate OS scheduled events) so I don't need to manage this within my application code.
I can also see that the CONFIG_PM option isn't actually taking in the compiled image; when I step debug through the code, it's clear the code section is compiled out:
```
#ifdef CONFIG_PM
_kernel.idle = z_get_next_timeout_expiry();

/*
* Call the suspend hook function of the soc interface
* to allow entry into a low power state. The function
* returns false if low power state was not entered, in
* which case, kernel does normal idle processing.
*
* This function is entered with interrupts disabled.
* If a low power state was entered, then the hook
* function should enable interrupts before exiting.
* This is because the kernel does not do its own idle
* processing in those cases i.e. skips k_cpu_idle().
* The kernel's idle processing re-enables interrupts
* which is essential for the kernel's scheduling
* logic.
*/
if (k_is_pre_kernel() || !pm_system_suspend(_kernel.idle)) {
k_cpu_idle();
}
#else
k_cpu_idle();
#endif /* CONFIG_PM */
```
Any guidance would be appreciated!
Parents
  • Hi

    A colleague of mine made a small test application to test the GRTC SYSCOUNTER in deep sleep mode that you should be able to use as reference for GRTC during system OFF mode implementation.

    Configs required for the below snippet:
    CONFIG_REBOOT=y
    CONFIG_POWEROFF=y

    #include <stdio.h>
    #include <nrf54l15_global.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/reboot.h>
    #include <zephyr/sys/poweroff.h>
    #include <zephyr/drivers/timer/nrf_grtc_timer.h>
    #include <zephyr/drivers/gpio.h>
    #define DEEP_SLEEP_TIME_S 2
    
    static const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);
    
    int main(void)
    {
     int err;
    
     printf("Hello World! %s\n", CONFIG_BOARD_TARGET);
    
     err = gpio_pin_configure_dt(&sw0, GPIO_INPUT);
     printf("gpio_pin_configure_dt %d\n", err);
     if (err) return err;
    
     err = gpio_pin_interrupt_configure_dt(&sw0, GPIO_INT_LEVEL_ACTIVE);
     printf("gpio_pin_interrupt_configure_dt %d\n", err);
     if (err) return err;
    
     while (1) {
      static uint8_t i = 0;
      i++;
      printf("%02d GRTC %08x%08x\n", i, NRF_GRTC->SYSCOUNTER[0].SYSCOUNTERH, NRF_GRTC->SYSCOUNTER[0].SYSCOUNTERL);
      k_msleep(1000);
      if (i > 3) {
       sys_reboot(SYS_REBOOT_WARM);
       sys_reboot(SYS_REBOOT_COLD);
       err = z_nrf_grtc_wakeup_prepare(DEEP_SLEEP_TIME_S * USEC_PER_SEC);
       // printf("z_nrf_grtc_wakeup_prepare %d\n", err);
       if (!err) {
        sys_poweroff();
       }
      }
     }
    
     return 0;
    }
     

    As for making the idle thread putting the device into system OFF mode I think you need to implement that logic in your idle thread yourself. You can probably use the system OFF sample project available in the nRF Connect SDK here for reference.

    Best regards,

    Simon

Reply
  • Hi

    A colleague of mine made a small test application to test the GRTC SYSCOUNTER in deep sleep mode that you should be able to use as reference for GRTC during system OFF mode implementation.

    Configs required for the below snippet:
    CONFIG_REBOOT=y
    CONFIG_POWEROFF=y

    #include <stdio.h>
    #include <nrf54l15_global.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/reboot.h>
    #include <zephyr/sys/poweroff.h>
    #include <zephyr/drivers/timer/nrf_grtc_timer.h>
    #include <zephyr/drivers/gpio.h>
    #define DEEP_SLEEP_TIME_S 2
    
    static const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);
    
    int main(void)
    {
     int err;
    
     printf("Hello World! %s\n", CONFIG_BOARD_TARGET);
    
     err = gpio_pin_configure_dt(&sw0, GPIO_INPUT);
     printf("gpio_pin_configure_dt %d\n", err);
     if (err) return err;
    
     err = gpio_pin_interrupt_configure_dt(&sw0, GPIO_INT_LEVEL_ACTIVE);
     printf("gpio_pin_interrupt_configure_dt %d\n", err);
     if (err) return err;
    
     while (1) {
      static uint8_t i = 0;
      i++;
      printf("%02d GRTC %08x%08x\n", i, NRF_GRTC->SYSCOUNTER[0].SYSCOUNTERH, NRF_GRTC->SYSCOUNTER[0].SYSCOUNTERL);
      k_msleep(1000);
      if (i > 3) {
       sys_reboot(SYS_REBOOT_WARM);
       sys_reboot(SYS_REBOOT_COLD);
       err = z_nrf_grtc_wakeup_prepare(DEEP_SLEEP_TIME_S * USEC_PER_SEC);
       // printf("z_nrf_grtc_wakeup_prepare %d\n", err);
       if (!err) {
        sys_poweroff();
       }
      }
     }
    
     return 0;
    }
     

    As for making the idle thread putting the device into system OFF mode I think you need to implement that logic in your idle thread yourself. You can probably use the system OFF sample project available in the nRF Connect SDK here for reference.

    Best regards,

    Simon

Children
  • Hi Simonr,

    Thanks for the snippet! My follow up Qs would be re:"I think you need to implement that logic in your idle thread yourself.." -- I guess how would I do that other than modifying the kernel code itself? Is there a way to hook into the idle thread somehow (via a callback, etc)? As I mentioned, I don't think the CONFIG_PM option is actually working -- which looks like would enable some functionality to do this...

Related