Polished ticker related code.

pull/2234/head
Głąbek, Andrzej 2016-06-23 12:27:18 +02:00
parent ba863f4e3d
commit 1357fb0ffc
4 changed files with 78 additions and 43 deletions

View File

@ -24,12 +24,27 @@
// 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.
// ["os_tick.c" uses hard coded addresses of the 'NRF_RTC1->EVENT_COMPARE[1]'
// register in inline assembly implementations of COMMON_RTC_IRQ_HANDLER,
// please remember to update those in case of doing changes here]
#define COMMON_RTC_INSTANCE NRF_RTC1
#define COMMON_RTC_IRQ_HANDLER RTC1_IRQHandler
#define US_TICKER_CC_CHANNEL 0
#define OS_TICK_CC_CHANNEL 1
#define LP_TICKER_CC_CHANNEL 2
#define COMMON_RTC_EVENT_COMPARE(channel) \
CONCAT_2(NRF_RTC_EVENT_COMPARE_, channel)
#define COMMON_RTC_INT_COMPARE_MASK(channel) \
CONCAT_3(NRF_RTC_INT_COMPARE, channel, _MASK)
#define US_TICKER_EVENT COMMON_RTC_EVENT_COMPARE(US_TICKER_CC_CHANNEL)
#define US_TICKER_INT_MASK COMMON_RTC_INT_COMPARE_MASK(US_TICKER_CC_CHANNEL)
#define OS_TICK_EVENT COMMON_RTC_EVENT_COMPARE(OS_TICK_CC_CHANNEL)
#define OS_TICK_INT_MASK COMMON_RTC_INT_COMPARE_MASK(OS_TICK_CC_CHANNEL)
#define LP_TICKER_EVENT COMMON_RTC_EVENT_COMPARE(LP_TICKER_CC_CHANNEL)
#define LP_TICKER_INT_MASK COMMON_RTC_INT_COMPARE_MASK(LP_TICKER_CC_CHANNEL)
extern bool m_common_rtc_enabled;
extern uint32_t volatile m_common_rtc_overflows;

View File

@ -34,8 +34,7 @@ void lp_ticker_set_interrupt(uint32_t now, uint32_t time)
{
(void)now;
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);
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
}
uint32_t lp_ticker_get_overflows_counter(void)

View File

@ -17,7 +17,7 @@
#include "common_rtc.h"
#include "toolchain.h"
#include "nrf_delay.h"
#include "nrf_drv_common.h"
#define MAX_RTC_COUNTER_VAL ((1uL << RTC_COUNTER_BITS) - 1)
@ -44,7 +44,7 @@ MBED_WEAK void OS_Tick_Handler() { }
#if defined (__CC_ARM) /* ARMCC Compiler */
__asm void RTC1_IRQHandler(void)
__asm void COMMON_RTC_IRQ_HANDLER(void)
{
IMPORT OS_Tick_Handler
IMPORT common_rtc_irq_handler
@ -59,7 +59,7 @@ __asm void RTC1_IRQHandler(void)
* would never been dequeued.
*
* \code
* void RTC1_IRQHandler(void) {
* void COMMON_RTC_IRQ_HANDLER(void) {
if(NRF_RTC1->EVENTS_COMPARE[1]) {
// never return...
OS_Tick_Handler();
@ -83,7 +83,7 @@ US_TICKER_HANDLER
#elif defined (__GNUC__) /* GNU Compiler */
__attribute__((naked)) void RTC1_IRQHandler(void)
__attribute__((naked)) void COMMON_RTC_IRQ_HANDLER(void)
{
/**
* Chanel 1 of RTC1 is used by RTX as a systick.
@ -95,7 +95,7 @@ __attribute__((naked)) void RTC1_IRQHandler(void)
* would never been dequeued.
*
* \code
* void RTC1_IRQHandler(void) {
* void COMMON_RTC_IRQ_HANDLER(void) {
if(NRF_RTC1->EVENTS_COMPARE[1]) {
// never return...
OS_Tick_Handler();
@ -122,7 +122,7 @@ __attribute__((naked)) void RTC1_IRQHandler(void)
#else
#error Compiler not supported.
#error Provide a definition of RTC1_IRQHandler.
#error Provide a definition of COMMON_RTC_IRQ_HANDLER.
/*
* Chanel 1 of RTC1 is used by RTX as a systick.
@ -134,7 +134,7 @@ __attribute__((naked)) void RTC1_IRQHandler(void)
* will never been dequeued. After a certain time a stack overflow will happen.
*
* \code
* void RTC1_IRQHandler(void) {
* void COMMON_RTC_IRQ_HANDLER(void) {
if(NRF_RTC1->EVENTS_COMPARE[1]) {
// never return...
OS_Tick_Handler();
@ -188,8 +188,8 @@ static uint32_t get_next_tick_cc_delta() {
}
static inline void clear_tick_interrupt() {
NRF_RTC1->EVENTS_COMPARE[1] = 0;
NRF_RTC1->EVTENCLR = (1 << 17);
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, OS_TICK_EVENT);
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK);
}
/**
@ -224,7 +224,7 @@ static inline bool is_in_wrapped_range(uint32_t begin, uint32_t end, uint32_t va
* Register the next tick.
*/
static void register_next_tick() {
previous_tick_cc_value = NRF_RTC1->CC[1];
previous_tick_cc_value = nrf_rtc_cc_get(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL);
uint32_t delta = get_next_tick_cc_delta();
uint32_t new_compare_value = (previous_tick_cc_value + delta) & MAX_RTC_COUNTER_VAL;
@ -236,16 +236,16 @@ static void register_next_tick() {
// 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;
uint32_t current_counter = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
// 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;
nrf_rtc_cc_set(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL, new_compare_value);
// Enable generation of the compare event for the value set above (this
// event will trigger the interrupt).
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK);
__enable_irq();
}
@ -259,11 +259,10 @@ int os_tick_init (void)
{
common_rtc_init();
NRF_RTC1->CC[1] = 0;
clear_tick_interrupt();
nrf_rtc_cc_set(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL, 0);
register_next_tick();
return RTC1_IRQn;
return nrf_drv_get_IRQn(COMMON_RTC_INSTANCE);
}
/**
@ -283,8 +282,8 @@ void os_tick_irqack(void)
* @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];
uint32_t current_counter = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
uint32_t next_tick_cc_value = nrf_rtc_cc_get(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL);
return is_in_wrapped_range(previous_tick_cc_value, next_tick_cc_value, current_counter) ? 0 : 1;
}
@ -299,8 +298,8 @@ uint32_t os_tick_ovf(void) {
* @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];
uint32_t current_counter = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
uint32_t next_tick_cc_value = nrf_rtc_cc_get(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL);
// 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)) {

View File

@ -30,35 +30,35 @@ uint32_t volatile m_common_rtc_overflows = 0;
#if defined(TARGET_MCU_NRF51822)
void common_rtc_irq_handler(void)
#else
void RTC1_IRQHandler(void)
void COMMON_RTC_IRQ_HANDLER(void)
#endif
{
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))
{
event = US_TICKER_EVENT;
int_mask = US_TICKER_INT_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();
}
#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))
{
event = LP_TICKER_EVENT;
int_mask = LP_TICKER_INT_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))
{
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, event)) {
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, event);
// Don't disable this event. It shall occur periodically.
++m_common_rtc_overflows;
}
}
@ -76,18 +76,41 @@ void common_rtc_init(void)
nrf_rtc_prescaler_set(COMMON_RTC_INSTANCE, 0);
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 |
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, US_TICKER_EVENT);
#if defined(TARGET_MCU_NRF51822)
NRF_RTC_INT_COMPARE1_MASK |
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, OS_TICK_EVENT);
#endif
#if DEVICE_LOWPOWERTIMER
NRF_RTC_INT_COMPARE2_MASK |
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, LP_TICKER_EVENT);
#endif
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
// Interrupts on all related events are enabled permanently. Particular
// events will be enabled or disabled as needed (such approach is more
// energy efficient).
nrf_rtc_int_enable(COMMON_RTC_INSTANCE,
#if defined(TARGET_MCU_NRF51822)
OS_TICK_INT_MASK |
#endif
#if DEVICE_LOWPOWERTIMER
LP_TICKER_INT_MASK |
#endif
US_TICKER_INT_MASK |
NRF_RTC_INT_OVERFLOW_MASK);
// This event is enabled permanently, since overflow indications are needed
// continuously.
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
// All other relevant events are initially disabled.
nrf_rtc_event_disable(COMMON_RTC_INSTANCE,
#if defined(TARGET_MCU_NRF51822)
OS_TICK_INT_MASK |
#endif
#if DEVICE_LOWPOWERTIMER
LP_TICKER_INT_MASK |
#endif
US_TICKER_INT_MASK);
nrf_drv_common_irq_enable(nrf_drv_get_IRQn(COMMON_RTC_INSTANCE),
APP_IRQ_PRIORITY_LOW);
@ -161,13 +184,12 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
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);
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, US_TICKER_INT_MASK);
}
void us_ticker_disable_interrupt(void)
{
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK);
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, US_TICKER_INT_MASK);
}
void us_ticker_clear_interrupt(void)