Setup:
- nrf-sdk (v2.7.0rc2)
- custom board with nRF52840 QIAAD0 SoC
- current measurement directly on nRF VDD using Keysight 34465A, VDD=1V8
I'm using a code which is a copy-paste from subsys/pm/pm.c to disable peripherals registered in system. What I want to achieve is dynamically turning on/off some peripherals and for starters I wanted to disable all of them. What I see is current around 720uA, but once I explicitly disable UARTE1 in the device tree, current drops to 11uA. Similarly when I measure on external power source (3V) I got 540uA with UARTE1 enabled in dts and 50uA with UARTE1 disabled.
I saw many posts about UARTE1 keeping HFCLK on, turning off DMA on UARTE1 with STOPTX task, but from what I understand this is done automatically in uart_nrfx_uarte.c on action PM_DEVICE_ACTION_SUSPEND. I tried also to use another solution with powering off the UARTE1 by writing 0 to 0x40028FFC and then powering it back on and enabling it using PM_DEVICE_ACTION_RESUME, however when powering off/on the UARTE1 and then running resume action it causes UARTE1 to break and it's not functional anymore.
Any input appreciated,
thanks
static int disable_ds_1(void) { pm_policy_state_lock_get(PM_STATE_SOFT_OFF, PM_ALL_SUBSTATES); return 0; } SYS_INIT(disable_ds_1, PRE_KERNEL_2, 0); TYPE_SECTION_START_EXTERN(const struct device *, pm_device_slots); static size_t num_susp; static int pm_suspend_devices(void) { const struct device *devs; size_t devc; devc = z_device_get_all_static(&devs); num_susp = 0; for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) { int ret; /* * Ignore uninitialized devices, busy devices, wake up sources, and * devices with runtime PM enabled. */ if (!device_is_ready(dev) || pm_device_is_busy(dev) || pm_device_wakeup_is_enabled(dev) || pm_device_runtime_is_enabled(dev)) { continue; } ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND); /* ignore devices not supporting or already at the given state */ if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) { continue; } else if (ret < 0) { printk("Device %s did not enter %s state (%d)\n\r", dev->name, pm_device_state_str(PM_DEVICE_STATE_SUSPENDED), ret); return ret; } TYPE_SECTION_START(pm_device_slots)[num_susp] = dev; num_susp++; } return 0; } static void pm_resume_devices(void) { for (int i = (num_susp - 1); i >= 0; i--) { pm_device_action_run(TYPE_SECTION_START(pm_device_slots)[i], PM_DEVICE_ACTION_RESUME); } num_susp = 0; } int main(void) { pm_suspend_devices(); k_sleep(K_SECONDS(10)); pm_resume_devices(); k_sleep(K_SECONDS(1)); while (1) { k_sleep(K_SECONDS(1)); printk("ALIVE!\n\r"); } return 0; }