Merge pull request #8049 from OpenNuvoton/nuvoton_fix_hal_sleep

Nuvoton: Fix mbed_hal-sleep test failed
pull/8298/head
Martin Kojtal 2018-10-01 11:48:25 +02:00 committed by GitHub
commit 59ce41f255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1237 additions and 849 deletions

View File

@ -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;

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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();

View File

@ -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));

View File

@ -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

View File

@ -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();

View File

@ -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));

View File

@ -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

View File

@ -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();

View File

@ -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));

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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
}