From 55f88a0942b9548f8d02fa9d0f05ccfd6180cffd Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Thu, 27 Feb 2020 17:38:53 +0800 Subject: [PATCH 1/2] M487: Re-implement Reset_Handler() in naked inline assembly This is to guarantee SRAM bank2, not initialized yet, isn't used for stack by function preamble code at the very start. --- .../TARGET_M480/device/startup_M480.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M480/device/startup_M480.c b/targets/TARGET_NUVOTON/TARGET_M480/device/startup_M480.c index a851c655ed3..6110f145770 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/device/startup_M480.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/device/startup_M480.c @@ -360,18 +360,12 @@ __asm void Reset_Handler_Cascade(void *sp, void *pc) #elif defined (__GNUC__) || defined (__ICCARM__) -void Reset_Handler(void) +__attribute__((naked)) void Reset_Handler(void) { - /* NOTE: In debugger disassembly view, check initial stack cannot be accessed until initial stack pointer has changed to 0x20000200 */ - __asm volatile ( - "mov sp, %0 \n" - "mov r0, sp \n" - "mov r1, %1 \n" - "b Reset_Handler_Cascade \n" - : /* output operands */ - : "l"(0x20000200), "l"(&Reset_Handler_1) /* input operands */ - : "r0", "r1", "cc" /* list of clobbered registers */ - ); + __asm("ldr sp, =0x20000200 \n"); + __asm("mov r0, sp \n"); + __asm("ldr r1, =Reset_Handler_1 \n"); + __asm("b Reset_Handler_Cascade \n"); } void Reset_Handler_Cascade(void *sp, void *pc) From cbf1a8a6fd30610483032ef9d9ee68c9e9ab7067 Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Tue, 3 Sep 2019 18:04:23 +0800 Subject: [PATCH 2/2] M487: Get around h/w issue with reset from power-down mode When UART interrupt enabled and WDT reset from power-down mode, in the next cycle, UART interrupt keeps breaking in and cannot block unless via NVIC. To get around it, we deliberately make up a signal of WDT wake-up from power-down mode in the start of boot proces when WDT reset is detected. --- .../TARGET_M480/mbed_overrides.c | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c b/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c index 23838a50038..5f7c63cdbb7 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c @@ -16,6 +16,20 @@ #include "analogin_api.h" +void WDT_IRQHandler(void) +{ + /* Check WDT interrupt flag */ + if (WDT_GET_TIMEOUT_INT_FLAG()) { + WDT_CLEAR_TIMEOUT_INT_FLAG(); + WDT_RESET_COUNTER(); + } + + /* Check WDT wake-up flag */ + if (WDT_GET_TIMEOUT_WAKEUP_FLAG()) { + WDT_CLEAR_TIMEOUT_WAKEUP_FLAG(); + } +} + void mbed_sdk_init(void) { // NOTE: Support singleton semantics to be called from other init functions @@ -69,4 +83,49 @@ void mbed_sdk_init(void) /* Lock protected registers */ SYS_LockReg(); + + /* Get around h/w issue with reset from power-down mode + * + * When UART interrupt enabled and WDT reset from power-down mode, in the next + * cycle, UART interrupt keeps breaking in and cannot block unless via NVIC. To + * get around it, we make up a signal of WDT wake-up from power-down mode in the + * start of boot process on detecting WDT reset. + */ + if (SYS_IS_WDT_RST()) { + /* Enable IP module clock */ + CLK_EnableModuleClock(WDT_MODULE); + + /* Select IP clock source */ + CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0); + + /* The name of symbol WDT_IRQHandler() is mangled in C++ and cannot + * override that in startup file in C. Note the NVIC_SetVector call + * cannot be left out when WDT_IRQHandler() is redefined in C++ file. + * + * NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler); + */ + NVIC_EnableIRQ(WDT_IRQn); + + SYS_UnlockReg(); + + /* Configure/Enable WDT */ + WDT->CTL = WDT_TIMEOUT_2POW4 | // Timeout interval of 2^4 LIRC clocks + WDT_CTL_WDTEN_Msk | // Enable watchdog timer + WDT_CTL_INTEN_Msk | // Enable interrupt + WDT_CTL_WKF_Msk | // Clear wake-up flag + WDT_CTL_WKEN_Msk | // Enable wake-up on timeout + WDT_CTL_IF_Msk | // Clear interrupt flag + WDT_CTL_RSTF_Msk | // Clear reset flag + !WDT_CTL_RSTEN_Msk | // Disable reset + WDT_CTL_RSTCNT_Msk; // Reset up counter + + CLK_PowerDown(); + + /* Clear all flags & Disable WDT/INT/WK/RST */ + WDT->CTL = (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk | WDT_CTL_RSTCNT_Msk); + + NVIC_DisableIRQ(WDT_IRQn); + + SYS_LockReg(); + } }