Merge pull request #14073 from bbugl/feature-nrf52-low-power-ble

Feature nrf52 low power ble
feature-nrf52-low-power-ble
Vincent Coubard 2021-06-02 13:52:43 +01:00 committed by GitHub
commit 8f2d1b2998
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 20 deletions

View File

@ -17,6 +17,7 @@ target_sources(mbed-ble-cordio
stack/sources/pal_bb_ble_rf.c
stack/sources/pal_cfg.c
stack/sources/pal_crypto.c
stack/sources/pal_rtc.c
stack/sources/pal_timer.c
)

View File

@ -202,6 +202,10 @@ NRFCordioHCIDriver::~NRFCordioHCIDriver()
// Stop timer
NRF_TIMER0->TASKS_STOP = 1;
NRF_TIMER0->TASKS_CLEAR = 1;
NRF_TIMER0->TASKS_SHUTDOWN = 1;
// Stop rtc
NRF_RTC1->TASKS_STOP = 1;
NVIC_ClearPendingIRQ(RADIO_IRQn);
NVIC_ClearPendingIRQ(TIMER0_IRQn);
@ -233,6 +237,7 @@ ble::buf_pool_desc_t NRFCordioHCIDriver::get_buffer_pool_description()
void NRFCordioHCIDriver::do_initialize()
{
if(_is_init) {
NRF_RTC1->TASKS_START = 1;
return;
}
@ -260,7 +265,13 @@ void NRFCordioHCIDriver::do_initialize()
{
}
if(NRF_CLOCK->LFCLKSRC == CLOCK_LFCLKSRC_SRC_RC) {
NRF_CLOCK->EVENTS_DONE = 0;
NRF_CLOCK->TASKS_CAL = 1;
while (NRF_CLOCK->EVENTS_DONE == 0)
{
}
}
// mbed-os target uses IRQ Handler names with _v added at the end
// (TIMER0_IRQHandler_v and TIMER2_IRQHandler_v) so we need to register these manually
@ -313,7 +324,13 @@ void NRFCordioHCIDriver::do_initialize()
void NRFCordioHCIDriver::do_terminate()
{
// Stop timer
NRF_TIMER0->TASKS_STOP = 1;
NRF_TIMER0->TASKS_CLEAR = 1;
NRF_TIMER0->TASKS_SHUTDOWN = 1;
// Stop rtc
NRF_RTC1->TASKS_STOP = 1;
}
void NRFCordioHCIDriver::start_reset_sequence()

View File

@ -527,6 +527,7 @@ void PalBbBleLowPower(void)
#if (USE_RTC_BB_CLK)
NRF_TIMER0->TASKS_STOP = 1;
NRF_TIMER0->TASKS_CLEAR = 1;
NRF_TIMER0->TASKS_SHUTDOWN = 1;
#endif
}

View File

@ -231,9 +231,6 @@ void PalRtcInit(void)
PalRtcDisableCompareIrq(channelId);
}
/* Configure low-frequency clock. */
NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->TASKS_LFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) { }

View File

@ -33,3 +33,9 @@ target_sources(mbed-core
us_ticker.c
watchdog_api.c
)
target_link_libraries(mbed-core
INTERFACE
mbed-ble-cordio
)

View File

@ -100,9 +100,6 @@ void COMMON_RTC_IRQ_HANDLER(void)
__STATIC_INLINE void errata_20(void)
{
#if defined(NRF52_PAN_20)
if (COMMON_RTC_INSTANCE != NRF_RTC1) {
return;
}
if (!NRF_HAL_SD_IS_ENABLED())
{
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
@ -112,12 +109,10 @@ __STATIC_INLINE void errata_20(void)
{
}
}
NRF_RTC1->TASKS_STOP = 0;
COMMON_RTC_INSTANCE->TASKS_STOP = 0;
#endif
}
void RTC1_IRQHandler(void);
void common_rtc_init(void)
{
if (m_common_rtc_enabled) {
@ -132,9 +127,7 @@ void common_rtc_init(void)
nrf_rtc_task_trigger(COMMON_RTC_INSTANCE, NRF_RTC_TASK_STOP);
if (COMMON_RTC_INSTANCE == NRF_RTC1) {
NVIC_SetVector(RTC1_IRQn, (uint32_t)RTC1_IRQHandler);
}
NVIC_SetVector(COMMON_RTC_IRQN, (uint32_t)COMMON_RTC_IRQ_HANDLER);
/* RTC is driven by the low frequency (32.768 kHz) clock, a proper request
* must be made to have it running.
@ -160,12 +153,12 @@ void common_rtc_init(void)
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK
#if defined(TARGET_MCU_NRF51822)
| OS_TICK_INT_MASK
| OS_TICK_INT_MASK
#endif
#if DEVICE_LPTICKER
| LP_TICKER_INT_MASK
| LP_TICKER_INT_MASK
#endif
);
);
/* This interrupt is enabled permanently, since overflow indications are needed
* continuously.

View File

@ -28,6 +28,7 @@
// of NRF51) as an alternative tick source for RTOS.
#define COMMON_RTC_INSTANCE NRF_RTC0
#define COMMON_RTC_IRQ_HANDLER RTC0_IRQHandler
#define COMMON_RTC_IRQN RTC0_IRQn
#define OS_TICK_CC_CHANNEL 0
#define LP_TICKER_CC_CHANNEL 1

View File

@ -20,9 +20,11 @@
#include "nrf_soc.h"
#include "nrf_timer.h"
#include "us_ticker.h"
#if BB_CLK_RATE_HZ == 32768 && FEATURE_BLE == 1
#include "bb_api.h"
#include "pal_timer.h"
#include "pal_rtc.h"
#endif
#if defined(SOFTDEVICE_PRESENT)
#include "nrf_sdh.h"
@ -41,14 +43,25 @@ extern bool us_ticker_initialized;
void hal_sleep(void)
{
/* Clock management for low power mode. */
#if BB_CLK_RATE_HZ == 32768
// Trigger an event when an interrupt is pending. This allows to wake up
// the processor from disabled interrupts.
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
#if defined(NRF52) || defined(NRF52840_XXAA)
/* Clear exceptions and PendingIRQ from the FPU unit */
__set_FPSCR(__get_FPSCR() & ~(FPU_EXCEPTION_MASK));
(void)__get_FPSCR();
NVIC_ClearPendingIRQ(FPU_IRQn);
#endif
/* Clock management for low power mode. */
#if BB_CLK_RATE_HZ == 32768 && FEATURE_BLE == 1
uint32_t rtcNow = NRF_RTC1->COUNTER;
if ((BbGetCurrentBod() == NULL))
{
if ((PalTimerGetState() == PAL_TIMER_STATE_BUSY &&
((NRF_RTC1->CC[3] - rtcNow) & PAL_MAX_RTC_COUNTER_VAL) > PAL_HFCLK_OSC_SETTLE_TICKS) ||
((NRF_RTC1->CC[3] - rtcNow) & PAL_MAX_RTC_COUNTER_VAL) > PAL_HFCLK_OSC_SETTLE_TICKS) ||
(PalTimerGetState() == PAL_TIMER_STATE_READY))
{
/* disable HFCLK */
@ -60,7 +73,33 @@ void hal_sleep(void)
#endif
NRF_POWER->TASKS_LOWPWR = 1;
__WFI();
// Note: it is not sufficient to just use WFE here, since the internal
// event register may be already set from an event that occurred in the
// past (like an SVC call to the SoftDevice) and in such case WFE will
// just clear the register and continue execution.
// Therefore, the strategy here is to first clear the event register
// by using SEV/WFE pair, and then execute WFE again, unless there is
// a pending interrupt.
// Set an event and wake up whatsoever, this will clear the event
// register from all previous events set (SVC call included)
__SEV();
__WFE();
// Test if there is an interrupt pending (mask reserved regions)
if (SCB->ICSR & (SCB_ICSR_RESERVED_BITS_MASK))
{
// Ok, there is an interrut pending, no need to go to sleep
return;
}
else
{
// next event will wakeup the CPU
// If an interrupt occured between the test of SCB->ICSR and this
// instruction, WFE will just not put the CPU to sleep
__WFE();
}
}
void hal_deepsleep(void)