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;
}