Hi Devzone,
I am using an nrf5340 with NCS v2.0.0 and am trying to implement power management.
I found this link and have been taking hints from it
https://github.com/nrfconnect/sdk-zephyr/tree/main/samples/boards/nrf/system_off
This is the scenario I would like to implement.
- Enter deep sleep mode (used primarily for shipping device and storage)
- Wakeup on GPIOTE interrupt when ready for use
- Advertise/pair/bond
- Do a few tasks based on timer
- Sample data from various devices attached to peripherals
- Setup to enter PM_STATE_SUSPEND_TO_RAM sleep mode
- Un-init peripherals
- Set peripherals to PM_DEVICE_ACTION_SUSPEND
- Set peripheral pins to output low
- Enter PM_STATE_SUSPEND_TO_RAM
- Un-init peripherals
- Wakeup on timer
- Init peripherals
- Set peripherals to PM_DEVICE_ACTION_RESUME
- Initialize peripherals
- Sample data from various devices attached to peripherals
- Init peripherals
- Got back to 5
Peripherals used:
I2C1
SPIM2
SPIM4
SAADC
DPPI
reduced prj.conf setup
CONFIG_I2C=y CONFIG_SENSOR=y CONFIG_TMP116=y CONFIG_NRFX_SPIM2=y CONFIG_NRFX_SPIM4=y CONFIG_PM=y CONFIG_PM_DEVICE=y CONFIG_NRFX_SAADC=y CONFIG_NRFX_TIMER1=y CONFIG_NRFX_DPPI=y
To prevent the nrf5340 from entering deep sleep mode until I tell it I call
pm_policy_state_lock_get(PM_STATE_SOFT_OFF);
struct pm_state_info sleep_state = {PM_STATE_SUSPEND_TO_RAM, 0, 0}; pm_state_force(0u, &sleep_state);
I have mostly everything mostly working, I can read and write to my devices on the various peripherals. The issue I am running into is directly setting the power setting of the various peripherals.
Calling this code to set the I2C1 device to suspend, results in a system crash.
struct device *i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c1)); pm_device_action_run(i2c_dev, PM_DEVICE_ACTION_SUSPEND);
After stepping through that code I see that the crash occurs after calling
atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_STATE_LOCKED);
I saw this same issue when setting the power state for SPI2.
I have a few questions:
- What devices are supported by pm_device_action_run? It runs OK in the sample for UART0 listed above but not for I2C1 or SPI2.
- Does the peripherals have to be un-initialized and the pins configured in output low mode for the greatest power saving?
- What is the correct order of operation for the peripherals:
- For wakeup? Set to active state, then initialize or vice versa?
- For sleep? Set to suspend then un-initialize or vice versa?
- Should I even bother trying to run a pm_device_action_run on the I2C1, SPIM2, etc... or will the power management set that for me automatically?
- I have a tmp117 attached to I2C1 and am using the zephyr driver to communicate with it. How do you unconfigure the I2C1? Again is it even necessary to configure it, use it then unconfigure it after use to achieve power savings?
- Do I need to setup power states in my overlay file? I didn't see one in the sample I sited above.
- What is the best way to achieve the scenario I described above with the best power savings?
- How do you set wake on interrupt for a single GPIOTE? The example has this for a GPIO sw0 on the nrf5340dk
/* Configure to generate PORT event (wakeup) on button 1 press. */ nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios), NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios), NRF_GPIO_PIN_SENSE_LOW);
- This is what I currently have for GPIOTE using pin31. Will this work the same way?
#define GPIOTE31 NRF_GPIO_PIN_MAP(0,31) const nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); nrfx_gpiote_in_init(GPIOTE31, &in_config, set_wakeup_detected);
Any help in configuring and setup to achieve best power saving would be appreciated.
Thanks