From 669eaca3d6f16b58487460c73d5b59fac7bac914 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Fri, 18 Dec 2020 08:33:50 +0100 Subject: [PATCH 01/10] NRF52: Fix errata_20 Nordic documentation suggests that this needs to be done regardless of which RTC is used. --- targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c index 858813c75f..0160191768 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c @@ -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,7 +109,7 @@ __STATIC_INLINE void errata_20(void) { } } - NRF_RTC1->TASKS_STOP = 0; + COMMON_RTC_INSTANCE->TASKS_STOP = 0; #endif } From 079b9e0d0a0cb42d5477eeafd081ec60429f26f3 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Fri, 18 Dec 2020 08:39:50 +0100 Subject: [PATCH 02/10] BLE: Remove hardcoded use of external low frequency crystal oscillator If the internal RC oscillator is used it needs to be calibrated after the HF clock is started. --- .../TARGET_NRF5x/NRFCordioHCIDriver.cpp | 8 +++++++- .../TARGET_NRF5x/stack/sources/pal_rtc.c | 3 --- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp index 6e74440d23..223a2e50c0 100644 --- a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp +++ b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp @@ -260,7 +260,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 diff --git a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_rtc.c b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_rtc.c index fea87a0cb8..20d3db4ad9 100644 --- a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_rtc.c +++ b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_rtc.c @@ -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) { } From 77b599fac380d3daea39e8bb53610ca5e17dba0f Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Fri, 18 Dec 2020 12:01:17 +0100 Subject: [PATCH 03/10] NRF52: Stop RTC and shutdown timer for cordio when not in use --- .../TARGET_NRF5x/NRFCordioHCIDriver.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp index 223a2e50c0..19808e70f3 100644 --- a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp +++ b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp @@ -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; } @@ -319,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() From bc813ea302c1642546d3e8b8ddd9f5bb85271796 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Mon, 25 Jan 2021 16:12:49 +0100 Subject: [PATCH 04/10] NRF52: Add dependency on cordio --- .../TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/CMakeLists.txt b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/CMakeLists.txt index 765e1808ca..33e8e8dfb2 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/CMakeLists.txt +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/CMakeLists.txt @@ -33,3 +33,9 @@ target_sources(mbed-core us_ticker.c watchdog_api.c ) + + +target_link_libraries(mbed-core + INTERFACE + mbed-ble-cordio +) \ No newline at end of file From c246770817d8fb5b68cdc228eafc7a8db746b050 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Tue, 26 Jan 2021 08:19:40 +0100 Subject: [PATCH 05/10] NRF52: Fix bare metal builds Bare metal builds are not necessarily dependent on BLE or the Cordio stack, therefore BLE and Cordio related things should only be included when they are used. --- targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c index 3d11c54177..af2f071be6 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c @@ -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,14 @@ extern bool us_ticker_initialized; void hal_sleep(void) { - /* Clock management for low power mode. */ -#if BB_CLK_RATE_HZ == 32768 + /* 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 */ From 1cfcc5b8a490de63432f67117714ffc681250080 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Tue, 26 Jan 2021 13:21:07 +0100 Subject: [PATCH 06/10] NRF52: Add pal_rtc.c file to cmake for NRFCordioHCIDriver --- .../TARGET_NORDIC_CORDIO/TARGET_NRF5x/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/CMakeLists.txt b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/CMakeLists.txt index 29996451c0..ce5a88f10a 100644 --- a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/CMakeLists.txt +++ b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/CMakeLists.txt @@ -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 ) From 9b911ff9e144c371a2cfea922c3e753cb51cdbc2 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Wed, 27 Jan 2021 15:59:43 +0100 Subject: [PATCH 07/10] NRF52: Use COMMON_RTC macros consistently Add a COMMON_RTC_IRQN macro to abstract RTC instance away completely --- .../TARGET_NRF5x/TARGET_NRF52/common_rtc.c | 12 ++++-------- .../TARGET_NRF5x/TARGET_NRF52/common_rtc.h | 1 + 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c index 0160191768..a15f8a8d18 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.c @@ -113,8 +113,6 @@ __STATIC_INLINE void errata_20(void) #endif } -void RTC1_IRQHandler(void); - void common_rtc_init(void) { if (m_common_rtc_enabled) { @@ -129,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. @@ -157,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. diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.h b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.h index e07c59bdc2..e48eed5e11 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.h +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/common_rtc.h @@ -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 From 9256c9838f40846ff0dc58d2b5222e19250d4b20 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Fri, 5 Feb 2021 10:16:29 +0100 Subject: [PATCH 08/10] BLE: Turn off Timer0 completely after Adv for real low power operation --- .../TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_bb_ble.c | 1 + 1 file changed, 1 insertion(+) diff --git a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_bb_ble.c b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_bb_ble.c index f14748d3f7..f55e4bd53a 100644 --- a/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_bb_ble.c +++ b/connectivity/drivers/ble/FEATURE_BLE/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/stack/sources/pal_bb_ble.c @@ -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 } From c95912b6dd142ae42fb8c9a0ab22bd18893c10e3 Mon Sep 17 00:00:00 2001 From: Benjamin Bugl / EVVA Wien Date: Fri, 5 Feb 2021 11:45:41 +0100 Subject: [PATCH 09/10] NRF52: Revert some changes to hal_sleep I don't understand why they were made and I couldn't measure any difference. --- .../TARGET_NRF5x/TARGET_NRF52/sleep.c | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c index af2f071be6..ea3114555f 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c @@ -43,6 +43,21 @@ extern bool us_ticker_initialized; void hal_sleep(void) { + /* Clock management for low power mode. */ +#if BB_CLK_RATE_HZ == 32768 && FEATURE_BLE == 1 + // ensure debug is disconnected if semihost is enabled.... + + // 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; @@ -62,7 +77,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) From a44580b71c3760b0ba9898823fb73c05aabb2846 Mon Sep 17 00:00:00 2001 From: BUGL Benjamin / EVVA Wien Date: Thu, 22 Apr 2021 07:45:46 +0200 Subject: [PATCH 10/10] NRF52: Remove redundant (and unterminated) #if This is a remnant of reverting back to an older version of sleep. --- targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c index ea3114555f..e4a566f397 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/sleep.c @@ -43,10 +43,6 @@ extern bool us_ticker_initialized; void hal_sleep(void) { - /* Clock management for low power mode. */ -#if BB_CLK_RATE_HZ == 32768 && FEATURE_BLE == 1 - // ensure debug is disconnected if semihost is enabled.... - // Trigger an event when an interrupt is pending. This allows to wake up // the processor from disabled interrupts. SCB->SCR |= SCB_SCR_SEVONPEND_Msk;