Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
Diff: targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c
- Revision:
- 174:b96e65c34a4d
- Parent:
- 169:e3b6fe271b81
diff -r e131a1973e81 -r b96e65c34a4d targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c --- a/targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c Fri Sep 15 14:59:18 2017 +0100 +++ b/targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c Mon Oct 02 15:33:19 2017 +0100 @@ -271,6 +271,14 @@ US_TICKER_CC_CHANNEL, US_TICKER_INT_MASK); } +void us_ticker_fire_interrupt(void) +{ + uint32_t closest_safe_compare = common_rtc_32bit_ticks_get() + 2; + + nrf_rtc_cc_set(COMMON_RTC_INSTANCE, US_TICKER_CC_CHANNEL, RTC_WRAP(closest_safe_compare)); + nrf_rtc_event_enable(COMMON_RTC_INSTANCE, US_TICKER_INT_MASK); +} + void us_ticker_disable_interrupt(void) { nrf_rtc_event_disable(COMMON_RTC_INSTANCE, US_TICKER_INT_MASK); @@ -291,24 +299,6 @@ #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; - -/* The Period of RTC oscillator, unit [1/RTC1_CONFIG_FREQUENCY] */ -static uint32_t os_rtc_period; - -/* Variable for frozen RTC1 counter value. It is used when system timer is disabled. */ -static uint32_t frozen_sub_tick = 0; - - -#ifdef MBED_CONF_RTOS_PRESENT - #include "rtx_os.h" //import osRtxInfo, SysTick_Handler() - - static inline void clear_tick_interrupt(); -#endif - #ifndef RTC1_CONFIG_FREQUENCY #define RTC1_CONFIG_FREQUENCY 32678 // [Hz] #endif @@ -317,210 +307,15 @@ void COMMON_RTC_IRQ_HANDLER(void) { - if(nrf_rtc_event_pending(COMMON_RTC_INSTANCE, OS_TICK_EVENT)) { -#ifdef MBED_CONF_RTOS_PRESENT - clear_tick_interrupt(); - // Trigger the SysTick_Handler just after exit form RTC Handler. - NVIC_SetPendingIRQ(SWI3_IRQn); - - nrf_gpio_pin_set(11); -#endif - } else { + if(!nrf_rtc_event_pending(COMMON_RTC_INSTANCE, OS_TICK_EVENT)) { common_rtc_irq_handler(); } } - -#ifdef MBED_CONF_RTOS_PRESENT -/** - * Return the next number of clock cycle needed for the next tick. - * @note This function has been carefully optimized for a systick occurring every 1000us. - */ -static uint32_t get_next_tick_cc_delta() -{ - uint32_t delta = 0; - - if (osRtxConfig.tick_freq != 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_rtc_period; - } 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() +IRQn_Type mbed_get_m0_tick_irqn() { - nrf_rtc_event_clear(COMMON_RTC_INSTANCE, OS_TICK_EVENT); - nrf_rtc_event_disable(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK); -} - -/** - * 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_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; - - // 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_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 + 1) == false) { - new_compare_value = current_counter + delta; - } - 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(); + return SWI3_IRQn; } -/** - * 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 - */ -int32_t osRtxSysTimerSetup(void) -{ - common_rtc_init(); - - os_rtc_period = (RTC1_CONFIG_FREQUENCY) / osRtxConfig.tick_freq; - - return nrf_drv_get_IRQn(COMMON_RTC_INSTANCE); -} - -// Start SysTickt timer emulation -void osRtxSysTimerEnable(void) -{ - nrf_rtc_int_enable(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK); - - uint32_t current_cnt = nrf_rtc_counter_get(COMMON_RTC_INSTANCE); - nrf_rtc_cc_set(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL, current_cnt); - register_next_tick(); - - NVIC_SetVector(SWI3_IRQn, (uint32_t)SysTick_Handler); - NVIC_SetPriority(SWI3_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Emulated Systick Interrupt */ - NVIC_EnableIRQ(SWI3_IRQn); -} - -// Stop SysTickt timer emulation -void osRtxSysTimerDisable(void) -{ - nrf_rtc_int_disable(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK); - - // RTC1 is free runing. osRtxSysTimerGetCount will return proper frozen value - // thanks to geting frozen value instead of RTC1 counter value - frozen_sub_tick = nrf_rtc_counter_get(COMMON_RTC_INSTANCE); -} - - - -/** - * 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 osRtxSysTimerAckIRQ(void) -{ - register_next_tick(); -} - -// provide a free running incremental value over the entire 32-bit range -uint32_t osRtxSysTimerGetCount(void) -{ - uint32_t current_cnt; - uint32_t sub_tick; - - if (nrf_rtc_int_is_enabled(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK)) { - // system timer is enabled - current_cnt = nrf_rtc_counter_get(COMMON_RTC_INSTANCE); - - if (current_cnt >= previous_tick_cc_value) { - //0 prev current MAX - //|------|---------|------------|----> - sub_tick = current_cnt - previous_tick_cc_value; - } else { - //0 current prev MAX - //|------|---------|------------|----> - sub_tick = MAX_RTC_COUNTER_VAL - previous_tick_cc_value + current_cnt; - } - } else { // system timer is disabled - sub_tick = frozen_sub_tick; - } - - return (os_rtc_period * osRtxInfo.kernel.tick) + sub_tick; -} - -// Timer Tick frequency -uint32_t osRtxSysTimerGetFreq (void) { - return RTC1_CONFIG_FREQUENCY; -} - -#endif // #ifdef MBED_CONF_RTOS_PRESENT - #endif // defined(TARGET_MCU_NRF51822)