305 lines
11 KiB
C
305 lines
11 KiB
C
|
/*
|
||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||
|
*
|
||
|
* The MIT License (MIT)
|
||
|
*
|
||
|
* Copyright (c) 2013-2018 Damien P. George
|
||
|
* Copyright (c) 2022 Renesas Electronics Corporation
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
* of this software and associated documentation files (the "Software"), to deal
|
||
|
* in the Software without restriction, including without limitation the rights
|
||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the Software is
|
||
|
* furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
* THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include "py/runtime.h"
|
||
|
#include "py/mperrno.h"
|
||
|
#include "py/mphal.h"
|
||
|
#include "hal_data.h"
|
||
|
#include "rtc.h"
|
||
|
#include "powerctrl.h"
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
// Sleep Mode
|
||
|
// At power on, by default sleep is set as the low-power mode. Sleep
|
||
|
// mode is the most convenient low-power mode available, as it does
|
||
|
// not require any special configuration (other than configuring and
|
||
|
// enabling a suitable interrupt or event to wake the MCU from sleep)
|
||
|
// to return to normal program-execution mode.
|
||
|
// The states of the SRAM, the processor registers, and the hardware
|
||
|
// peripherals are all maintained in sleep mode, and the time needed
|
||
|
// to enter and wake from sleep is minimal. Any interrupt causes the
|
||
|
// MCU device to wake from sleep mode, including the Systick interrupt
|
||
|
// used by the RTOS scheduler.
|
||
|
|
||
|
// Software Standby Mode
|
||
|
// In software-standby mode, the CPU, as well as most of the on-chip
|
||
|
// peripheral functions and all of the internal oscillators, are
|
||
|
// stopped.
|
||
|
// The contents of the CPU internal registers and SRAM data, the states
|
||
|
// of on-chip peripheral functions, and I/O Ports are all retained.
|
||
|
// Software-standby mode allows significant reduction in power
|
||
|
// consumption, because most of the oscillators are stopped in this mode.
|
||
|
// Like sleep mode, standby mode requires an interrupt or event be
|
||
|
// configured and enabled to wake up.
|
||
|
|
||
|
// Snooze Mode
|
||
|
// Snooze mode can be used with some MCU peripherals to execute basic
|
||
|
// tasks while keeping the MCU in a low-power state.
|
||
|
// Many core peripherals and all clocks can be selected to run during
|
||
|
// Snooze, allowing for more flexible low-power configuration than
|
||
|
// Software Standby mode. To enable Snooze, select "Software Standby
|
||
|
// mode with Snooze mode enabled" for the "Low Power Mode" configuration
|
||
|
// option.
|
||
|
// Snooze mode settings (including entry/exit sources) are available
|
||
|
// under "Standby Options".
|
||
|
|
||
|
// Deep Software Standby Mode
|
||
|
// Deep Software Standby Mode is only available on some MCU devices.
|
||
|
// The MCU always wakes from Deep Software Standby Mode by going
|
||
|
// through reset, either by the negation of the reset pin or by one of
|
||
|
// the wakeup sources configurable in the "Deep Standby Options"
|
||
|
// configuration group.
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if defined(USE_FSP_LPM)
|
||
|
|
||
|
// LPM_MODE_SLEEP: Sleep mode
|
||
|
// LPM_MODE_STANDBY: Software Standby mode
|
||
|
// LPM_MODE_STANDBY_SNOOZE: Software Standby mode with Snooze mode enabled
|
||
|
// LPM_MODE_DEEP: Deep Software Standby mode
|
||
|
|
||
|
lpm_instance_ctrl_t g_lpm_sleep_ctrl;
|
||
|
|
||
|
const lpm_cfg_t g_lpm_sleep_cfg = {
|
||
|
.low_power_mode = LPM_MODE_SLEEP,
|
||
|
.snooze_cancel_sources = LPM_SNOOZE_CANCEL_SOURCE_NONE,
|
||
|
.standby_wake_sources = (lpm_standby_wake_source_t)0,
|
||
|
.snooze_request_source = LPM_SNOOZE_REQUEST_RTC_PERIOD,
|
||
|
.snooze_end_sources = (lpm_snooze_end_t)0,
|
||
|
.dtc_state_in_snooze = LPM_SNOOZE_DTC_DISABLE,
|
||
|
#if BSP_FEATURE_LPM_HAS_SBYCR_OPE
|
||
|
.output_port_enable = 0,
|
||
|
#endif
|
||
|
#if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
|
||
|
.io_port_state = 0,
|
||
|
.power_supply_state = 0,
|
||
|
.deep_standby_cancel_source = (lpm_deep_standby_cancel_source_t)0,
|
||
|
.deep_standby_cancel_edge = (lpm_deep_standby_cancel_edge_t)0,
|
||
|
#endif
|
||
|
.p_extend = NULL,
|
||
|
};
|
||
|
|
||
|
const lpm_instance_t g_lpm_sleep = {
|
||
|
.p_api = &g_lpm_on_lpm,
|
||
|
.p_ctrl = &g_lpm_sleep_ctrl,
|
||
|
.p_cfg = &g_lpm_sleep_cfg
|
||
|
};
|
||
|
|
||
|
lpm_instance_ctrl_t g_lpm_deep_ctrl;
|
||
|
|
||
|
const lpm_cfg_t g_lpm_deep_cfg = {
|
||
|
.low_power_mode = LPM_MODE_DEEP,
|
||
|
.snooze_cancel_sources =
|
||
|
LPM_SNOOZE_CANCEL_SOURCE_NONE,
|
||
|
.standby_wake_sources =
|
||
|
(lpm_standby_wake_source_t)0,
|
||
|
.snooze_request_source =
|
||
|
LPM_SNOOZE_REQUEST_RXD0_FALLING,
|
||
|
.snooze_end_sources =
|
||
|
(lpm_snooze_end_t)0,
|
||
|
.dtc_state_in_snooze =
|
||
|
LPM_SNOOZE_DTC_DISABLE,
|
||
|
#if BSP_FEATURE_LPM_HAS_SBYCR_OPE
|
||
|
.output_port_enable = LPM_OUTPUT_PORT_ENABLE_RETAIN,
|
||
|
#endif
|
||
|
#if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
|
||
|
.io_port_state = LPM_IO_PORT_NO_CHANGE,
|
||
|
.power_supply_state = LPM_POWER_SUPPLY_DEEPCUT0,
|
||
|
.deep_standby_cancel_source = LPM_DEEP_STANDBY_CANCEL_SOURCE_RTC_INTERVAL | LPM_DEEP_STANDBY_CANCEL_SOURCE_RTC_ALARM | (lpm_deep_standby_cancel_source_t)0,
|
||
|
.deep_standby_cancel_edge = (lpm_deep_standby_cancel_edge_t)0,
|
||
|
#endif
|
||
|
.p_extend = NULL,
|
||
|
};
|
||
|
|
||
|
const lpm_instance_t g_lpm_deep = {
|
||
|
.p_api = &g_lpm_on_lpm,
|
||
|
.p_ctrl = &g_lpm_deep_ctrl,
|
||
|
.p_cfg = &g_lpm_deep_cfg
|
||
|
};
|
||
|
|
||
|
lpm_instance_ctrl_t g_lpm_standby_ctrl;
|
||
|
|
||
|
const lpm_cfg_t g_lpm_standby_cfg = {
|
||
|
.low_power_mode = LPM_MODE_STANDBY,
|
||
|
.snooze_cancel_sources =
|
||
|
LPM_SNOOZE_CANCEL_SOURCE_NONE,
|
||
|
.standby_wake_sources =
|
||
|
LPM_STANDBY_WAKE_SOURCE_RTCALM | LPM_STANDBY_WAKE_SOURCE_RTCPRD | (lpm_standby_wake_source_t)0,
|
||
|
.snooze_request_source = LPM_SNOOZE_REQUEST_RXD0_FALLING,
|
||
|
.snooze_end_sources = (lpm_snooze_end_t)0,
|
||
|
.dtc_state_in_snooze = LPM_SNOOZE_DTC_DISABLE,
|
||
|
#if BSP_FEATURE_LPM_HAS_SBYCR_OPE
|
||
|
.output_port_enable = LPM_OUTPUT_PORT_ENABLE_RETAIN,
|
||
|
#endif
|
||
|
#if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
|
||
|
.io_port_state = LPM_IO_PORT_NO_CHANGE,
|
||
|
.power_supply_state = LPM_POWER_SUPPLY_DEEPCUT0,
|
||
|
.deep_standby_cancel_source = LPM_DEEP_STANDBY_CANCEL_SOURCE_RTC_INTERVAL | (lpm_deep_standby_cancel_source_t)0,
|
||
|
.deep_standby_cancel_edge = (lpm_deep_standby_cancel_edge_t)0,
|
||
|
#endif
|
||
|
.p_extend = NULL,
|
||
|
};
|
||
|
|
||
|
const lpm_instance_t g_lpm_standby = {
|
||
|
.p_api = &g_lpm_on_lpm,
|
||
|
.p_ctrl = &g_lpm_standby_ctrl,
|
||
|
.p_cfg = &g_lpm_standby_cfg
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
NORETURN void powerctrl_mcu_reset(void) {
|
||
|
#if BSP_FEATURE_TZ_HAS_TRUSTZONE
|
||
|
R_BSP_NonSecureEnter();
|
||
|
#else
|
||
|
NVIC_SystemReset();
|
||
|
#endif
|
||
|
while (1) {
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
|
||
|
while (1) {
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t
|
||
|
// bl_addr) {
|
||
|
// }
|
||
|
|
||
|
void powerctrl_check_enter_bootloader(void) {
|
||
|
}
|
||
|
|
||
|
void powerctrl_enter_sleep_mode(void) {
|
||
|
// start trandition to RA MCU sleep mode
|
||
|
#if defined(USE_FSP_LPM)
|
||
|
fsp_err_t err;
|
||
|
err = R_LPM_Open(&g_lpm_sleep_ctrl, &g_lpm_sleep_cfg);
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter sleep mode"));
|
||
|
}
|
||
|
err = R_LPM_LowPowerModeEnter(&g_lpm_sleep_ctrl);
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter sleep mode"));
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void powerctrl_enter_stop_mode(void) {
|
||
|
// Disable IRQs so that the IRQ that wakes the device from stop mode is not
|
||
|
// executed until after the clocks are reconfigured
|
||
|
uint32_t irq_state = disable_irq();
|
||
|
|
||
|
#if defined(MICROPY_BOARD_ENTER_STOP)
|
||
|
MICROPY_BOARD_ENTER_STOP
|
||
|
#endif
|
||
|
|
||
|
// start trandition to RA MCU sleep mode
|
||
|
#if defined(USE_FSP_LPM)
|
||
|
fsp_err_t err;
|
||
|
err = R_LPM_Open(&g_lpm_standby_ctrl, &g_lpm_standby_cfg);
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter stop mode"));
|
||
|
}
|
||
|
err = R_LPM_LowPowerModeEnter(&g_lpm_standby_ctrl);
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter stop mode"));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// reconfigure the system clock after waking up
|
||
|
|
||
|
#if defined(MICROPY_BOARD_LEAVE_STOP)
|
||
|
MICROPY_BOARD_LEAVE_STOP
|
||
|
#endif
|
||
|
|
||
|
// Enable IRQs now that all clocks are reconfigured
|
||
|
enable_irq(irq_state);
|
||
|
}
|
||
|
|
||
|
void powerctrl_enter_standby_mode(void) {
|
||
|
rtc_init_finalise();
|
||
|
|
||
|
#if defined(MICROPY_BOARD_ENTER_STANDBY)
|
||
|
MICROPY_BOARD_ENTER_STANDBY
|
||
|
#endif
|
||
|
|
||
|
// start trandition to RA MCU deep software standby mode via software standby mode
|
||
|
#if defined(USE_FSP_LPM)
|
||
|
|
||
|
fsp_err_t err;
|
||
|
err = R_LPM_Open(&g_lpm_deep_ctrl, &g_lpm_deep_cfg);
|
||
|
/* Handle any errors. This function should be defined by the user. */
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter stop mode"));
|
||
|
}
|
||
|
/* Check the Deep Software Standby Reset Flag. */
|
||
|
if (1U == R_SYSTEM->RSTSR0_b.DPSRSTF) {
|
||
|
/* Clear the IOKEEP bit to allow I/O Port use. */
|
||
|
err = R_LPM_IoKeepClear(&g_lpm_deep_ctrl);
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter stop mode"));
|
||
|
}
|
||
|
}
|
||
|
/* Add user code here. */
|
||
|
/* Reconfigure the module to set the IOKEEP bit before entering deep software standby. */
|
||
|
err = R_LPM_LowPowerReconfigure(&g_lpm_deep_ctrl, &g_lpm_deep_cfg);
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter stop mode"));
|
||
|
}
|
||
|
err = R_LPM_LowPowerModeEnter(&g_lpm_deep_ctrl);
|
||
|
/* Code after R_LPM_LowPowerModeEnter when using Deep Software Standby never be executed.
|
||
|
* Deep software standby exits by resetting the MCU. */
|
||
|
if (err != FSP_SUCCESS) {
|
||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Can't enter stop mode"));
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// We need to clear the PWR wake-up-flag before entering standby, since
|
||
|
// the flag may have been set by a previous wake-up event. Furthermore,
|
||
|
// we need to disable the wake-up sources while clearing this flag, so
|
||
|
// that if a source is active it does actually wake the device.
|
||
|
// See section 5.3.7 of RM0090.
|
||
|
|
||
|
// save RTC interrupts
|
||
|
// disable register write protection
|
||
|
// disable RTC interrupts
|
||
|
// clear RTC wake-up flags
|
||
|
|
||
|
// enable previously-enabled RTC interrupts
|
||
|
// enable register write protection
|
||
|
|
||
|
// enter standby mode
|
||
|
|
||
|
// we never return; MCU is reset on exit from standby
|
||
|
}
|