samples: mimxrt595: Add Deep power down sample

Add a sample to put the part into Deep power down mode by
setting the state to PM_STATE_SOFT_OFF.
Wakup the part using an RTC alarm.

Signed-off-by: Mahesh Mahadevan <mahesh.mahadevan@nxp.com>
This commit is contained in:
Mahesh Mahadevan 2022-11-11 14:24:45 -06:00 committed by David Leach
commit 1a27e2bd8e
7 changed files with 263 additions and 0 deletions

View file

@ -0,0 +1,9 @@
# Copyright 2022, NXP
#
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(mimxrt595_evk_cm33_system_off)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,7 @@
# Copyright 2022, NXP
#
# SPDX-License-Identifier: Apache-2.0
mainmenu "MIMXRT595_EVK_CM33 SYSTEM_OFF demo"
source "Kconfig.zephyr"

View file

@ -0,0 +1,142 @@
.. _mimxrt595_evk-system-off-sample:
RT595 System Off demo
#####################
Overview
********
This sample can be used for basic power measurement and as an example of
soft off on NXP i.MX RT platforms. The functional behavior is:
* Busy-wait for 2 seconds
* Turn the system off after enabling wakeup through RTC and set alarm
10 seconds in the future to wake up the processor
Requirements
************
This application uses MIMXRT595-EVK for the demo.
Building, Flashing and Running
******************************
.. zephyr-app-commands::
:zephyr-app: samples/boards/mimxrt595_evk_cm33/system_off
:board: mimxrt595_evk_cm33
:goals: build flash
:compact:
Running:
1. Open UART terminal.
2. Power Cycle Device.
3. Device will turn on and idle for 2 seconds
4. Device will turn itself off using deep power down mode. RTC alarm
will wake device and restart the application from a warm reset.
Sample Output
=================
MIMXRT595-EVK core output
--------------------------
.. code-block:: console
*** Booting Zephyr OS build zephyr-v3.2.0-1045-g07228f716c78 ***
mimxrt595_evk_cm33 system off demo
RTC Alarm set for 10 seconds to wake from soft-off.
Entering system off
OTP Fuse setting to wake from Deep Power Down and reset flash
#############################################################
Background
**********
This sample will not resume the application after waking from Deep Power
Down (DPD) mode on an EVK with default settings. The reason is that the
flash is not normally reset when waking from DPD. This sample
eXecutes-In-Place (XIP) from the external flash. When the MCU wakes from
DPD, it wakes through the reset flow. But if the external flash is not
reset, the MCU and flash are no longer in sync, and the MCU cannot XIP.
In this default state, one can confirm the RTC is waking the MCU from
DPD because the MCU will set the PMIC_MODE pins to 0b00 requesting the
PMIC to enter the default boot mode, and the PMIC will enable the
regulator driving the VDDCORE rail at 1.0V. However, the MCU will not be
able to XIP from the flash to resume. One can press the Reset button in
this state to restart the app.
To wake from DPD and resume XIP from the flash, the MCU needs to be
configured to reset the external flash. This can be done by programming
the One-Time-Programmable (OTP) fuses in the MCU. The steps below detail
how program the OTP BOOT_CFG1 fuses to use GPIO pin PIO4_5 as the flash
reset. This fuse setting instructs the ROM bootloader to toggle PIO4_5
when resetting the flash. Note that the MIMXRT595-EVK board is designed
to have PIO4_5 drive the octal flash reset pin on FlexSPI0. Other boards
using this MCU may use a different GPIO pin, and the setting in the OTP
fuses must match the GPIO pin connected to reset. Before programming
fuses, it is best to write the OTP shadow registers first and confirm
the operation. Then program the OTP fuses after confirming the correct
settings. For more details on OTP fuses and shadow registers, refer to
the Reference Manual for this MCU, and the OTP Fuse Map spreadsheet
included as an attachment in the Reference Manual PDF.
Tools needed
************
These steps use the blhost tool that runs on a host computer running
Linux, Windows, or MacOS. Download blhost, find the appropriate blhost
executable for your host OS, and use the command-line steps below to
program the OTP fuses. To download, go to https://www.nxp.com/mcuboot,
and find the Blhost package under Downloads.
Steps to program OTP fuses on MIMXRT595-EVK
*******************************************
These steps detail using USB as the interface between blhost and the
ROM bootloader. UART is another option, for more details see the
blhost documentation and the Boot ROM chapter in the MCU Reference
Manual.
1. Power the EVK and connect USB J38 to host computer. J38 is for the
USB peripheral of the MCU, and will also power the EVK.
2. Set the DIP switches of SW7 to On-Off-On (123) to boot in ISP USB
HID mode.
3. Press the Reset button SW3 to boot in ISP mode. The EVK should
enumerate as a USB HID device in the host computer.
4. This command confirms the current settings of BOOT_CFG1 fuses:
blhost -u 0x1fc9,0x0023 -- efuse-read-once 0x61
5. This command programs BOOT_CFG1 to enable the flash reset pin using
PIO4_5:
blhost -u 0x1fc9,0x0023 -- efuse-program-once 0x61 0x164000
6. This command confirms the programmed fuses in BOOT_CFG1:
blhost -u 0x1fc9,0x0023 -- efuse-read-once 0x61
7. Set the DIP switches of SW7 to Off-Off-On (123) to boot from the
external flash on FlexSPI0.
8. Press the Reset button SW3 to boot from flash and run the app.
Expected results from blhost
****************************
>blhost -u 0x1fc9,0x0023 -- efuse-read-once 0x61
Inject command 'efuse-read-once'
Response status = 0 (0x0) Success.
Response word 1 = 4 (0x4)
Response word 2 = 0 (0x0)
>blhost -u 0x1fc9,0x0023 -- efuse-program-once 0x61 0x164000
Inject command 'efuse-program-once'
Successful generic response to command 'efuse-program-once'
Response status = 0 (0x0) Success.
>blhost -u 0x1fc9,0x0023 -- efuse-read-once 0x61
Inject command 'efuse-read-once'
Response status = 0 (0x0) Success.
Response word 1 = 4 (0x4)
Response word 2 = 1458176 (0x164000)

View file

@ -0,0 +1,10 @@
/*
* Copyright 2022, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
&rtc {
status = "okay";
wakeup-source;
};

View file

@ -0,0 +1,14 @@
#
# Copyright 2022, NXP
#
# SPDX-License-Identifier: Apache-2.0
#
CONFIG_PM=y
# Turn on Device Level Power Management as we wish
# to reconfigure the FlexSPI pins for power savings
# when transitioning the SoC to Deep Low Power modes.
CONFIG_PM_DEVICE=y
# Enable the RTC
CONFIG_COUNTER=y

View file

@ -0,0 +1,13 @@
#
# Copyright 2022, NXP
#
# SPDX-License-Identifier: Apache-2.0
#
sample:
name: Deep Power Down State Sample for mimxrt595_evk
common:
tags: power
tests:
sample.boards.mimxrt595_evk_cm33.system_off:
build_only: true
platform_allow: mimxrt595_evk_cm33

View file

@ -0,0 +1,68 @@
/*
* Copyright 2022, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/counter.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/policy.h>
#define BUSY_WAIT_S 2U
#define SLEEP_S 2U
#define SOFT_OFF_S 10U
#define RTC_NODE DT_NODELABEL(rtc)
#if !DT_NODE_HAS_STATUS(RTC_NODE, okay)
#error "Unsupported board: rtc node is not enabled"
#endif
#define RTC_CHANNEL_ID 0
static const struct device *const rtc_dev = DEVICE_DT_GET(RTC_NODE);
void main(void)
{
int ret;
printk("\n%s system off demo\n", CONFIG_BOARD);
uint32_t sleep_ticks = counter_us_to_ticks(rtc_dev, SOFT_OFF_S * 1000ULL * 1000ULL);
counter_start(rtc_dev);
if (sleep_ticks == 0) {
/* counter_us_to_ticks will round down the number of ticks to the nearest int. */
/* Ensure at least one tick is used in the RTC */
sleep_ticks++;
}
const struct counter_alarm_cfg alarm_cfg = {
.ticks = sleep_ticks,
.flags = 0,
};
ret = counter_set_channel_alarm(rtc_dev, RTC_CHANNEL_ID, &alarm_cfg);
if (ret != 0) {
printk("Could not rtc alarm.\n");
return;
}
printk("RTC Alarm set for %llu seconds to wake from soft-off.\n",
counter_ticks_to_us(rtc_dev, alarm_cfg.ticks) / (1000ULL * 1000ULL));
printk("Entering system off");
pm_state_force(0u, &(struct pm_state_info){ PM_STATE_SOFT_OFF, 0, 0 });
/* Now we need to go sleep. This will let the idle thread runs and
* the pm subsystem will use the forced state.
*/
k_sleep(K_SECONDS(SLEEP_S));
printk("ERROR: System off failed\n");
while (true) {
/* spin to avoid fall-off behavior */
}
}