summaryrefslogtreecommitdiffstatshomepage
path: root/ports/stm32/powerctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ports/stm32/powerctrl.c')
-rw-r--r--ports/stm32/powerctrl.c88
1 files changed, 80 insertions, 8 deletions
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index eea009e2d7..a750e8f5be 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -26,10 +26,10 @@
#include "py/mperrno.h"
#include "py/mphal.h"
+#include "boardctrl.h"
#include "powerctrl.h"
#include "rtc.h"
#include "extmod/modbluetooth.h"
-#include "py/mpconfig.h"
#ifndef NO_QSTR
#include "genhdr/pllfreqtable.h"
#endif
@@ -46,7 +46,7 @@ static uint32_t __attribute__((unused)) micropy_hw_hse_value = HSE_VALUE;
static uint32_t __attribute__((unused)) micropy_hw_clk_pllm = MICROPY_HW_CLK_PLLM;
#endif
-#if defined(STM32H5) || defined(STM32H7)
+#if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
#define RCC_SR RSR
#if defined(STM32H747xx)
#define RCC_SR_SFTRSTF RCC_RSR_SFT2RSTF
@@ -63,7 +63,7 @@ static uint32_t __attribute__((unused)) micropy_hw_clk_pllm = MICROPY_HW_CLK_PLL
#define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0
#elif defined(STM32H723xx)
#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling()
-#elif defined(STM32H5)
+#elif defined(STM32H5) || defined(STM32N6)
#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling()
#else
#define POWERCTRL_GET_VOLTAGE_SCALING() \
@@ -115,7 +115,7 @@ static inline void powerctrl_disable_hsi_if_unused(void) {
#endif
}
-NORETURN void powerctrl_mcu_reset(void) {
+MP_NORETURN void powerctrl_mcu_reset(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
*BL_STATE_PTR = BL_STATE_INVALID;
#if __DCACHE_PRESENT == 1
@@ -125,7 +125,7 @@ NORETURN void powerctrl_mcu_reset(void) {
NVIC_SystemReset();
}
-NORETURN static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t bl_addr) {
+MP_NORETURN static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t bl_addr) {
__asm volatile (
"ldr r2, [r1, #0]\n" // get address of stack pointer
"msr msp, r2\n" // get stack pointer
@@ -135,7 +135,13 @@ NORETURN static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, ui
MP_UNREACHABLE;
}
-NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
+MP_NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
+ #if defined(STM32N6)
+ LL_PWR_EnableBkUpAccess();
+ TAMP_S->BKP31R = r0;
+ NVIC_SystemReset();
+ #endif
+
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
// Enter the bootloader via a reset, so everything is reset (including WDT).
@@ -169,6 +175,8 @@ void powerctrl_check_enter_bootloader(void) {
#endif
}
+#if !defined(STM32N6)
+
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB) && !defined(STM32WL)
typedef struct _sysclk_scaling_table_entry_t {
@@ -781,6 +789,8 @@ static void powerctrl_low_power_exit_wb55() {
#endif // !defined(STM32F0) && !defined(STM32G0) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4)
+#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
@@ -809,7 +819,7 @@ void powerctrl_enter_stop_mode(void) {
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
#endif
- #if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32G4) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4) && !defined(STM32WB) && !defined(STM32WL)
+ #if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32G4) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4) && !defined(STM32N6) && !defined(STM32WB) && !defined(STM32WL)
// takes longer to wake but reduces stop current
HAL_PWREx_EnableFlashPowerDown();
#endif
@@ -848,6 +858,8 @@ void powerctrl_enter_stop_mode(void) {
#if defined(STM32F7)
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
+ #elif defined(STM32N6)
+ HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
#else
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
#endif
@@ -912,6 +924,19 @@ void powerctrl_enter_stop_mode(void) {
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) {
}
+ #elif defined(STM32N6)
+
+ // Enable PLL1, and switch the CPU and system clock source to use PLL1.
+ LL_RCC_PLL1_Enable();
+ while (!LL_RCC_PLL1_IsReady()) {
+ }
+ LL_RCC_SetCpuClkSource(LL_RCC_CPU_CLKSOURCE_IC1);
+ while (LL_RCC_GetCpuClkSource() != LL_RCC_CPU_CLKSOURCE_STATUS_IC1) {
+ }
+ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_IC2_IC6_IC11);
+ while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_IC2_IC6_IC11) {
+ }
+
#else // defined(STM32H5)
// enable PLL
@@ -1016,9 +1041,47 @@ void powerctrl_enter_stop_mode(void) {
enable_irq(irq_state);
}
-NORETURN void powerctrl_enter_standby_mode(void) {
+#if defined(STM32N6)
+
+// Upon wake from standby, STM32N6 can resume execution from retained SRAM1.
+// Place a small bootloader there which initialises XSPI in memory-mapped mode
+// and jumps to the main application entry point.
+
+#include "xspi.h"
+
+extern uint32_t _estack;
+
+void Reset_Handler(void);
+
+void iram_bootloader_reset(void) {
+ #if defined(MICROPY_BOARD_LEAVE_STANDBY)
+ MICROPY_BOARD_LEAVE_STANDBY;
+ #endif
+ xspi_init();
+ Reset_Handler();
+}
+
+// Very simple ARM vector table.
+const uint32_t iram_bootloader_isr_vector[] = {
+ (uint32_t)&_estack,
+ (uint32_t)&iram_bootloader_reset,
+};
+
+#endif
+
+MP_NORETURN void powerctrl_enter_standby_mode(void) {
rtc_init_finalise();
+ #if defined(STM32N6)
+ // Upon wake from standby, jump to the code at SRAM1.
+ // A board can reconfigure this in MICROPY_BOARD_ENTER_STANDBY if needed.
+ LL_PWR_EnableTCMSBRetention();
+ LL_PWR_EnableTCMFLXSBRetention();
+ LL_APB4_GRP2_EnableClock(LL_APB4_GRP2_PERIPH_SYSCFG);
+ SCB_CleanDCache();
+ SYSCFG->INITSVTORCR = (uint32_t)&iram_bootloader_isr_vector[0];
+ #endif
+
#if defined(MICROPY_BOARD_ENTER_STANDBY)
MICROPY_BOARD_ENTER_STANDBY
#endif
@@ -1039,6 +1102,13 @@ NORETURN void powerctrl_enter_standby_mode(void) {
mp_bluetooth_deinit();
#endif
+ #if defined(STM32N6)
+
+ // Clear all WKUPx flags.
+ LL_PWR_ClearFlag_WU();
+
+ #else
+
// 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
@@ -1135,6 +1205,8 @@ NORETURN void powerctrl_enter_standby_mode(void) {
powerctrl_low_power_prep_wb55();
#endif
+ #endif
+
// enter standby mode
HAL_PWR_EnterSTANDBYMode();