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_bb_ble_rf.c
|
||||||
stack/sources/pal_cfg.c
|
stack/sources/pal_cfg.c
|
||||||
stack/sources/pal_crypto.c
|
stack/sources/pal_crypto.c
|
||||||
|
stack/sources/pal_rtc.c
|
||||||
stack/sources/pal_timer.c
|
stack/sources/pal_timer.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,10 @@ NRFCordioHCIDriver::~NRFCordioHCIDriver()
|
||||||
// Stop timer
|
// Stop timer
|
||||||
NRF_TIMER0->TASKS_STOP = 1;
|
NRF_TIMER0->TASKS_STOP = 1;
|
||||||
NRF_TIMER0->TASKS_CLEAR = 1;
|
NRF_TIMER0->TASKS_CLEAR = 1;
|
||||||
|
NRF_TIMER0->TASKS_SHUTDOWN = 1;
|
||||||
|
|
||||||
|
// Stop rtc
|
||||||
|
NRF_RTC1->TASKS_STOP = 1;
|
||||||
|
|
||||||
NVIC_ClearPendingIRQ(RADIO_IRQn);
|
NVIC_ClearPendingIRQ(RADIO_IRQn);
|
||||||
NVIC_ClearPendingIRQ(TIMER0_IRQn);
|
NVIC_ClearPendingIRQ(TIMER0_IRQn);
|
||||||
|
@ -233,6 +237,7 @@ ble::buf_pool_desc_t NRFCordioHCIDriver::get_buffer_pool_description()
|
||||||
void NRFCordioHCIDriver::do_initialize()
|
void NRFCordioHCIDriver::do_initialize()
|
||||||
{
|
{
|
||||||
if(_is_init) {
|
if(_is_init) {
|
||||||
|
NRF_RTC1->TASKS_START = 1;
|
||||||
return;
|
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
|
// 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
|
// (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()
|
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()
|
void NRFCordioHCIDriver::start_reset_sequence()
|
||||||
|
|
|
@ -527,6 +527,7 @@ void PalBbBleLowPower(void)
|
||||||
#if (USE_RTC_BB_CLK)
|
#if (USE_RTC_BB_CLK)
|
||||||
NRF_TIMER0->TASKS_STOP = 1;
|
NRF_TIMER0->TASKS_STOP = 1;
|
||||||
NRF_TIMER0->TASKS_CLEAR = 1;
|
NRF_TIMER0->TASKS_CLEAR = 1;
|
||||||
|
NRF_TIMER0->TASKS_SHUTDOWN = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,9 +231,6 @@ void PalRtcInit(void)
|
||||||
PalRtcDisableCompareIrq(channelId);
|
PalRtcDisableCompareIrq(channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure low-frequency clock. */
|
|
||||||
NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
|
|
||||||
|
|
||||||
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
|
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
|
||||||
NRF_CLOCK->TASKS_LFCLKSTART = 1;
|
NRF_CLOCK->TASKS_LFCLKSTART = 1;
|
||||||
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) { }
|
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) { }
|
||||||
|
|
|
@ -33,3 +33,9 @@ target_sources(mbed-core
|
||||||
us_ticker.c
|
us_ticker.c
|
||||||
watchdog_api.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)
|
__STATIC_INLINE void errata_20(void)
|
||||||
{
|
{
|
||||||
#if defined(NRF52_PAN_20)
|
#if defined(NRF52_PAN_20)
|
||||||
if (COMMON_RTC_INSTANCE != NRF_RTC1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!NRF_HAL_SD_IS_ENABLED())
|
if (!NRF_HAL_SD_IS_ENABLED())
|
||||||
{
|
{
|
||||||
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTC1_IRQHandler(void);
|
|
||||||
|
|
||||||
void common_rtc_init(void)
|
void common_rtc_init(void)
|
||||||
{
|
{
|
||||||
if (m_common_rtc_enabled) {
|
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);
|
nrf_rtc_task_trigger(COMMON_RTC_INSTANCE, NRF_RTC_TASK_STOP);
|
||||||
|
|
||||||
if (COMMON_RTC_INSTANCE == NRF_RTC1) {
|
NVIC_SetVector(COMMON_RTC_IRQN, (uint32_t)COMMON_RTC_IRQ_HANDLER);
|
||||||
NVIC_SetVector(RTC1_IRQn, (uint32_t)RTC1_IRQHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RTC is driven by the low frequency (32.768 kHz) clock, a proper request
|
/* RTC is driven by the low frequency (32.768 kHz) clock, a proper request
|
||||||
* must be made to have it running.
|
* 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
|
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK
|
||||||
#if defined(TARGET_MCU_NRF51822)
|
#if defined(TARGET_MCU_NRF51822)
|
||||||
| OS_TICK_INT_MASK
|
| OS_TICK_INT_MASK
|
||||||
#endif
|
#endif
|
||||||
#if DEVICE_LPTICKER
|
#if DEVICE_LPTICKER
|
||||||
| LP_TICKER_INT_MASK
|
| LP_TICKER_INT_MASK
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
/* This interrupt is enabled permanently, since overflow indications are needed
|
/* This interrupt is enabled permanently, since overflow indications are needed
|
||||||
* continuously.
|
* continuously.
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
// of NRF51) as an alternative tick source for RTOS.
|
// of NRF51) as an alternative tick source for RTOS.
|
||||||
#define COMMON_RTC_INSTANCE NRF_RTC0
|
#define COMMON_RTC_INSTANCE NRF_RTC0
|
||||||
#define COMMON_RTC_IRQ_HANDLER RTC0_IRQHandler
|
#define COMMON_RTC_IRQ_HANDLER RTC0_IRQHandler
|
||||||
|
#define COMMON_RTC_IRQN RTC0_IRQn
|
||||||
#define OS_TICK_CC_CHANNEL 0
|
#define OS_TICK_CC_CHANNEL 0
|
||||||
#define LP_TICKER_CC_CHANNEL 1
|
#define LP_TICKER_CC_CHANNEL 1
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
#include "nrf_soc.h"
|
#include "nrf_soc.h"
|
||||||
#include "nrf_timer.h"
|
#include "nrf_timer.h"
|
||||||
#include "us_ticker.h"
|
#include "us_ticker.h"
|
||||||
|
#if BB_CLK_RATE_HZ == 32768 && FEATURE_BLE == 1
|
||||||
#include "bb_api.h"
|
#include "bb_api.h"
|
||||||
#include "pal_timer.h"
|
#include "pal_timer.h"
|
||||||
#include "pal_rtc.h"
|
#include "pal_rtc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SOFTDEVICE_PRESENT)
|
#if defined(SOFTDEVICE_PRESENT)
|
||||||
#include "nrf_sdh.h"
|
#include "nrf_sdh.h"
|
||||||
|
@ -41,14 +43,25 @@ extern bool us_ticker_initialized;
|
||||||
|
|
||||||
void hal_sleep(void)
|
void hal_sleep(void)
|
||||||
{
|
{
|
||||||
/* Clock management for low power mode. */
|
// Trigger an event when an interrupt is pending. This allows to wake up
|
||||||
#if BB_CLK_RATE_HZ == 32768
|
// 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;
|
uint32_t rtcNow = NRF_RTC1->COUNTER;
|
||||||
|
|
||||||
if ((BbGetCurrentBod() == NULL))
|
if ((BbGetCurrentBod() == NULL))
|
||||||
{
|
{
|
||||||
if ((PalTimerGetState() == PAL_TIMER_STATE_BUSY &&
|
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))
|
(PalTimerGetState() == PAL_TIMER_STATE_READY))
|
||||||
{
|
{
|
||||||
/* disable HFCLK */
|
/* disable HFCLK */
|
||||||
|
@ -60,7 +73,33 @@ void hal_sleep(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NRF_POWER->TASKS_LOWPWR = 1;
|
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)
|
void hal_deepsleep(void)
|
||||||
|
|
Loading…
Reference in New Issue