mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #14073 from bbugl/feature-nrf52-low-power-ble
Feature nrf52 low power blefeature-nrf52-low-power-ble
commit
8f2d1b2998
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) { }
|
||||
|
|
|
@ -33,3 +33,9 @@ target_sources(mbed-core
|
|||
us_ticker.c
|
||||
watchdog_api.c
|
||||
)
|
||||
|
||||
|
||||
target_link_libraries(mbed-core
|
||||
INTERFACE
|
||||
mbed-ble-cordio
|
||||
)
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue