mbed

Fork of mbed-dev by mbed official

Revision:
167:e84263d55307
Parent:
165:e614a9f1c9e2
Child:
169:e3b6fe271b81
--- a/targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c	Thu Jun 08 15:02:37 2017 +0100
+++ b/targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c	Wed Jun 21 17:46:44 2017 +0100
@@ -103,9 +103,6 @@
 #endif
 }
 
-#if (defined (__ICCARM__)) && defined(TARGET_MCU_NRF51822)//IAR
-__stackless __task 
-#endif
 void RTC1_IRQHandler(void);
 
 void common_rtc_init(void)
@@ -299,169 +296,70 @@
  */
 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;
+     
+
 /*
  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.
+   * osRtxConfig.tick_freq: The RTX tick frequency.
+   * osRtxInfo.kernel.tick: Count of RTX ticks.
+   
+   * SysTick_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(void)
+MBED_WEAK void SysTick_Handler(void)
 {
 }
 
 
-#if defined (__CC_ARM)         /* ARMCC Compiler */
-
-__asm void COMMON_RTC_IRQ_HANDLER(void)
-{
-    IMPORT  OS_Tick_Handler
-    IMPORT  common_rtc_irq_handler
+#ifdef MBED_CONF_RTOS_PRESENT
+    #include "rtx_os.h" //import osRtxInfo, SysTick_Handler()
+    
+    static inline void clear_tick_interrupt();
+#endif
 
-    /**
-     * 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 COMMON_RTC_IRQ_HANDLER(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}
-    ; ALIGN ;
-}
+#ifndef RTC1_CONFIG_FREQUENCY
+    #define RTC1_CONFIG_FREQUENCY    32678 // [Hz]
+#endif
 
-#elif defined (__GNUC__)        /* GNU Compiler */
+
 
-__attribute__((naked)) void COMMON_RTC_IRQ_HANDLER(void)
+void COMMON_RTC_IRQ_HANDLER(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 COMMON_RTC_IRQ_HANDLER(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"
-    );
-}
+    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);
 
-#elif defined (__ICCARM__)//IAR
-void common_rtc_irq_handler(void);
-
-__stackless __task void COMMON_RTC_IRQ_HANDLER(void)
-{
-    uint32_t temp;
-
-    __asm volatile(
-    "   ldr  %[temp], [%[reg2check]] \n"
-    "   cmp  %[temp], #0             \n"
-    "   beq  1f                      \n"
-    "   bl.w OS_Tick_Handler            \n"
-    "1:                             \n"
-    "   push {r3, lr}\n"
-    "   blx %[rtc_irq] \n"
-    "   pop {r3, pc}\n"
-
-    : /* Outputs */
-    [temp] "=&r"(temp)
-    : /* Inputs */
-    [reg2check] "r"(0x40011144),
-    [rtc_irq] "r"(common_rtc_irq_handler)
-    : /* Clobbers */
-    "cc"
-    );
-    (void)temp;
+        nrf_gpio_pin_set(11);
+#endif
+    } else {
+        common_rtc_irq_handler();
+    }
 }
 
 
-#else
-
-#error Compiler not supported.
-#error Provide a definition of 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
- * will never been dequeued. After a certain time a stack overflow will happen.
- *
- * \code
- * void COMMON_RTC_IRQ_HANDLER(void) {
-     if(NRF_RTC1->EVENTS_COMPARE[1]) {
-         // never return...
-         OS_Tick_Handler();
-     } else {
-         common_rtc_irq_handler();
-     }
-   }
- * \endcode
- */
-
-#endif
-
+#ifdef MBED_CONF_RTOS_PRESENT
 /**
  * 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.
+ * @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 (os_clockrate != 1000) {
+    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_trv + 1;
+        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.
@@ -556,82 +454,89 @@
     __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)
+int32_t osRtxSysTimerSetup(void)
 {
     common_rtc_init();
-    nrf_rtc_int_enable(COMMON_RTC_INSTANCE, OS_TICK_INT_MASK);
-
-    nrf_rtc_cc_set(COMMON_RTC_INSTANCE, OS_TICK_CC_CHANNEL, 0);
-    register_next_tick();
+    
+    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 os_tick_irqack(void)
+void osRtxSysTimerAckIRQ(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)
+// provide a free running incremental value over the entire 32-bit range
+uint32_t osRtxSysTimerGetCount(void)
 {
-    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);
+    uint32_t current_cnt;
+    uint32_t sub_tick;
 
-    return is_in_wrapped_range(previous_tick_cc_value, next_tick_cc_value, current_counter) ? 0 : 1;
+    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;
 }
 
-/**
- * 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_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)) {
-        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);
-    }
-
+// Timer Tick frequency
+uint32_t osRtxSysTimerGetFreq (void) {
+    return RTC1_CONFIG_FREQUENCY;
 }
 
+#endif // #ifdef MBED_CONF_RTOS_PRESENT
+
 #endif // defined(TARGET_MCU_NRF51822)