mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #8049 from OpenNuvoton/nuvoton_fix_hal_sleep
Nuvoton: Fix mbed_hal-sleep test failedpull/8298/head
commit
59ce41f255
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -197,6 +197,18 @@ void SYS_UnlockReg_S(void)
|
|||
SYS_UnlockReg();
|
||||
}
|
||||
|
||||
__NONSECURE_ENTRY
|
||||
void CLK_Idle_S(void)
|
||||
{
|
||||
CLK_Idle();
|
||||
}
|
||||
|
||||
__NONSECURE_ENTRY
|
||||
void CLK_PowerDown_S(void)
|
||||
{
|
||||
CLK_PowerDown();
|
||||
}
|
||||
|
||||
static bool check_mod_ns(int modclass, uint32_t modidx)
|
||||
{
|
||||
const nu_modidx_ns_t *modidx_ns = modidx_ns_tab;
|
||||
|
|
|
@ -71,6 +71,14 @@ void SYS_LockReg_S(void);
|
|||
__NONSECURE_ENTRY
|
||||
void SYS_UnlockReg_S(void);
|
||||
|
||||
/* Secure CLK_Idle */
|
||||
__NONSECURE_ENTRY
|
||||
void CLK_Idle_S(void);
|
||||
|
||||
/* Secure CLK_PowerDown */
|
||||
__NONSECURE_ENTRY
|
||||
void CLK_PowerDown_S(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#if DEVICE_LPTICKER
|
||||
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_wait_api.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_timer.h"
|
||||
#include "nu_miscutil.h"
|
||||
#include "partition_M2351.h"
|
||||
|
||||
|
@ -135,10 +135,10 @@ void lp_ticker_init(void)
|
|||
// Continuous mode
|
||||
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451/M480/M2351. In M451/M480/M2351, TIMER_CNT is updated continuously by default.
|
||||
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
timer_base->CMP = cmp_timer;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
// Set vector
|
||||
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
|
||||
|
@ -146,13 +146,13 @@ void lp_ticker_init(void)
|
|||
NVIC_DisableIRQ(TIMER_MODINIT.irq_n);
|
||||
|
||||
TIMER_EnableInt(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_EnableWakeup(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_Start(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
/* Wait for timer to start counting and raise active flag */
|
||||
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nu_modutil.h"
|
||||
#include "nu_bitutil.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -22,30 +22,48 @@
|
|||
#include "device.h"
|
||||
#include "objects.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#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.
|
||||
*/
|
||||
__NONSECURE_ENTRY
|
||||
void hal_sleep(void)
|
||||
{
|
||||
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
||||
SYS_UnlockReg();
|
||||
CLK_Idle();
|
||||
SYS_LockReg();
|
||||
#else
|
||||
SYS_UnlockReg_S();
|
||||
CLK_Idle_S();
|
||||
SYS_LockReg_S();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter power-down mode, in which HXT/HIRC are halted.
|
||||
*/
|
||||
__NONSECURE_ENTRY
|
||||
void hal_deepsleep(void)
|
||||
{
|
||||
#if DEVICE_SERIAL
|
||||
if (!serial_can_deep_sleep()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
||||
SYS_UnlockReg();
|
||||
CLK_PowerDown();
|
||||
SYS_LockReg();
|
||||
#else
|
||||
SYS_UnlockReg_S();
|
||||
CLK_PowerDown_S();
|
||||
SYS_LockReg_S();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#if DEVICE_LPTICKER
|
||||
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_wait_api.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_timer.h"
|
||||
#include "nu_miscutil.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
|
@ -101,10 +101,10 @@ void lp_ticker_init(void)
|
|||
// Continuous mode
|
||||
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
|
||||
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
timer_base->CMP = cmp_timer;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
// Set vector
|
||||
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
|
||||
|
@ -112,13 +112,13 @@ void lp_ticker_init(void)
|
|||
NVIC_DisableIRQ(TIMER_MODINIT.irq_n);
|
||||
|
||||
TIMER_EnableInt(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_EnableWakeup(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_Start(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
/* Wait for timer to start counting and raise active flag */
|
||||
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nu_modutil.h"
|
||||
#include "nu_bitutil.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
#include "device.h"
|
||||
#include "objects.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#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();
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#if DEVICE_LPTICKER
|
||||
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_wait_api.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_timer.h"
|
||||
#include "nu_miscutil.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
|
@ -101,10 +101,10 @@ void lp_ticker_init(void)
|
|||
// Continuous mode
|
||||
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451/M480. In M451/M480, TIMER_CNT is updated continuously by default.
|
||||
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
timer_base->CMP = cmp_timer;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
// Set vector
|
||||
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
|
||||
|
@ -112,13 +112,13 @@ void lp_ticker_init(void)
|
|||
NVIC_DisableIRQ(TIMER_MODINIT.irq_n);
|
||||
|
||||
TIMER_EnableInt(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_EnableWakeup(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_Start(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
/* Wait for timer to start counting and raise active flag */
|
||||
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nu_modutil.h"
|
||||
#include "nu_bitutil.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
#include "device.h"
|
||||
#include "objects.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#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();
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#if DEVICE_LPTICKER
|
||||
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_wait_api.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_timer.h"
|
||||
#include "nu_miscutil.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
|
@ -102,13 +102,13 @@ void lp_ticker_init(void)
|
|||
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
|
||||
// Continuous mode
|
||||
timer_base->CTL = TIMER_CONTINUOUS_MODE;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
timer_base->PRECNT = prescale_timer;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
timer_base->CMPR = cmp_timer;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
// Set vector
|
||||
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
|
||||
|
@ -116,13 +116,13 @@ void lp_ticker_init(void)
|
|||
NVIC_DisableIRQ(TIMER_MODINIT.irq_n);
|
||||
|
||||
TIMER_EnableInt(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_EnableWakeup(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_Start(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
/* Wait for timer to start counting and raise active flag */
|
||||
while(! (timer_base->CTL & TIMER_CTL_TMR_ACT_Msk));
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
#include <string.h>
|
||||
#include "cmsis.h"
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_bitutil.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
#include "device.h"
|
||||
#include "objects.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#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();
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#if DEVICE_LPTICKER
|
||||
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_wait_api.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_timer.h"
|
||||
#include "nu_miscutil.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
|
@ -100,10 +100,10 @@ void lp_ticker_init(void)
|
|||
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
|
||||
// Continuous mode
|
||||
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer | TIMER_CTL_CNTDATEN_Msk;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
timer_base->CMP = cmp_timer;
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
// Set vector
|
||||
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
|
||||
|
@ -111,13 +111,13 @@ void lp_ticker_init(void)
|
|||
NVIC_DisableIRQ(TIMER_MODINIT.irq_n);
|
||||
|
||||
TIMER_EnableInt(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_EnableWakeup(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
TIMER_Start(timer_base);
|
||||
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
nu_busy_wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
|
||||
|
||||
/* Wait for timer to start counting and raise active flag */
|
||||
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nu_modutil.h"
|
||||
#include "nu_bitutil.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
#include "device.h"
|
||||
#include "objects.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#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();
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2015-2016 Nuvoton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nu_timer.h"
|
||||
#include "mbed_power_mgmt.h"
|
||||
#include "mbed_critical.h"
|
||||
#include "us_ticker_api.h"
|
||||
#include "mbed_assert.h"
|
||||
|
||||
void nu_countdown_init(struct nu_countdown_ctx_s *ctx, us_timestamp_t interval_us)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
sleep_manager_lock_deep_sleep();
|
||||
ctx->_ticker_data = get_us_ticker_data();
|
||||
ctx->_interval_end_us = ticker_read_us(ctx->_ticker_data) + interval_us;
|
||||
ctx->_expired = false;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
bool nu_countdown_expired(struct nu_countdown_ctx_s *ctx)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (! ctx->_expired) {
|
||||
ctx->_expired = ticker_read_us(ctx->_ticker_data) >= ctx->_interval_end_us;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
||||
return ctx->_expired;
|
||||
}
|
||||
|
||||
void nu_countdown_free(struct nu_countdown_ctx_s *ctx)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
|
||||
void nu_busy_wait_us(uint32_t us)
|
||||
{
|
||||
const uint32_t bits = us_ticker_get_info()->bits;
|
||||
const uint32_t mask = (1 << bits) - 1;
|
||||
MBED_ASSERT(us_ticker_get_info()->frequency == 1000000);
|
||||
uint32_t prev = us_ticker_read();
|
||||
while (1) {
|
||||
const uint32_t cur = us_ticker_read();
|
||||
const uint32_t elapsed = (cur - prev) & mask;
|
||||
if (elapsed > us) {
|
||||
break;
|
||||
}
|
||||
us -= elapsed;
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delay 4 cycles per round by hand-counting instruction cycles
|
||||
*
|
||||
* The delay function here is implemented by just hand-counting instruction cycles rather than preferred
|
||||
* H/W timer since it is to use in cases where H/W timer is not available. Usually, it can delay at least
|
||||
* 4-cycles per round.
|
||||
*
|
||||
* In modern pipeline core, plus flash performance and other factors, we cannot rely accurately on hand-
|
||||
* counting instruction cycles for expected delay cycles.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
MBED_NOINLINE
|
||||
__asm void nu_delay_cycle_x4(uint32_t rounds)
|
||||
{
|
||||
// AStyle should not format inline assembly
|
||||
// *INDENT-OFF*
|
||||
1
|
||||
#if !defined(__CORTEX_M0)
|
||||
NOP // 1 cycle
|
||||
#endif
|
||||
SUBS a1, a1, #1 // 1 cycle
|
||||
BCS %BT1 // 3 cycles(M0)/2 cycles(non-M0)
|
||||
BX lr
|
||||
// *INDENT-ON*
|
||||
}
|
||||
#elif defined (__ICCARM__)
|
||||
MBED_NOINLINE
|
||||
void nu_delay_cycle_x4(uint32_t rounds)
|
||||
{
|
||||
__asm volatile(
|
||||
"loop: \n"
|
||||
#if !defined(__CORTEX_M0)
|
||||
" NOP \n" // 1 cycle
|
||||
#endif
|
||||
" SUBS %0, %0, #1 \n" // 1 cycle
|
||||
" BCS.n loop\n" // 3 cycles(M0)/2 cycles(non-M0)
|
||||
: "+r"(rounds)
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
#elif defined ( __GNUC__ ) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
|
||||
MBED_NOINLINE
|
||||
void nu_delay_cycle_x4(uint32_t rounds)
|
||||
{
|
||||
__asm__ volatile(
|
||||
"%=:\n\t"
|
||||
#if !defined(__CORTEX_M0)
|
||||
"NOP\n\t" // 1 cycle
|
||||
#endif
|
||||
#if defined(__thumb__) && !defined(__thumb2__) && !defined(__ARMCC_VERSION)
|
||||
"SUB %0, #1\n\t" // 1 cycle
|
||||
#else
|
||||
"SUBS %0, %0, #1\n\t" // 1 cycle
|
||||
#endif
|
||||
"BCS %=b\n\t" // 3 cycles(M0)/2 cycles(non-M0)
|
||||
: "+l"(rounds)
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
#endif
|
|
@ -20,8 +20,6 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "cmsis.h"
|
||||
#include "mbed_power_mgmt.h"
|
||||
#include "mbed_critical.h"
|
||||
#include "ticker_api.h"
|
||||
#include "us_ticker_api.h"
|
||||
|
||||
|
@ -58,33 +56,26 @@ struct nu_countdown_ctx_s {
|
|||
bool _expired; // Expired or not
|
||||
};
|
||||
|
||||
__STATIC_INLINE void nu_countdown_init(struct nu_countdown_ctx_s *ctx, us_timestamp_t interval_us)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
sleep_manager_lock_deep_sleep();
|
||||
ctx->_ticker_data = get_us_ticker_data();
|
||||
ctx->_interval_end_us = ticker_read_us(ctx->_ticker_data) + interval_us;
|
||||
ctx->_expired = false;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
void nu_countdown_init(struct nu_countdown_ctx_s *ctx, us_timestamp_t interval_us);
|
||||
bool nu_countdown_expired(struct nu_countdown_ctx_s *ctx);
|
||||
void nu_countdown_free(struct nu_countdown_ctx_s *ctx);
|
||||
|
||||
__STATIC_INLINE bool nu_countdown_expired(struct nu_countdown_ctx_s *ctx)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (! ctx->_expired) {
|
||||
ctx->_expired = ticker_read_us(ctx->_ticker_data) >= ctx->_interval_end_us;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
||||
return ctx->_expired;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nu_countdown_free(struct nu_countdown_ctx_s *ctx)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
/* Replacement for wait_us when intermediary us ticker layer is disabled
|
||||
*
|
||||
* Use of wait_us directly from the low power ticker causes the system to deadlock during
|
||||
* the sleep test because the sleep test disables the intermediary us ticker layer during
|
||||
* the test.
|
||||
*
|
||||
* To prevent this lockup, nu_busy_wait_us is created to replace wait_us, which uses the us ticker
|
||||
* directly rather than go though the intermediary us ticker layer.
|
||||
*
|
||||
* During wait period through nu_busy_wait_us, CPU would be busy spinning.
|
||||
*/
|
||||
void nu_busy_wait_us(uint32_t us);
|
||||
|
||||
/* Delay 4 cycles per round by hand-counting instruction cycles */
|
||||
void nu_delay_cycle_x4(uint32_t rounds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue