Low power management of external flash

Hi,

my setup is the following:

- SDK 2.6.3

- nRF5340

- Low power management for external flash enabled

- Logging enabled (based on littleFS)

- external flash used to store continuously data 

With this configuration i am observing an exponential increase of booting time due to the introduction of the the entry to and exit from low power of the external flash as defined in the file \v2.6.3\zephyr\drivers\flash\spi_nor.c.

The characteristic of my external flash for entry and exit the deep sleep mode are the following:

- 30us to enter in Deep Power down mode

- 10us to exit Deep Power down mode

Those values are rounded up to 1 ms each by the defines in \v2.6.3\zephyr\drivers\flash\spi_nor.c 

#define T_RES1_MS DIV_ROUND_UP(DT_INST_PROP(0, t_exit_dpd), NSEC_PER_MSEC)

#define T_DP_MS DIV_ROUND_UP(DT_INST_PROP(0, t_enter_dpd), NSEC_PER_MSEC)

1. Why the need to convert in milliseconds those delays (in the specific case, causing an increase between 30 and 100 times) ?

2. For such kind of microseconds delay would not be better to use even a blocking delay like NRFX_DELAY_US ? (I have modified the spi.nor file and seems to work properly)

3. Is there a way - even i looked for but could not find it - to enable the power management for the external flash at runtime ? So in my case, it would be disabled at the boot up and once done, it gets enabled.

4. Eventually, could this change be considered in the future version of sdk ?

Thanks in advance for your support.

Kind regards

Riccardo Gaiati

 

  • Hi,

    1. Why the need to convert in milliseconds those delays (in the specific case, causing an increase between 30 and 100 times) ?

    In the API we're using we're rounding up to nearest ms. If your device are capable of running with those delays and your activity can handle it (and you can handle the extra current consumption that might come with this), you're free to test out using 30 and 10 µs instead.

    2. For such kind of microseconds delay would not be better to use even a blocking delay like NRFX_DELAY_US ? (I have modified the spi.nor file and seems to work properly)

    If it works and you've tested it properly, then you should be able to use the nrfx_delay_us instead, but note that we've only tested with what is present in the SDK by default

    3. Is there a way - even i looked for but could not find it - to enable the power management for the external flash at runtime ? So in my case, it would be disabled at the boot up and once done, it gets enabled.

    PM device API: https://docs.nordicsemi.com/bundle/ncs-latest/page/zephyr/services/pm/index.html 

    4. Eventually, could this change be considered in the future version of sdk ?

    I'm not 100% sure this is relevant after you've seen through the PM device in item 3, but let me know if that change sanything

    Kind regards,
    Andreas

  • Hi,

    thanks for the reply.

    Regarding the PM APIs, i can control the entry ti and exit from low power of the flash through those functions. But what about the log system ? Would it call these function aswell ? 

  • Hi,

    Yes, if I understand your question correct. The logging system itself doesn't automatically call PM functions, but if you're for instance logging over UART you can use the PM API to suspend the UART device, somewhat similar to what's shown below and thus disable/enable logging:

    const struct device *uart0_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));  
    pm_device_action_run(uart0_dev, PM_DEVICE_ACTION_SUSPEND);

    From here you can resume the UART device when you need it to enable logging again. I believe this public case might still be relevant, allthough it is >2 years old. Do note that some API's and configs may have changed from the relevant NCS version at that point in time and the latest and greatest now in 2025: Nordic Q&A: nRF52840 Power Management when idle.
    Let me know if I understood your question properly and please clarify if I missed what you were referring to
    Kind regards,
    Andreas
  • Thanks for the reply.

    The logging system is using the littlefs and the external flash. From your reply, i understand that this approach with the PM apis would not work in my case; unless i create a wrapper for the log functions where those PM apis are then invoked.

    At this point, i find easier to modify the actual implementation of spi_nor.c where the delays are now defined in TICKS, so that all the other modules that use it are not affected.

    #if DT_INST_NODE_HAS_PROP(0, t_enter_dpd)
    #define T_DP_US (DT_INST_PROP(0, t_enter_dpd) / NSEC_PER_USEC)
    #define T_DP_TICK (k_us_to_ticks_near32(T_DP_US))
    #else /* T_ENTER_DPD */
    #define T_DP_MS 0
    #endif /* T_ENTER_DPD */
    #if DT_INST_NODE_HAS_PROP(0, t_exit_dpd)
    #define T_RES1_US (DT_INST_PROP(0, t_exit_dpd) / NSEC_PER_USEC)
    #define T_RES1_TICK (k_us_to_ticks_near32(T_RES1_US))

    Honestly, i dont see why this approach cannot be considered in the future, instead of rounding up to 1 ms all the delays to enter and exit the low power of a flash. Is there an official place where a proposal like this can be done ?

    Thanks again for your support.

  • Hmm, maybe. I did some looking around because I remembered another case from roughly 1.5 years ago with NCS v2.4.1. At this point in time we had limited/experimental XIP over QSPI support and to showcase how to do a "low" power version of this a colleague of mine created a demo. You might be able to apply a similar application to the logging functionality and/or external flash as done below in the excerpt of main() within the attached xip sample.

    The interesting part in the snippet below that I'm referring to is related to

    pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
    pm_device_action_run(flash_dev, PM_DEVICE_ACTION_RESUME);

    int main(void)
    {
    	int blink_status = 0;
    	int err;
    	
    	const struct device *flash_dev = DEVICE_DT_GET(FLASH_NODE);
    	const struct device *uart_dev = DEVICE_DT_GET(UART_NODE);
    
      printk("XIP test sample\n");
      k_sleep(K_SECONDS(1));
    
      for (;;) {
        printk("Start test loop\n");
    
    #if CONFIG_NORDIC_QSPI_NOR_XIP
        nrf_qspi_nor_xip_enable(flash_dev, true);
        for(int i = 0; i < 10; i++){
          xip_test_write_ext_flash();
          k_sleep(K_MSEC(1));
          printk("XIP external flash write %d\n",i);
        }
    #endif
    
        for(int i = 0; i < 10; i++){
          test_write_ext_flash();
          k_sleep(K_MSEC(1));
          printk("External flash write %d\n",i);
        }
    
        printk("Disable test loop and sleep for 10 sec\n");
        pm_device_action_run(uart_dev, PM_DEVICE_ACTION_SUSPEND);
        pm_device_action_run(flash_dev, PM_DEVICE_ACTION_SUSPEND);
    #if CONFIG_NORDIC_QSPI_NOR_XIP
        xip_enabled = 0;
        nrf_qspi_nor_xip_enable(flash_dev, false);
    #endif
    
        dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
        k_sleep(K_SECONDS(10));
    
        pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME);
        pm_device_action_run(flash_dev, PM_DEVICE_ACTION_RESUME);
        xip_enabled = 1;
      }
    }

    8156.xip_write_run_disable_feat_xip_thread (3).zip

    I.e you can use PM API to suspend the flash_device when you've finished your activity with/on the external flash, but I'm not sure how well this translates to how to do this with the logging module. Let me know if you have any thoughts w.r.t how suspending the flash device is done in this sample

    Kind regards,
    Andreas

Related