From bb3875049c90e0641d65cdd232ecf927e6a9f6d1 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Mon, 13 Aug 2018 14:25:27 +0800 Subject: [PATCH] Fix serial corruption due to deep sleep Prevent deep sleep when there is still any character being transmitted on the UART. This allows tickless to be safely enabled. --- .../TARGET_NUVOTON/TARGET_M2351/serial_api.c | 22 +++++++++++++++++ targets/TARGET_NUVOTON/TARGET_M2351/sleep.c | 11 +++++++++ .../TARGET_NUVOTON/TARGET_M451/serial_api.c | 22 +++++++++++++++++ targets/TARGET_NUVOTON/TARGET_M451/sleep.c | 11 +++++++++ .../TARGET_NUVOTON/TARGET_M480/serial_api.c | 22 +++++++++++++++++ targets/TARGET_NUVOTON/TARGET_M480/sleep.c | 11 +++++++++ .../TARGET_NANO100/serial_api.c | 24 ++++++++++++++++++- targets/TARGET_NUVOTON/TARGET_NANO100/sleep.c | 11 +++++++++ .../TARGET_NUVOTON/TARGET_NUC472/serial_api.c | 22 +++++++++++++++++ targets/TARGET_NUVOTON/TARGET_NUC472/sleep.c | 11 +++++++++ 10 files changed, 166 insertions(+), 1 deletion(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M2351/serial_api.c index 277332ccea..534791c9d1 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M2351/serial_api.c @@ -25,6 +25,7 @@ #include "nu_modutil.h" #include "nu_bitutil.h" #include +#include #if DEVICE_SERIAL_ASYNCH #include "dma_api.h" @@ -87,6 +88,8 @@ static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch); static int serial_is_irq_en(serial_t *obj, SerialIrq irq); #endif +bool serial_can_deep_sleep(void); + static struct nu_uart_var uart0_var = { .ref_cnt = 0, .obj = NULL, @@ -1171,4 +1174,23 @@ static int serial_is_irq_en(serial_t *obj, SerialIrq irq) } #endif // #if DEVICE_SERIAL_ASYNCH + +bool serial_can_deep_sleep(void) +{ + bool sleep_allowed = 1; + const struct nu_modinit_s *modinit = uart_modinit_tab; + while (modinit->var != NULL) { + struct nu_uart_var *uart_var = (struct nu_uart_var *) modinit->var; + UART_T *uart_base = (UART_T *) NU_MODBASE(modinit->modname); + if (uart_var->ref_cnt > 0) { + if (!UART_IS_TX_EMPTY(uart_base)) { + sleep_allowed = 0; + break; + } + } + modinit++; + } + return sleep_allowed; +} + #endif // #if DEVICE_SERIAL diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/sleep.c b/targets/TARGET_NUVOTON/TARGET_M2351/sleep.c index 487da4799d..2ea568957a 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/sleep.c +++ b/targets/TARGET_NUVOTON/TARGET_M2351/sleep.c @@ -22,9 +22,14 @@ #include "device.h" #include "objects.h" #include "PeripheralPins.h" +#include #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#if DEVICE_SERIAL +bool serial_can_deep_sleep(void); +#endif + /** * Enter idle mode, in which just CPU is halted. */ @@ -42,6 +47,12 @@ void hal_sleep(void) __NONSECURE_ENTRY void hal_deepsleep(void) { +#if DEVICE_SERIAL + if (!serial_can_deep_sleep()) { + return; + } +#endif + SYS_UnlockReg(); CLK_PowerDown(); SYS_LockReg(); diff --git a/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c index 5c6b3335fc..3eb5efa34d 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c @@ -25,6 +25,7 @@ #include "nu_modutil.h" #include "nu_bitutil.h" #include +#include #if DEVICE_SERIAL_ASYNCH #include "dma_api.h" @@ -83,6 +84,8 @@ static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch); static int serial_is_irq_en(serial_t *obj, SerialIrq irq); #endif +bool serial_can_deep_sleep(void); + static struct nu_uart_var uart0_var = { .ref_cnt = 0, .obj = NULL, @@ -1088,4 +1091,23 @@ static int serial_is_irq_en(serial_t *obj, SerialIrq irq) } #endif // #if DEVICE_SERIAL_ASYNCH + +bool serial_can_deep_sleep(void) +{ + bool sleep_allowed = 1; + const struct nu_modinit_s *modinit = uart_modinit_tab; + while (modinit->var != NULL) { + struct nu_uart_var *uart_var = (struct nu_uart_var *) modinit->var; + UART_T *uart_base = (UART_T *) NU_MODBASE(modinit->modname); + if (uart_var->ref_cnt > 0) { + if (!UART_IS_TX_EMPTY(uart_base)) { + sleep_allowed = 0; + break; + } + } + modinit++; + } + return sleep_allowed; +} + #endif // #if DEVICE_SERIAL diff --git a/targets/TARGET_NUVOTON/TARGET_M451/sleep.c b/targets/TARGET_NUVOTON/TARGET_M451/sleep.c index c2bb24eb7e..ae41314636 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/sleep.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/sleep.c @@ -22,6 +22,11 @@ #include "device.h" #include "objects.h" #include "PeripheralPins.h" +#include + +#if DEVICE_SERIAL +bool serial_can_deep_sleep(void); +#endif /** * Enter idle mode, in which just CPU is halted. @@ -38,6 +43,12 @@ void hal_sleep(void) */ void hal_deepsleep(void) { +#if DEVICE_SERIAL + if (!serial_can_deep_sleep()) { + return; + } +#endif + SYS_UnlockReg(); CLK_PowerDown(); SYS_LockReg(); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c index 04c15c21d4..dcb24294d1 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c @@ -25,6 +25,7 @@ #include "nu_modutil.h" #include "nu_bitutil.h" #include +#include #if DEVICE_SERIAL_ASYNCH #include "dma_api.h" @@ -87,6 +88,8 @@ static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch); static int serial_is_irq_en(serial_t *obj, SerialIrq irq); #endif +bool serial_can_deep_sleep(void); + static struct nu_uart_var uart0_var = { .ref_cnt = 0, .obj = NULL, @@ -1145,4 +1148,23 @@ static int serial_is_irq_en(serial_t *obj, SerialIrq irq) } #endif // #if DEVICE_SERIAL_ASYNCH + +bool serial_can_deep_sleep(void) +{ + bool sleep_allowed = 1; + const struct nu_modinit_s *modinit = uart_modinit_tab; + while (modinit->var != NULL) { + struct nu_uart_var *uart_var = (struct nu_uart_var *) modinit->var; + UART_T *uart_base = (UART_T *) NU_MODBASE(modinit->modname); + if (uart_var->ref_cnt > 0) { + if (!UART_IS_TX_EMPTY(uart_base)) { + sleep_allowed = 0; + break; + } + } + modinit++; + } + return sleep_allowed; +} + #endif // #if DEVICE_SERIAL diff --git a/targets/TARGET_NUVOTON/TARGET_M480/sleep.c b/targets/TARGET_NUVOTON/TARGET_M480/sleep.c index c2bb24eb7e..ae41314636 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/sleep.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/sleep.c @@ -22,6 +22,11 @@ #include "device.h" #include "objects.h" #include "PeripheralPins.h" +#include + +#if DEVICE_SERIAL +bool serial_can_deep_sleep(void); +#endif /** * Enter idle mode, in which just CPU is halted. @@ -38,6 +43,12 @@ void hal_sleep(void) */ void hal_deepsleep(void) { +#if DEVICE_SERIAL + if (!serial_can_deep_sleep()) { + return; + } +#endif + SYS_UnlockReg(); CLK_PowerDown(); SYS_LockReg(); diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c index 4a7b26d608..216f34d4bb 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c @@ -18,13 +18,14 @@ #if DEVICE_SERIAL -#include #include "cmsis.h" #include "mbed_error.h" #include "mbed_assert.h" #include "PeripheralPins.h" #include "nu_modutil.h" #include "nu_bitutil.h" +#include +#include #if DEVICE_SERIAL_ASYNCH #include "dma_api.h" @@ -76,6 +77,8 @@ static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch); static int serial_is_irq_en(serial_t *obj, SerialIrq irq); #endif +bool serial_can_deep_sleep(void); + static struct nu_uart_var uart0_var = { .ref_cnt = 0, .obj = NULL, @@ -990,4 +993,23 @@ static int serial_is_irq_en(serial_t *obj, SerialIrq irq) } #endif // #if DEVICE_SERIAL_ASYNCH + +bool serial_can_deep_sleep(void) +{ + bool sleep_allowed = 1; + const struct nu_modinit_s *modinit = uart_modinit_tab; + while (modinit->var != NULL) { + struct nu_uart_var *uart_var = (struct nu_uart_var *) modinit->var; + UART_T *uart_base = (UART_T *) NU_MODBASE(modinit->modname); + if (uart_var->ref_cnt > 0) { + if (!UART_IS_TX_EMPTY(uart_base)) { + sleep_allowed = 0; + break; + } + } + modinit++; + } + return sleep_allowed; +} + #endif // #if DEVICE_SERIAL diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/sleep.c b/targets/TARGET_NUVOTON/TARGET_NANO100/sleep.c index dd32dd4171..2de2ab5881 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/sleep.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/sleep.c @@ -22,6 +22,11 @@ #include "device.h" #include "objects.h" #include "PeripheralPins.h" +#include + +#if DEVICE_SERIAL +bool serial_can_deep_sleep(void); +#endif /** * Enter idle mode, in which just CPU is halted. @@ -38,6 +43,12 @@ void hal_sleep(void) */ void hal_deepsleep(void) { +#if DEVICE_SERIAL + if (!serial_can_deep_sleep()) { + return; + } +#endif + SYS_UnlockReg(); CLK_PowerDown(); SYS_LockReg(); diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c index 37d66761e7..fa6240a39f 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c @@ -25,6 +25,7 @@ #include "nu_modutil.h" #include "nu_bitutil.h" #include +#include #if DEVICE_SERIAL_ASYNCH #include "dma_api.h" @@ -87,6 +88,8 @@ static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch); static int serial_is_irq_en(serial_t *obj, SerialIrq irq); #endif +bool serial_can_deep_sleep(void); + static struct nu_uart_var uart0_var = { .ref_cnt = 0, .obj = NULL, @@ -1136,4 +1139,23 @@ static int serial_is_irq_en(serial_t *obj, SerialIrq irq) } #endif // #if DEVICE_SERIAL_ASYNCH + +bool serial_can_deep_sleep(void) +{ + bool sleep_allowed = 1; + const struct nu_modinit_s *modinit = uart_modinit_tab; + while (modinit->var != NULL) { + struct nu_uart_var *uart_var = (struct nu_uart_var *) modinit->var; + UART_T *uart_base = (UART_T *) NU_MODBASE(modinit->modname); + if (uart_var->ref_cnt > 0) { + if (!UART_IS_TX_EMPTY(uart_base)) { + sleep_allowed = 0; + break; + } + } + modinit++; + } + return sleep_allowed; +} + #endif // #if DEVICE_SERIAL diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/sleep.c b/targets/TARGET_NUVOTON/TARGET_NUC472/sleep.c index c2bb24eb7e..ae41314636 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/sleep.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/sleep.c @@ -22,6 +22,11 @@ #include "device.h" #include "objects.h" #include "PeripheralPins.h" +#include + +#if DEVICE_SERIAL +bool serial_can_deep_sleep(void); +#endif /** * Enter idle mode, in which just CPU is halted. @@ -38,6 +43,12 @@ void hal_sleep(void) */ void hal_deepsleep(void) { +#if DEVICE_SERIAL + if (!serial_can_deep_sleep()) { + return; + } +#endif + SYS_UnlockReg(); CLK_PowerDown(); SYS_LockReg();