From 601b96dde2e4695bc649f7b15f7bd46ae2b85c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C5=82=C4=85bek=2C=20Andrzej?= Date: Wed, 22 Jun 2016 14:00:30 +0200 Subject: [PATCH] Restored alternative method of RTOS tick generation for NRF51, which was undesirably removed when the new us_ticker implementation was introduced. --- .../TARGET_MCU_NRF51822/sdk/nrf_drv_config.h | 2 +- .../TARGET_MCU_NRF52832/sdk/nrf_drv_config.h | 2 +- .../{rtc_common.h => common_rtc.h} | 29 +- .../hal/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c | 25 +- .../hal/TARGET_NORDIC/TARGET_NRF5/os_tick.c | 329 ++++++++++++++++++ .../hal/TARGET_NORDIC/TARGET_NRF5/rtc_api.c | 12 +- .../sdk/drivers_nrf/rtc/nrf_drv_rtc.c | 290 --------------- .../sdk/drivers_nrf/rtc/nrf_drv_rtc.h | 325 ----------------- .../hal/TARGET_NORDIC/TARGET_NRF5/us_ticker.c | 110 +++--- 9 files changed, 435 insertions(+), 689 deletions(-) rename hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/{rtc_common.h => common_rtc.h} (51%) create mode 100644 hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/os_tick.c delete mode 100644 hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.c delete mode 100644 hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.h diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/nrf_drv_config.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/nrf_drv_config.h index 31df5d63a5..d3dc577462 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/nrf_drv_config.h +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/nrf_drv_config.h @@ -138,7 +138,7 @@ #define RTC0_INSTANCE_INDEX 0 #endif -#define RTC1_ENABLED 1 +#define RTC1_ENABLED 0 #if (RTC1_ENABLED == 1) #define RTC1_CONFIG_FREQUENCY 32768 diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/sdk/nrf_drv_config.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/sdk/nrf_drv_config.h index bdf509e0a5..3fb5149d3c 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/sdk/nrf_drv_config.h +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/sdk/nrf_drv_config.h @@ -138,7 +138,7 @@ #define RTC0_INSTANCE_INDEX 0 #endif -#define RTC1_ENABLED 1 +#define RTC1_ENABLED 0 #if (RTC1_ENABLED == 1) #define RTC1_CONFIG_FREQUENCY 32768 diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_common.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/common_rtc.h similarity index 51% rename from hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_common.h rename to hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/common_rtc.h index 43ec5ff512..789427c692 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_common.h +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/common_rtc.h @@ -14,21 +14,26 @@ * limitations under the License. */ -#ifndef RTC_COMMON_H -#define RTC_COMMON_H +#ifndef COMMON_RTC_H +#define COMMON_RTC_H -#include "nrf_drv_rtc.h" +#include "nrf_rtc.h" -#define RTC_COUNTER_BITS 24 +#define RTC_COUNTER_BITS 24u -#define LP_TICKER_CC_CHANNEL 0 -#define US_TICKER_CC_CHANNEL 1 +// Instance 0 is reserved for SoftDevice. +// Instance 1 is used as a common one for us_ticker, lp_ticker and (in case +// of NRF51) as an alternative tick source for RTOS. +#define COMMON_RTC_INSTANCE NRF_RTC1 -extern nrf_drv_rtc_t const m_rtc_common; -extern bool m_rtc_common_enabled; -extern uint32_t volatile m_rtc_common_overflows; +#define US_TICKER_CC_CHANNEL 0 +#define OS_TICK_CC_CHANNEL 1 +#define LP_TICKER_CC_CHANNEL 2 -void rtc_common_init(void); -uint32_t rtc_common_32bit_ticks_get(void); +extern bool m_common_rtc_enabled; +extern uint32_t volatile m_common_rtc_overflows; -#endif // RTC_COMMON_H +void common_rtc_init(void); +uint32_t common_rtc_32bit_ticks_get(void); + +#endif // COMMON_RTC_H diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c index ca292114ea..4a928b79f4 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c @@ -17,42 +17,37 @@ #if DEVICE_LOWPOWERTIMER -#include "rtc_common.h" +#include "common_rtc.h" #include "sleep_api.h" void lp_ticker_init(void) { - rtc_common_init(); + common_rtc_init(); } uint32_t lp_ticker_read(void) { - return rtc_common_32bit_ticks_get(); + return common_rtc_32bit_ticks_get(); } void lp_ticker_set_interrupt(uint32_t now, uint32_t time) { (void)now; - // The passed 32-bit 'time' value is wrapped properly by the driver, so it - // is usable by the 24-bit counter. - ret_code_t result = nrf_drv_rtc_cc_set(&m_rtc_common, LP_TICKER_CC_CHANNEL, - time, true); - if (result != NRF_SUCCESS) - { - MBED_ASSERT(false); - } + nrf_rtc_cc_set(COMMON_RTC_INSTANCE, LP_TICKER_CC_CHANNEL, RTC_WRAP(time)); + nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_COMPARE_2); + nrf_rtc_event_enable(COMMON_RTC_INSTANCE, NRF_RTC_INT_COMPARE2_MASK); } uint32_t lp_ticker_get_overflows_counter(void) { - // Cut out the part of 'm_rtc_common_overflows' used by - // 'rtc_common_32bit_ticks_get()'. - return (m_rtc_common_overflows >> (32 - RTC_COUNTER_BITS)); + // Cut out the part of 'm_common_rtc_overflows' used by + // 'common_rtc_32bit_ticks_get()'. + return (m_common_rtc_overflows >> (32u - RTC_COUNTER_BITS)); } uint32_t lp_ticker_get_compare_match(void) { - return nrf_rtc_cc_get(m_rtc_common.p_reg, LP_TICKER_CC_CHANNEL); + return nrf_rtc_cc_get(COMMON_RTC_INSTANCE, LP_TICKER_CC_CHANNEL); } void lp_ticker_sleep_until(uint32_t now, uint32_t time) diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/os_tick.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/os_tick.c new file mode 100644 index 0000000000..3b4a51f25c --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/os_tick.c @@ -0,0 +1,329 @@ +/* mbed Microcontroller Library + * Copyright (c) 2013 Nordic Semiconductor + * + * 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. + */ +#if defined(TARGET_MCU_NRF51822) + +#include "common_rtc.h" +#include "toolchain.h" +#include "nrf_delay.h" + + +#define MAX_RTC_COUNTER_VAL ((1uL << RTC_COUNTER_BITS) - 1) + +/** + * The value previously set in the capture compare register of channel 1 + */ +static uint32_t previous_tick_cc_value = 0; + +/* + RTX provide the following definitions which are used by the tick code: + * os_trv: The number (minus 1) of clock cycle between two tick. + * os_clockrate: Time duration between two ticks (in us). + * OS_Tick_Handler: The function which handle a tick event. + This function is special because it never returns. + Those definitions are used by the code which handle the os tick. + To allow compilation of us_ticker programs without RTOS, those symbols are + exported from this module as weak ones. + */ +MBED_WEAK uint32_t const os_trv; +MBED_WEAK uint32_t const os_clockrate; +MBED_WEAK void OS_Tick_Handler() { } + + +#if defined (__CC_ARM) /* ARMCC Compiler */ + +__asm void RTC1_IRQHandler(void) +{ + IMPORT OS_Tick_Handler + IMPORT common_rtc_irq_handler + + /** + * Chanel 1 of RTC1 is used by RTX as a systick. + * If the compare event on channel 1 is set, then branch to OS_Tick_Handler. + * Otherwise, just execute common_rtc_irq_handler. + * This function has to be written in assembly and tagged as naked because OS_Tick_Handler + * will never return. + * A c function would put lr on the stack before calling OS_Tick_Handler and this value + * would never been dequeued. + * + * \code + * void RTC1_IRQHandler(void) { + if(NRF_RTC1->EVENTS_COMPARE[1]) { + // never return... + OS_Tick_Handler(); + } else { + common_rtc_irq_handler(); + } + } + * \endcode + */ + ldr r0,=0x40011144 + ldr r1, [r0, #0] + cmp r1, #0 + beq US_TICKER_HANDLER + bl OS_Tick_Handler +US_TICKER_HANDLER + push {r3, lr} + bl common_rtc_irq_handler + pop {r3, pc} + nop /* padding */ +} + +#elif defined (__GNUC__) /* GNU Compiler */ + +__attribute__((naked)) void RTC1_IRQHandler(void) +{ + /** + * Chanel 1 of RTC1 is used by RTX as a systick. + * If the compare event on channel 1 is set, then branch to OS_Tick_Handler. + * Otherwise, just execute common_rtc_irq_handler. + * This function has to be written in assembly and tagged as naked because OS_Tick_Handler + * will never return. + * A c function would put lr on the stack before calling OS_Tick_Handler and this value + * would never been dequeued. + * + * \code + * void RTC1_IRQHandler(void) { + if(NRF_RTC1->EVENTS_COMPARE[1]) { + // never return... + OS_Tick_Handler(); + } else { + common_rtc_irq_handler(); + } + } + * \endcode + */ + __asm__ ( + "ldr r0,=0x40011144\n" + "ldr r1, [r0, #0]\n" + "cmp r1, #0\n" + "beq US_TICKER_HANDLER\n" + "bl OS_Tick_Handler\n" + "US_TICKER_HANDLER:\n" + "push {r3, lr}\n" + "bl common_rtc_irq_handler\n" + "pop {r3, pc}\n" + "nop" + ); +} + +#else + +#error Compiler not supported. +#error Provide a definition of RTC1_IRQHandler. + +/* + * Chanel 1 of RTC1 is used by RTX as a systick. + * If the compare event on channel 1 is set, then branch to OS_Tick_Handler. + * Otherwise, just execute common_rtc_irq_handler. + * This function has to be written in assembly and tagged as naked because OS_Tick_Handler + * will never return. + * A c function would put lr on the stack before calling OS_Tick_Handler and this value + * will never been dequeued. After a certain time a stack overflow will happen. + * + * \code + * void RTC1_IRQHandler(void) { + if(NRF_RTC1->EVENTS_COMPARE[1]) { + // never return... + OS_Tick_Handler(); + } else { + common_rtc_irq_handler(); + } + } + * \endcode + */ + +#endif + +/** + * Return the next number of clock cycle needed for the next tick. + * @note This function has been carrefuly optimized for a systick occuring every 1000us. + */ +static uint32_t get_next_tick_cc_delta() { + uint32_t delta = 0; + + if (os_clockrate != 1000) { + // In RTX, by default SYSTICK is is used. + // A tick event is generated every os_trv + 1 clock cycles of the system timer. + delta = os_trv + 1; + } else { + // If the clockrate is set to 1000us then 1000 tick should happen every second. + // Unfortunatelly, when clockrate is set to 1000, os_trv is equal to 31. + // If (os_trv + 1) is used as the delta value between two ticks, 1000 ticks will be + // generated in 32000 clock cycle instead of 32768 clock cycles. + // As a result, if a user schedule an OS timer to start in 100s, the timer will start + // instead after 97.656s + // The code below fix this issue, a clock rate of 1000s will generate 1000 ticks in 32768 + // clock cycles. + // The strategy is simple, for 1000 ticks: + // * 768 ticks will occur 33 clock cycles after the previous tick + // * 232 ticks will occur 32 clock cycles after the previous tick + // By default every delta is equal to 33. + // Every five ticks (20%, 200 delta in one second), the delta is equal to 32 + // The remaining (32) deltas equal to 32 are distributed using primes numbers. + static uint32_t counter = 0; + if ((counter % 5) == 0 || (counter % 31) == 0 || (counter % 139) == 0 || (counter == 503)) { + delta = 32; + } else { + delta = 33; + } + ++counter; + if (counter == 1000) { + counter = 0; + } + } + return delta; +} + +static inline void clear_tick_interrupt() { + NRF_RTC1->EVENTS_COMPARE[1] = 0; + NRF_RTC1->EVTENCLR = (1 << 17); +} + +/** + * Indicate if a value is included in a range which can be wrapped. + * @param begin start of the range + * @param end end of the range + * @param val value to check + * @return true if the value is included in the range and false otherwise. + */ +static inline bool is_in_wrapped_range(uint32_t begin, uint32_t end, uint32_t val) { + // regular case, begin < end + // return true if begin <= val < end + if (begin < end) { + if (begin <= val && val < end) { + return true; + } else { + return false; + } + } else { + // In this case end < begin because it has wrap around the limits + // return false if end < val < begin + if (end < val && val < begin) { + return false; + } else { + return true; + } + } + +} + +/** + * Register the next tick. + */ +static void register_next_tick() { + previous_tick_cc_value = NRF_RTC1->CC[1]; + uint32_t delta = get_next_tick_cc_delta(); + uint32_t new_compare_value = (previous_tick_cc_value + delta) & MAX_RTC_COUNTER_VAL; + + // Disable irq directly for few cycles, + // Validation of the new CC value against the COUNTER, + // Setting the new CC value and enabling CC IRQ should be an atomic operation + // Otherwise, there is a possibility to set an invalid CC value because + // the RTC1 keeps running. + // This code is very short 20-38 cycles in the worst case, it shouldn't + // disturb softdevice. + __disable_irq(); + uint32_t current_counter = NRF_RTC1->COUNTER; + + // If an overflow occur, set the next tick in COUNTER + delta clock cycles + if (is_in_wrapped_range(previous_tick_cc_value, new_compare_value, current_counter) == false) { + new_compare_value = current_counter + delta; + } + NRF_RTC1->CC[1] = new_compare_value; + + // set the interrupt of CC channel 1 and reenable IRQs + NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE1_Msk; + __enable_irq(); +} + +/** + * Initialize alternative hardware timer as RTX kernel timer + * This function is directly called by RTX. + * @note this function shouldn't be called directly. + * @return IRQ number of the alternative hardware timer + */ +int os_tick_init (void) +{ + common_rtc_init(); + + NRF_RTC1->CC[1] = 0; + clear_tick_interrupt(); + register_next_tick(); + + return RTC1_IRQn; +} + +/** + * Acknowledge the tick interrupt. + * This function is called by the function OS_Tick_Handler of RTX. + * @note this function shouldn't be called directly. + */ +void os_tick_irqack(void) +{ + clear_tick_interrupt(); + register_next_tick(); +} + +/** + * Returns the overflow flag of the alternative hardware timer. + * @note This function is exposed by RTX kernel. + * @return 1 if the timer has overflowed and 0 otherwise. + */ +uint32_t os_tick_ovf(void) { + uint32_t current_counter = NRF_RTC1->COUNTER; + uint32_t next_tick_cc_value = NRF_RTC1->CC[1]; + + return is_in_wrapped_range(previous_tick_cc_value, next_tick_cc_value, current_counter) ? 0 : 1; +} + +/** + * Return the value of the alternative hardware timer. + * @note The documentation is not very clear about what is expected as a result, + * is it an ascending counter, a descending one ? + * None of this is specified. + * The default systick is a descending counter and this function return values in + * descending order, even if the internal counter used is an ascending one. + * @return the value of the alternative hardware timer. + */ +uint32_t os_tick_val(void) { + uint32_t current_counter = NRF_RTC1->COUNTER; + uint32_t next_tick_cc_value = NRF_RTC1->CC[1]; + + // do not use os_tick_ovf because its counter value can be different + if(is_in_wrapped_range(previous_tick_cc_value, next_tick_cc_value, current_counter)) { + if (next_tick_cc_value > previous_tick_cc_value) { + return next_tick_cc_value - current_counter; + } else if(current_counter <= next_tick_cc_value) { + return next_tick_cc_value - current_counter; + } else { + return next_tick_cc_value + (MAX_RTC_COUNTER_VAL - current_counter); + } + } else { + // use (os_trv + 1) has the base step, can be totally inacurate ... + uint32_t clock_cycles_by_tick = os_trv + 1; + + // if current counter has wrap arround, add the limit to it. + if (current_counter < next_tick_cc_value) { + current_counter = current_counter + MAX_RTC_COUNTER_VAL; + } + + return clock_cycles_by_tick - ((current_counter - next_tick_cc_value) % clock_cycles_by_tick); + } + + return 0; +} + +#endif // defined(TARGET_MCU_NRF51822) diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_api.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_api.c index 4792335375..cf37709ee3 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_api.c +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/rtc_api.c @@ -17,7 +17,7 @@ #if DEVICE_RTC -#include "rtc_common.h" +#include "common_rtc.h" #include "nrf_drv_clock.h" #include "app_util_platform.h" @@ -25,7 +25,7 @@ static time_t m_time_base; void rtc_init(void) { - rtc_common_init(); + common_rtc_init(); } void rtc_free(void) @@ -37,16 +37,16 @@ void rtc_free(void) int rtc_isenabled(void) { - return m_rtc_common_enabled; + return m_common_rtc_enabled; } static uint32_t rtc_seconds_get(void) { // Convert current counter value to seconds. - uint32_t seconds = nrf_drv_rtc_counter_get(&m_rtc_common) / RTC_INPUT_FREQ; + uint32_t seconds = nrf_rtc_counter_get(COMMON_RTC_INSTANCE) / RTC_INPUT_FREQ; // Add proper amount of seconds for each registered overflow of the counter. - uint32_t seconds_per_overflow = (1 << RTC_COUNTER_BITS) / RTC_INPUT_FREQ; - return (seconds + (m_rtc_common_overflows * seconds_per_overflow)); + uint32_t seconds_per_overflow = (1uL << RTC_COUNTER_BITS) / RTC_INPUT_FREQ; + return (seconds + (m_common_rtc_overflows * seconds_per_overflow)); } time_t rtc_read(void) diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.c deleted file mode 100644 index 0af7ad3204..0000000000 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.c +++ /dev/null @@ -1,290 +0,0 @@ -/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. - * - * The information contained herein is property of Nordic Semiconductor ASA. - * Terms and conditions of usage are described in detail in NORDIC - * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. - * - * Licensees are granted free, non-transferable use of the information. NO - * WARRANTY of ANY KIND is provided. This heading must NOT be removed from - * the file. - * - */ - -#include "nrf_drv_rtc.h" -#include "nrf_rtc.h" -#include "nrf_assert.h" -#include "app_util_platform.h" - -/**@brief RTC driver instance control block structure. */ -typedef struct -{ - nrf_drv_state_t state; /**< Instance state. */ - bool reliable; /**< Reliable mode flag. */ - uint8_t tick_latency; /**< Maximum length of interrupt handler in ticks (max 7.7 ms). */ -} nrf_drv_rtc_cb_t; - -// User callbacks local storage. -static nrf_drv_rtc_handler_t m_handlers[RTC_COUNT]; -static nrf_drv_rtc_cb_t m_cb[RTC_COUNT]; - -static const nrf_drv_rtc_config_t m_default_config[] = { -#if RTC0_ENABLED - NRF_DRV_RTC_DEFAULT_CONFIG(0), -#endif -#if RTC1_ENABLED - NRF_DRV_RTC_DEFAULT_CONFIG(1), -#endif -#if RTC2_ENABLED - NRF_DRV_RTC_DEFAULT_CONFIG(2) -#endif -}; - -ret_code_t nrf_drv_rtc_init(nrf_drv_rtc_t const * const p_instance, - nrf_drv_rtc_config_t const * p_config, - nrf_drv_rtc_handler_t handler) -{ - if (handler) - { - m_handlers[p_instance->instance_id] = handler; - } - else - { - return NRF_ERROR_INVALID_PARAM; - } - - if (p_config == NULL) - { - p_config = &m_default_config[p_instance->instance_id]; - } - - if (m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED) - { - return NRF_ERROR_INVALID_STATE; - } - - nrf_drv_common_irq_enable(p_instance->irq, p_config->interrupt_priority); - nrf_rtc_prescaler_set(p_instance->p_reg, p_config->prescaler); - m_cb[p_instance->instance_id].reliable = p_config->reliable; - m_cb[p_instance->instance_id].tick_latency = p_config->tick_latency; - m_cb[p_instance->instance_id].state = NRF_DRV_STATE_INITIALIZED; - - return NRF_SUCCESS; -} - -void nrf_drv_rtc_uninit(nrf_drv_rtc_t const * const p_instance) -{ - uint32_t mask = NRF_RTC_INT_TICK_MASK | - NRF_RTC_INT_OVERFLOW_MASK | - NRF_RTC_INT_COMPARE0_MASK | - NRF_RTC_INT_COMPARE1_MASK | - NRF_RTC_INT_COMPARE2_MASK | - NRF_RTC_INT_COMPARE3_MASK; - ASSERT(m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED); - - nrf_drv_common_irq_disable(p_instance->irq); - - nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP); - nrf_rtc_event_disable(p_instance->p_reg, mask); - nrf_rtc_int_disable(p_instance->p_reg, mask); - - m_cb[p_instance->instance_id].state = NRF_DRV_STATE_UNINITIALIZED; -} - -void nrf_drv_rtc_enable(nrf_drv_rtc_t const * const p_instance) -{ - ASSERT(m_cb[p_instance->instance_id].state == NRF_DRV_STATE_INITIALIZED); - - nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_START); - m_cb[p_instance->instance_id].state = NRF_DRV_STATE_POWERED_ON; -} - -void nrf_drv_rtc_disable(nrf_drv_rtc_t const * const p_instance) -{ - ASSERT(m_cb[p_instance->instance_id].state == NRF_DRV_STATE_POWERED_ON); - - nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP); - m_cb[p_instance->instance_id].state = NRF_DRV_STATE_INITIALIZED; -} - -ret_code_t nrf_drv_rtc_cc_disable(nrf_drv_rtc_t const * const p_instance, uint32_t channel) -{ - ASSERT(m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED); - ASSERT(channelcc_channel_count); - - uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel); - nrf_rtc_event_t event = RTC_CHANNEL_EVENT_ADDR(channel); - - nrf_rtc_event_disable(p_instance->p_reg,int_mask); - if (nrf_rtc_int_is_enabled(p_instance->p_reg,int_mask)) - { - nrf_rtc_int_disable(p_instance->p_reg,int_mask); - if (nrf_rtc_event_pending(p_instance->p_reg,event)) - { - nrf_rtc_event_clear(p_instance->p_reg,event); - return NRF_ERROR_TIMEOUT; - } - } - return NRF_SUCCESS; -} - -ret_code_t nrf_drv_rtc_cc_set(nrf_drv_rtc_t const * const p_instance, - uint32_t channel, - uint32_t val, - bool enable_irq) -{ - ASSERT(m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED); - ASSERT(channelcc_channel_count); - - uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel); - nrf_rtc_event_t event = RTC_CHANNEL_EVENT_ADDR(channel); - - nrf_rtc_event_disable(p_instance->p_reg, int_mask); - nrf_rtc_int_disable(p_instance->p_reg, int_mask); - - val = RTC_WRAP(val); - if (m_cb[p_instance->instance_id].reliable) - { - nrf_rtc_cc_set(p_instance->p_reg,channel,val); - uint32_t cnt = nrf_rtc_counter_get(p_instance->p_reg); - int32_t diff = cnt - val; - if (cnt < val) - { - diff += RTC_COUNTER_COUNTER_Msk; - } - if (diff < m_cb[p_instance->instance_id].tick_latency) - { - return NRF_ERROR_TIMEOUT; - } - } - else - { - nrf_rtc_cc_set(p_instance->p_reg,channel,val); - } - - if (enable_irq) - { - nrf_rtc_event_clear(p_instance->p_reg,event); - nrf_rtc_int_enable(p_instance->p_reg, int_mask); - } - nrf_rtc_event_enable(p_instance->p_reg,int_mask); - - return NRF_SUCCESS; -} - -void nrf_drv_rtc_tick_enable(nrf_drv_rtc_t const * const p_instance, bool enable_irq) -{ - nrf_rtc_event_t event = NRF_RTC_EVENT_TICK; - uint32_t mask = NRF_RTC_INT_TICK_MASK; - - nrf_rtc_event_clear(p_instance->p_reg, event); - nrf_rtc_event_enable(p_instance->p_reg, mask); - if (enable_irq) - { - nrf_rtc_int_enable(p_instance->p_reg, mask); - } -} - -void nrf_drv_rtc_tick_disable(nrf_drv_rtc_t const * const p_instance) -{ - uint32_t mask = NRF_RTC_INT_TICK_MASK; - - nrf_rtc_event_disable(p_instance->p_reg, mask); - nrf_rtc_int_disable(p_instance->p_reg, mask); -} - -void nrf_drv_rtc_overflow_enable(nrf_drv_rtc_t const * const p_instance, bool enable_irq) -{ - nrf_rtc_event_t event = NRF_RTC_EVENT_OVERFLOW; - uint32_t mask = NRF_RTC_INT_OVERFLOW_MASK; - - nrf_rtc_event_clear(p_instance->p_reg, event); - nrf_rtc_event_enable(p_instance->p_reg, mask); - if (enable_irq) - { - nrf_rtc_int_enable(p_instance->p_reg, mask); - } -} -void nrf_drv_rtc_overflow_disable(nrf_drv_rtc_t const * const p_instance) -{ - uint32_t mask = NRF_RTC_INT_OVERFLOW_MASK; - nrf_rtc_event_disable(p_instance->p_reg, mask); - nrf_rtc_int_disable(p_instance->p_reg, mask); -} - -uint32_t nrf_drv_rtc_max_ticks_get(nrf_drv_rtc_t const * const p_instance) -{ - ASSERT(m_cb[p_instance->instance_id].reliable); - uint32_t ticks; - if (m_cb[p_instance->instance_id].reliable) - { - ticks = RTC_COUNTER_COUNTER_Msk - m_cb[p_instance->instance_id].tick_latency; - } - else - { - ticks = RTC_COUNTER_COUNTER_Msk; - } - return ticks; -} - -/**@brief Generic function for handling RTC interrupt - * - * @param[in] p_reg Pointer to instance register structure. - * @param[in] instance_id Index of instance. - */ -__STATIC_INLINE void nrf_drv_rtc_int_handler(NRF_RTC_Type * p_reg, - uint32_t instance_id, - uint32_t channel_count) -{ - uint32_t i; - uint32_t int_mask = (uint32_t)NRF_RTC_INT_COMPARE0_MASK; - nrf_rtc_event_t event = NRF_RTC_EVENT_COMPARE_0; - - for (i = 0; i < channel_count; i++) - { - if (nrf_rtc_int_is_enabled(p_reg,int_mask) && nrf_rtc_event_pending(p_reg,event)) - { - nrf_rtc_event_disable(p_reg,int_mask); - nrf_rtc_int_disable(p_reg,int_mask); - nrf_rtc_event_clear(p_reg,event); - m_handlers[instance_id]((nrf_drv_rtc_int_type_t)i); - } - int_mask <<= 1; - event = (nrf_rtc_event_t)((uint32_t)event + sizeof(uint32_t)); - } - event = NRF_RTC_EVENT_TICK; - if (nrf_rtc_int_is_enabled(p_reg,NRF_RTC_INT_TICK_MASK) && - nrf_rtc_event_pending(p_reg, event)) - { - nrf_rtc_event_clear(p_reg, event); - m_handlers[instance_id](NRF_DRV_RTC_INT_TICK); - } - - event = NRF_RTC_EVENT_OVERFLOW; - if (nrf_rtc_int_is_enabled(p_reg,NRF_RTC_INT_OVERFLOW_MASK) && - nrf_rtc_event_pending(p_reg, event)) - { - nrf_rtc_event_clear(p_reg,event); - m_handlers[instance_id](NRF_DRV_RTC_INT_OVERFLOW); - } -} - -#if RTC0_ENABLED -void RTC0_IRQHandler(void) -{ - nrf_drv_rtc_int_handler(NRF_RTC0,RTC0_INSTANCE_INDEX, NRF_RTC_CC_CHANNEL_COUNT(0)); -} -#endif - -#if RTC1_ENABLED -void RTC1_IRQHandler(void) -{ - nrf_drv_rtc_int_handler(NRF_RTC1,RTC1_INSTANCE_INDEX, NRF_RTC_CC_CHANNEL_COUNT(1)); -} -#endif - -#if RTC2_ENABLED -void RTC2_IRQHandler(void) -{ - nrf_drv_rtc_int_handler(NRF_RTC2,RTC2_INSTANCE_INDEX, NRF_RTC_CC_CHANNEL_COUNT(2)); -} -#endif diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.h deleted file mode 100644 index c7148c89c6..0000000000 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/rtc/nrf_drv_rtc.h +++ /dev/null @@ -1,325 +0,0 @@ -/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. - * - * The information contained herein is property of Nordic Semiconductor ASA. - * Terms and conditions of usage are described in detail in NORDIC - * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. - * - * Licensees are granted free, non-transferable use of the information. NO - * WARRANTY of ANY KIND is provided. This heading must NOT be removed from - * the file. - * - */ - -#ifndef NRF_DRV_RTC_H -#define NRF_DRV_RTC_H - - -#include "nordic_common.h" -#include "nrf_drv_config.h" -#include "nrf_drv_common.h" -#include "nrf_rtc.h" -#include "sdk_errors.h" - -/** - * @addtogroup nrf_rtc RTC HAL and driver - * @ingroup nrf_drivers - * @brief Real timer counter (RTC) APIs. - * @details The RTC HAL provides basic APIs for accessing the registers of the real time counter (RTC). - * The RTC driver provides APIs on a higher level. - * - * @defgroup nrf_drv_rtc RTC driver - * @{ - * @ingroup nrf_rtc - * @brief Real timer counter (RTC) driver. - */ - -/**@brief Macro to convert microseconds into ticks. */ -#define RTC_US_TO_TICKS(us,freq) ((us*freq)/1000000) - -/** - * @enum nrf_drv_rtc_int_type_t - * @brief RTC driver interrupt types. - */ -typedef enum -{ - NRF_DRV_RTC_INT_COMPARE0 = 0, /**< Interrupt from COMPARE0 event. */ - NRF_DRV_RTC_INT_COMPARE1 = 1, /**< Interrupt from COMPARE1 event. */ - NRF_DRV_RTC_INT_COMPARE2 = 2, /**< Interrupt from COMPARE2 event. */ - NRF_DRV_RTC_INT_COMPARE3 = 3, /**< Interrupt from COMPARE3 event. */ - NRF_DRV_RTC_INT_TICK = 4, /**< Interrupt from TICK event. */ - NRF_DRV_RTC_INT_OVERFLOW = 5 /**< Interrupt from OVERFLOW event. */ -} nrf_drv_rtc_int_type_t; - -/**@brief RTC driver instance structure. */ -typedef struct -{ - NRF_RTC_Type * p_reg; /**< Pointer to instance register set. */ - IRQn_Type irq; /**< Instance IRQ ID. */ - uint8_t instance_id; /**< Instance index. */ - uint8_t cc_channel_count; /**< Number of capture/compare channels. */ -} nrf_drv_rtc_t; - -/**@brief Macro for creating RTC driver instance.*/ -#define NRF_DRV_RTC_INSTANCE(id) \ -{ \ - .p_reg = CONCAT_2(NRF_RTC, id), \ - .irq = CONCAT_3(RTC, id, _IRQn), \ - .instance_id = CONCAT_3(RTC, id, _INSTANCE_INDEX),\ - .cc_channel_count = NRF_RTC_CC_CHANNEL_COUNT(id), \ -} - -/**@brief RTC driver instance configuration structure. */ -typedef struct -{ - uint16_t prescaler; /**< Prescaler. */ - uint8_t interrupt_priority; /**< Interrupt priority. */ - uint8_t tick_latency; /**< Maximum length of interrupt handler in ticks (max 7.7 ms). */ - bool reliable; /**< Reliable mode flag. */ -} nrf_drv_rtc_config_t; - -/**@brief RTC instance default configuration. */ -#define NRF_DRV_RTC_DEFAULT_CONFIG(id) \ -{ \ - .prescaler = (uint16_t)(RTC_INPUT_FREQ / CONCAT_3(RTC, id, _CONFIG_FREQUENCY))-1, \ - .interrupt_priority = CONCAT_3(RTC, id, _CONFIG_IRQ_PRIORITY), \ - .reliable = CONCAT_3(RTC, id, _CONFIG_RELIABLE), \ - .tick_latency = RTC_US_TO_TICKS(NRF_MAXIMUM_LATENCY_US, CONCAT_3(RTC, id, _CONFIG_FREQUENCY)), \ -} - -/**@brief RTC driver instance handler type. */ -typedef void (*nrf_drv_rtc_handler_t)(nrf_drv_rtc_int_type_t int_type); - -/**@brief Function for initializing the RTC driver instance. - * - * After initialization, the instance is in power off state. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] p_config Initial configuration. Default configuration used if NULL. - * @param[in] handler User's event handler. - * - * @retval NRF_SUCCESS If successfully initialized. - * @retval NRF_ERROR_INVALID_PARAM If no handler was provided. - * @retval NRF_ERROR_INVALID_STATE If the instance is already initialized. - */ -ret_code_t nrf_drv_rtc_init(nrf_drv_rtc_t const * const p_instance, - nrf_drv_rtc_config_t const * p_config, - nrf_drv_rtc_handler_t handler); - -/**@brief Function for uninitializing the RTC driver instance. - * - * After uninitialization, the instance is in idle state. The hardware should return to the state - * before initialization. The function asserts if the instance is in idle state. - * - * @param[in] p_instance Pointer to the instance. - */ -void nrf_drv_rtc_uninit(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for enabling the RTC driver instance. - * - * @note Function asserts if instance is enabled. - * - * @param[in] p_instance Pointer to the instance. - */ -void nrf_drv_rtc_enable(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for disabling the RTC driver instance. - * - * @note Function asserts if instance is disabled. - * - * @param[in] p_instance Pointer to instance. - */ -void nrf_drv_rtc_disable(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for setting a compare channel. - * - * The function asserts if the instance is not initialized or if the channel parameter is - * wrong. The function powers on the instance if the instance was in power off state. - * - * The driver is not entering a critical section when configuring RTC, which means that it can be - * preempted for a certain amount of time. When the driver was preempted and the value to be set - * is short in time, there is a risk that the driver sets a compare value that is - * behind. If RTCn_CONFIG_RELIABLE is 1 for the given instance, the Reliable mode handles that case. - * However, to detect if the requested value is behind, this mode makes the following assumptions: - * - The maximum preemption time in ticks (8-bit value) is known and is less than 7.7 ms - * (for prescaler = 0, RTC frequency 32 kHz). - * - The requested absolute compare value is not bigger than (0x00FFFFFF)-tick_latency. It is - * the user's responsibility to ensure that. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] channel One of the instance's channels. - * @param[in] val Absolute value to be set in the compare register. - * @param[in] enable_irq True to enable the interrupt. False to disable the interrupt. - * - * @retval NRF_SUCCESS If the procedure was successful. - * @retval NRF_ERROR_TIMEOUT If the compare was not set because the request value is behind the current counter - * value. This error can only be reported if RTCn_CONFIG_RELIABLE = 1. - */ -ret_code_t nrf_drv_rtc_cc_set(nrf_drv_rtc_t const * const p_instance, - uint32_t channel, - uint32_t val, - bool enable_irq); - -/**@brief Function for disabling a channel. - * - * This function disables channel events and channel interrupts. The function asserts if the instance is not - * initialized or if the channel parameter is wrong. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] channel One of the instance's channels. - * - * @retval NRF_SUCCESS If the procedure was successful. - * @retval NRF_ERROR_TIMEOUT If an interrupt was pending on the requested channel. - */ -ret_code_t nrf_drv_rtc_cc_disable(nrf_drv_rtc_t const * const p_instance, uint32_t channel); - -/**@brief Function for enabling tick. - * - * This function enables the tick event and optionally the interrupt. The function asserts if the instance is not - * powered on. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] enable_irq True to enable the interrupt. False to disable the interrupt. - */ -void nrf_drv_rtc_tick_enable(nrf_drv_rtc_t const * const p_instance, bool enable_irq); - -/**@brief Function for disabling tick. - * - * This function disables the tick event and interrupt. - * - * @param[in] p_instance Pointer to the instance. - */ -void nrf_drv_rtc_tick_disable(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for enabling overflow. - * - * This function enables the overflow event and optionally the interrupt. The function asserts if the instance is - * not powered on. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] enable_irq True to enable the interrupt. False to disable the interrupt. - */ -void nrf_drv_rtc_overflow_enable(nrf_drv_rtc_t const * const p_instance, bool enable_irq); - -/**@brief Function for disabling overflow. - * - * This function disables the overflow event and interrupt. - * - * @param[in] p_instance Pointer to the instance. - */ -void nrf_drv_rtc_overflow_disable(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for getting the maximum relative ticks value that can be set in the compare channel. - * - * When a SoftDevice is used, it occupies the highest level interrupt, so that the application code can be - * interrupted at any moment for a certain period of time. If Reliable mode is enabled, the provided - * maximum latency is taken into account and the return value is smaller than the RTC counter - * resolution. If Reliable mode is disabled, the return value equals the counter resolution. - * - * @param[in] p_instance Pointer to the instance. - * - * @retval ticks Maximum ticks value. - */ -uint32_t nrf_drv_rtc_max_ticks_get(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for disabling all instance interrupts. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] p_mask Pointer to the location where the mask is filled. - */ -__STATIC_INLINE void nrf_drv_rtc_int_disable(nrf_drv_rtc_t const * const p_instance, - uint32_t * p_mask); - -/**@brief Function for enabling instance interrupts. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] mask Mask of interrupts to enable. - */ -__STATIC_INLINE void nrf_drv_rtc_int_enable(nrf_drv_rtc_t const * const p_instance, uint32_t mask); - -/**@brief Function for retrieving the current counter value. - * - * This function asserts if the instance is not powered on or if p_val is NULL. - * - * @param[in] p_instance Pointer to the instance. - * - * @retval value Counter value. - */ -__STATIC_INLINE uint32_t nrf_drv_rtc_counter_get(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for clearing the counter value. - * - * This function asserts if the instance is not powered on. - * - * @param[in] p_instance Pointer to the instance. - */ -__STATIC_INLINE void nrf_drv_rtc_counter_clear(nrf_drv_rtc_t const * const p_instance); - -/**@brief Function for returning a requested task address for the RTC driver instance. - * - * This function asserts if the output pointer is NULL. The task address can be used by the PPI module. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] task One of the peripheral tasks. - * - * @retval Address of task register. - */ -__STATIC_INLINE uint32_t nrf_drv_rtc_task_address_get(nrf_drv_rtc_t const * const p_instance, - nrf_rtc_task_t task); - -/**@brief Function for returning a requested event address for the RTC driver instance. - * - * This function asserts if the output pointer is NULL. The event address can be used by the PPI module. - * - * @param[in] p_instance Pointer to the instance. - * @param[in] event One of the peripheral events. - * - * @retval Address of event register. - */ -__STATIC_INLINE uint32_t nrf_drv_rtc_event_address_get(nrf_drv_rtc_t const * const p_instance, - nrf_rtc_event_t event); -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE void nrf_drv_rtc_int_disable(nrf_drv_rtc_t const * const p_instance, - uint32_t * p_mask) -{ - *p_mask = nrf_rtc_int_get(p_instance->p_reg); - nrf_rtc_int_disable(p_instance->p_reg, NRF_RTC_INT_TICK_MASK | - NRF_RTC_INT_OVERFLOW_MASK | - NRF_RTC_INT_COMPARE0_MASK | - NRF_RTC_INT_COMPARE1_MASK | - NRF_RTC_INT_COMPARE2_MASK | - NRF_RTC_INT_COMPARE3_MASK); -} - -__STATIC_INLINE void nrf_drv_rtc_int_enable(nrf_drv_rtc_t const * const p_instance, uint32_t mask) -{ - nrf_rtc_int_enable(p_instance->p_reg, mask); -} - -__STATIC_INLINE uint32_t nrf_drv_rtc_counter_get(nrf_drv_rtc_t const * const p_instance) -{ - return nrf_rtc_counter_get(p_instance->p_reg); -} - -__STATIC_INLINE void nrf_drv_rtc_counter_clear(nrf_drv_rtc_t const * const p_instance) -{ - nrf_rtc_task_trigger(p_instance->p_reg,NRF_RTC_TASK_CLEAR); -} - -__STATIC_INLINE uint32_t nrf_drv_rtc_task_address_get(nrf_drv_rtc_t const * const p_instance, - nrf_rtc_task_t task) -{ - return nrf_rtc_task_address_get(p_instance->p_reg, task); -} - -__STATIC_INLINE uint32_t nrf_drv_rtc_event_address_get(nrf_drv_rtc_t const * const p_instance, - nrf_rtc_event_t event) -{ - return nrf_rtc_event_address_get(p_instance->p_reg, event); -} -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -/** - *@} - **/ -#endif /* NRF_DRV_RTC_H */ diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/us_ticker.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/us_ticker.c index b35670ceae..5b9050bb71 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/us_ticker.c +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/us_ticker.c @@ -14,63 +14,95 @@ * limitations under the License. */ #include "us_ticker_api.h" -#include "rtc_common.h" +#include "common_rtc.h" #include "app_util.h" //------------------------------------------------------------------------------ -// Common stuff used also by lp_ticker and rtc_api (see "rtc_common.h"). +// Common stuff used also by lp_ticker and rtc_api (see "common_rtc.h"). // #include "nrf_drv_clock.h" #include "app_util_platform.h" -nrf_drv_rtc_t const m_rtc_common = NRF_DRV_RTC_INSTANCE(1); -bool m_rtc_common_enabled = false; -uint32_t volatile m_rtc_common_overflows = 0; +bool m_common_rtc_enabled = false; +uint32_t volatile m_common_rtc_overflows = 0; -static void irq_handler(nrf_drv_rtc_int_type_t int_type) +#if defined(TARGET_MCU_NRF51822) +void common_rtc_irq_handler(void) +#else +void RTC1_IRQHandler(void) +#endif { - if (int_type == (NRF_DRV_RTC_INT_COMPARE0 + US_TICKER_CC_CHANNEL)) { + nrf_rtc_event_t event; + uint32_t int_mask; + + event = NRF_RTC_EVENT_COMPARE_0; + int_mask = NRF_RTC_INT_COMPARE0_MASK; + if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, event)) + { + nrf_rtc_event_clear(COMMON_RTC_INSTANCE, event); + nrf_rtc_event_disable(COMMON_RTC_INSTANCE, int_mask); us_ticker_irq_handler(); } - else if (int_type == NRF_DRV_RTC_INT_OVERFLOW) { - ++m_rtc_common_overflows; + +#if DEVICE_LOWPOWERTIMER + event = NRF_RTC_EVENT_COMPARE_2; + int_mask = NRF_RTC_INT_COMPARE2_MASK; + if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, event)) + { + nrf_rtc_event_clear(COMMON_RTC_INSTANCE, event); + nrf_rtc_event_disable(COMMON_RTC_INSTANCE, int_mask); + } +#endif + + event = NRF_RTC_EVENT_OVERFLOW; + if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, event)) + { + nrf_rtc_event_clear(COMMON_RTC_INSTANCE, event); + ++m_common_rtc_overflows; } } -void rtc_common_init(void) +void common_rtc_init(void) { - if (m_rtc_common_enabled) { + if (m_common_rtc_enabled) { return; } - (void)nrf_drv_clock_init(); // RTC is driven by the low frequency (32.768 kHz) clock, a proper request // must be made to have it running. - nrf_drv_clock_lfclk_request(NULL); + // Currently this clock is started in 'SystemInit' (see "system_nrf51.c" + // or "system_nrf52.c", respectively). - nrf_drv_rtc_config_t const config = { - .prescaler = 0, // no prescaling - .interrupt_priority = APP_IRQ_PRIORITY_LOW, - .reliable = false - }; - if (nrf_drv_rtc_init(&m_rtc_common, &config, irq_handler) != NRF_SUCCESS) { - MBED_ASSERT(false); // initialization failed - return; - } - nrf_drv_rtc_overflow_enable(&m_rtc_common, true); + nrf_rtc_prescaler_set(COMMON_RTC_INSTANCE, 0); - nrf_drv_rtc_enable(&m_rtc_common); - m_rtc_common_enabled = true; + nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW); + nrf_rtc_event_enable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK); + nrf_rtc_int_enable(COMMON_RTC_INSTANCE, + NRF_RTC_INT_COMPARE0_MASK | + #if defined(TARGET_MCU_NRF51822) + NRF_RTC_INT_COMPARE1_MASK | + #endif + #if DEVICE_LOWPOWERTIMER + NRF_RTC_INT_COMPARE2_MASK | + #endif + NRF_RTC_INT_OVERFLOW_MASK); + + nrf_drv_common_irq_enable(nrf_drv_get_IRQn(COMMON_RTC_INSTANCE), + APP_IRQ_PRIORITY_LOW); + + nrf_rtc_task_trigger(COMMON_RTC_INSTANCE, NRF_RTC_TASK_START); + + m_common_rtc_enabled = true; } -uint32_t rtc_common_32bit_ticks_get(void) +uint32_t common_rtc_32bit_ticks_get(void) { - uint32_t ticks = nrf_drv_rtc_counter_get(&m_rtc_common); + uint32_t ticks = nrf_rtc_counter_get(COMMON_RTC_INSTANCE); // The counter used for time measurements is less than 32 bit wide, // so its value is complemented with the number of registered overflows // of the counter. - ticks += (m_rtc_common_overflows << RTC_COUNTER_BITS); + ticks += (m_common_rtc_overflows << RTC_COUNTER_BITS); return ticks; } //------------------------------------------------------------------------------ @@ -78,12 +110,12 @@ uint32_t rtc_common_32bit_ticks_get(void) void us_ticker_init(void) { - rtc_common_init(); + common_rtc_init(); } static uint64_t us_ticker_64bit_get(void) { - uint32_t ticks = rtc_common_32bit_ticks_get(); + uint32_t ticks = common_rtc_32bit_ticks_get(); // [ticks -> microseconds] return ROUNDED_DIV(((uint64_t)ticks) * 1000000, RTC_INPUT_FREQ); } @@ -122,24 +154,24 @@ void us_ticker_set_interrupt(timestamp_t timestamp) // difference between the compare value to be set and the current counter // value is 2 ticks. This guarantees that the compare trigger is properly // setup before the compare condition occurs. - uint32_t closest_safe_compare = rtc_common_32bit_ticks_get() + 2; + uint32_t closest_safe_compare = common_rtc_32bit_ticks_get() + 2; if ((int)(compare_value - closest_safe_compare) <= 0) { compare_value = closest_safe_compare; } - ret_code_t result = nrf_drv_rtc_cc_set(&m_rtc_common, US_TICKER_CC_CHANNEL, - compare_value, true); - if (result != NRF_SUCCESS) { - MBED_ASSERT(false); - } + + nrf_rtc_cc_set(COMMON_RTC_INSTANCE, US_TICKER_CC_CHANNEL, + RTC_WRAP(compare_value)); + nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_COMPARE_0); + nrf_rtc_event_enable(COMMON_RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); } void us_ticker_disable_interrupt(void) { - nrf_drv_rtc_cc_disable(&m_rtc_common, US_TICKER_CC_CHANNEL); + nrf_rtc_event_disable(COMMON_RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); } void us_ticker_clear_interrupt(void) { - // No implementation needed. Interrupt flags are cleared by IRQ handler - // in 'nrf_drv_rtc'. + // No implementation needed. The event that triggers the interrupt is + // cleared in 'common_rtc_irq_handler'. }