UARTE1 doesn't turn off using Zephyr PM subsystem

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

Parents Reply Children
No Data
Related