You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/04/11 23:25:41 UTC

[11/28] incubator-mynewt-core git commit: Enter tickless regime during idle on NRF52.

Enter tickless regime during idle on NRF52.

'os_arch_idle(ticks)' now takes an argument to indicate how long before
the OS has anything useful to schedule. The architecture specific function
is allowed to suspend execution for up to those many ticks. Note that
this function may return earlier if another interrupt wakes up the CPU.
Note that 'ticks' may be zero in which case the CPU stays in the periodic
timer regime.

The idle stack size needed a bump to account for the increase in stack
depth.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/5b5abc88
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/5b5abc88
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/5b5abc88

Branch: refs/heads/develop
Commit: 5b5abc887e70a513a0fde8480b2f4f9daabe0d05
Parents: 8e31a9e
Author: Neel Natu <ne...@nahannisys.com>
Authored: Mon Apr 4 19:27:21 2016 -0700
Committer: Neel Natu <ne...@nahannisys.com>
Committed: Mon Apr 4 19:27:21 2016 -0700

----------------------------------------------------------------------
 hw/bsp/nrf52pdk/src/os_bsp.c                   | 89 +++++++++++++++++----
 libs/os/include/os/arch/cortex_m0/os/os_arch.h |  4 +-
 libs/os/include/os/arch/cortex_m4/os/os_arch.h |  5 +-
 libs/os/include/os/arch/sim/os/os_arch.h       |  2 +-
 libs/os/src/arch/cortex_m0/os_arch_arm.c       |  2 +-
 libs/os/src/arch/cortex_m4/os_arch_arm.c       | 11 +--
 libs/os/src/arch/sim/os_arch_sim.c             | 50 ++++++------
 libs/os/src/os.c                               | 25 +++++-
 8 files changed, 128 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/hw/bsp/nrf52pdk/src/os_bsp.c
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf52pdk/src/os_bsp.c b/hw/bsp/nrf52pdk/src/os_bsp.c
index 255f16f..f386137 100644
--- a/hw/bsp/nrf52pdk/src/os_bsp.c
+++ b/hw/bsp/nrf52pdk/src/os_bsp.c
@@ -89,52 +89,100 @@ os_bsp_init(void)
 #define CALLOUT_CMPREG      0   /* generate timer interrupt */
 #define CALLOUT_COUNTER     1   /* capture current timer value */
 #define CALLOUT_PRESCALER   4   /* prescaler to generate 1MHz timer freq */
-#define TIMER_GEQ(__t1, __t2)   ((int32_t)((__t1) - (__t2)) >= 0)
+#define TIMER_LT(__t1, __t2)    ((int32_t)((__t1) - (__t2)) < 0)
 
 static int timer_ticks_per_ostick;
+static os_time_t nrf52_max_idle_ticks;
 static uint32_t lastocmp;
 
 static inline uint32_t
 nrf52_callout_counter(void)
 {
     /*
+     * Make sure we are not interrupted between invoking the capture task
+     * and reading the value.
+     */
+    OS_ASSERT_CRITICAL();
+
+    /*
      * Capture the current timer value and return it.
      */
     CALLOUT_TIMER->TASKS_CAPTURE[CALLOUT_COUNTER] = 1;
     return (CALLOUT_TIMER->CC[CALLOUT_COUNTER]);
 }
 
+static inline void
+nrf52_callout_set_ocmp(uint32_t ocmp)
+{
+    uint32_t counter;
+
+    OS_ASSERT_CRITICAL();
+    while (1) {
+        CALLOUT_TIMER->CC[CALLOUT_CMPREG] = ocmp;
+        counter = nrf52_callout_counter();
+        if (TIMER_LT(counter, ocmp)) {
+            break;
+        }
+        ocmp += timer_ticks_per_ostick;
+    }
+}
+
 static void
 nrf52_timer_handler(void)
 {
     int ticks;
     os_sr_t sr;
-    uint32_t counter, ocmp;
-
-    assert(CALLOUT_TIMER->EVENTS_COMPARE[CALLOUT_CMPREG]);
+    uint32_t counter;
 
     OS_ENTER_CRITICAL(sr);
 
-    /* Clear interrupt */
-    CALLOUT_TIMER->EVENTS_COMPARE[CALLOUT_CMPREG] = 0;
-
-    /* Capture the timer value */
+    /*
+     * Calculate elapsed ticks and advance OS time.
+     */
     counter = nrf52_callout_counter();
-
-    /* Calculate elapsed ticks */
     ticks = (counter - lastocmp) / timer_ticks_per_ostick;
+    os_time_advance(ticks);
+
+    /* Clear timer interrupt */
+    CALLOUT_TIMER->EVENTS_COMPARE[CALLOUT_CMPREG] = 0;
+
+    /* Update the time associated with the most recent tick */
     lastocmp += ticks * timer_ticks_per_ostick;
 
-    ocmp = lastocmp;
-    do {
-        ocmp += timer_ticks_per_ostick;
-        CALLOUT_TIMER->CC[CALLOUT_CMPREG] = ocmp;
-        counter = nrf52_callout_counter();
-    } while (TIMER_GEQ(counter, ocmp));
+    /* Update the output compare to interrupt at the next tick */
+    nrf52_callout_set_ocmp(lastocmp + timer_ticks_per_ostick);
 
     OS_EXIT_CRITICAL(sr);
+}
 
-    os_time_advance(ticks);
+void
+os_bsp_idle(os_time_t ticks)
+{
+    uint32_t ocmp;
+
+    OS_ASSERT_CRITICAL();
+
+    if (ticks > 0) {
+        /*
+         * Enter tickless regime during long idle durations.
+         */
+        if (ticks > nrf52_max_idle_ticks) {
+            ticks = nrf52_max_idle_ticks;
+        }
+        ocmp = lastocmp + ticks * timer_ticks_per_ostick;
+        nrf52_callout_set_ocmp(ocmp);
+    }
+
+    __DSB();
+    __WFI();
+
+    if (ticks > 0) {
+        /*
+         * Update OS time before anything else when coming out of
+         * the tickless regime.
+         */
+        nrf52_timer_handler();
+    }
 }
 
 void
@@ -144,6 +192,13 @@ os_bsp_systick_init(uint32_t os_ticks_per_sec, int prio)
     timer_ticks_per_ostick = 1000000 / os_ticks_per_sec;
 
     /*
+     * The maximum number of timer ticks allowed to elapse during idle is
+     * limited to 1/4th the number of timer ticks before the counter rolls
+     * over.
+     */
+    nrf52_max_idle_ticks = (1UL << 30) / timer_ticks_per_ostick;
+
+    /*
      * Program CALLOUT_TIMER to operate at 1MHz and trigger an output
      * compare interrupt at a rate of 'os_ticks_per_sec'.
      */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/include/os/arch/cortex_m0/os/os_arch.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/arch/cortex_m0/os/os_arch.h b/libs/os/include/os/arch/cortex_m0/os/os_arch.h
index 23f6131..7259288 100755
--- a/libs/os/include/os/arch/cortex_m0/os/os_arch.h
+++ b/libs/os/include/os/arch/cortex_m0/os/os_arch.h
@@ -45,7 +45,7 @@ typedef uint32_t os_stack_t;
  * Stack sizes for common OS tasks
  */
 #define OS_SANITY_STACK_SIZE (64)
-#define OS_IDLE_STACK_SIZE (32)
+#define OS_IDLE_STACK_SIZE (64)
 
 #define OS_STACK_ALIGN(__nmemb) \
     (OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
@@ -69,7 +69,7 @@ os_error_t os_arch_os_start(void);
 void os_set_env(void);
 void os_arch_init_task_stack(os_stack_t *sf);
 void os_default_irq_asm(void);
-void os_arch_idle(void);
+void os_arch_idle(os_time_t ticks);
 
 /* External function prototypes supplied by BSP */
 void os_bsp_systick_init(uint32_t os_ticks_per_sec, int prio);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/include/os/arch/cortex_m4/os/os_arch.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/arch/cortex_m4/os/os_arch.h b/libs/os/include/os/arch/cortex_m4/os/os_arch.h
index ab0f95f..7b51c0d 100755
--- a/libs/os/include/os/arch/cortex_m4/os/os_arch.h
+++ b/libs/os/include/os/arch/cortex_m4/os/os_arch.h
@@ -45,7 +45,7 @@ typedef uint32_t os_stack_t;
  * Stack sizes for common OS tasks
  */
 #define OS_SANITY_STACK_SIZE (64)
-#define OS_IDLE_STACK_SIZE (32)
+#define OS_IDLE_STACK_SIZE (64)
 
 #define OS_STACK_ALIGN(__nmemb) \
     (OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
@@ -69,11 +69,12 @@ os_error_t os_arch_os_start(void);
 void os_set_env(void);
 void os_arch_init_task_stack(os_stack_t *sf);
 void os_default_irq_asm(void);
-void os_arch_idle(void);
+void os_arch_idle(os_time_t ticks);
 
 /* External function prototypes supplied by BSP */
 void os_bsp_systick_init(uint32_t os_tick_per_sec, int prio);
 void os_bsp_init(void);
+void os_bsp_idle(os_time_t ticks);
 void os_bsp_ctx_sw(void);
 
 #endif /* _OS_ARCH_X86_H */ 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/include/os/arch/sim/os/os_arch.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/arch/sim/os/os_arch.h b/libs/os/include/os/arch/sim/os/os_arch.h
index dd12cfd..4a33458 100644
--- a/libs/os/include/os/arch/sim/os/os_arch.h
+++ b/libs/os/include/os/arch/sim/os/os_arch.h
@@ -71,7 +71,7 @@ int os_arch_in_critical(void);
 os_error_t os_arch_os_init(void);
 void os_arch_os_stop(void);
 os_error_t os_arch_os_start(void);
-void os_arch_idle(void);
+void os_arch_idle(os_time_t ticks);
 
 void os_bsp_init(void);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/src/arch/cortex_m0/os_arch_arm.c
----------------------------------------------------------------------
diff --git a/libs/os/src/arch/cortex_m0/os_arch_arm.c b/libs/os/src/arch/cortex_m0/os_arch_arm.c
index 82603da..36377ba 100755
--- a/libs/os/src/arch/cortex_m0/os_arch_arm.c
+++ b/libs/os/src/arch/cortex_m0/os_arch_arm.c
@@ -334,7 +334,7 @@ os_arch_os_start(void)
 }
 
 void
-os_arch_idle(void)
+os_arch_idle(os_time_t ticks)
 {
     os_sr_t sr;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/src/arch/cortex_m4/os_arch_arm.c
----------------------------------------------------------------------
diff --git a/libs/os/src/arch/cortex_m4/os_arch_arm.c b/libs/os/src/arch/cortex_m4/os_arch_arm.c
index 5c4ad88..dc91e84 100755
--- a/libs/os/src/arch/cortex_m4/os_arch_arm.c
+++ b/libs/os/src/arch/cortex_m4/os_arch_arm.c
@@ -324,14 +324,7 @@ os_arch_os_start(void)
 }
 
 void
-os_arch_idle(void)
+os_arch_idle(os_time_t ticks)
 {
-    os_sr_t sr;
-
-    OS_ENTER_CRITICAL(sr);
-    __DSB();
-    __WFI();
-    OS_EXIT_CRITICAL(sr);
-
-    return;
+    os_bsp_idle(ticks);
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/src/arch/sim/os_arch_sim.c
----------------------------------------------------------------------
diff --git a/libs/os/src/arch/sim/os_arch_sim.c b/libs/os/src/arch/sim/os_arch_sim.c
index cb36df8..bbdc641 100644
--- a/libs/os/src/arch/sim/os_arch_sim.c
+++ b/libs/os/src/arch/sim/os_arch_sim.c
@@ -54,6 +54,7 @@ extern void os_arch_frame_init(struct stack_frame *sf);
 #define OS_USEC_PER_TICK    (1000000 / OS_TICKS_PER_SEC)
 
 static sigset_t allsigs, nosigs;
+static void timer_handler(int sig);
 
 /*
  * Called from 'os_arch_frame_init()' when setjmp returns indirectly via
@@ -176,52 +177,47 @@ os_arch_in_critical(void)
 }
 
 void
-os_arch_idle(void)
+os_arch_idle(os_time_t ticks)
 {
     int rc;
-    os_sr_t sr;
-    os_time_t now, sticks, cticks, ticks;
     struct itimerval it;
 
-    OS_ENTER_CRITICAL(sr);
-    assert(sr == 0);
+    OS_ASSERT_CRITICAL();
 
-    now = os_time_get();
-    sticks = os_sched_wakeup_ticks(now);
-    cticks = os_callout_wakeup_ticks(now);
-    ticks = min(sticks, cticks);
-    if (ticks > OS_TICKS_PER_SEC) {
+    if (ticks > 0) {
         /*
-         * Wakeup at least once a second (XXX arbitrary).
+         * Enter tickless regime and set the timer to fire after 'ticks'
+         * worth of time has elapsed.
          */
-        ticks = OS_TICKS_PER_SEC;
+        it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC;
+        it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK;
+        it.it_interval.tv_sec = 0;
+        it.it_interval.tv_usec = OS_USEC_PER_TICK;
+        rc = setitimer(ITIMER_REAL, &it, NULL);
+        assert(rc == 0);
     }
 
-    if (ticks == 0) {
+    sigsuspend(&nosigs);        /* Wait for a signal to wake us up */
+
+    if (ticks > 0) {
         /*
-         * If the wakeup time is in the past then send a SIGALRM to ourselves
-         * rather than wait for the interval timer to fire.
+         * Update OS time before anything else when coming out of
+         * the tickless regime.
          */
-        rc = kill(getpid(), SIGALRM);
-    } else {
+        timer_handler(SIGALRM);
+
         /*
-         * Set the timer to fire after 'ticks' worth of time has elapsed.
+         * Enable the periodic timer interrupt.
          */
-        it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC;
-        it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK;
+        it.it_value.tv_sec = 0;
+        it.it_value.tv_usec = OS_USEC_PER_TICK;
         it.it_interval.tv_sec = 0;
         it.it_interval.tv_usec = OS_USEC_PER_TICK;
         rc = setitimer(ITIMER_REAL, &it, NULL);
+        assert(rc == 0);
     }
-    assert(rc == 0);
-
-    sigsuspend(&nosigs);        /* Wait for a signal to wake us up */
-
-    OS_EXIT_CRITICAL(sr);
 }
 
-static void timer_handler(int sig);
-
 static struct {
     int num;
     void (*handler)(int sig);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5b5abc88/libs/os/src/os.c
----------------------------------------------------------------------
diff --git a/libs/os/src/os.c b/libs/os/src/os.c
index 078800a..4310178 100644
--- a/libs/os/src/os.c
+++ b/libs/os/src/os.c
@@ -30,14 +30,37 @@ uint32_t g_os_idle_ctr;
  */
 int g_os_started; 
 
+#ifdef ARCH_sim
+#define MIN_IDLE_TICKS  1
+#else
+#define MIN_IDLE_TICKS  (100 * OS_TICKS_PER_SEC / 1000) /* 100 msec */
+#endif
+#define MAX_IDLE_TICKS  (600 * OS_TICKS_PER_SEC)        /* 10 minutes */
 
 void
 os_idle_task(void *arg)
 {
+    os_sr_t sr;
+    os_time_t now;
+    os_time_t iticks, sticks, cticks;
+
     /* For now, idle task simply increments a counter to show it is running. */
     while (1) {
         ++g_os_idle_ctr;
-        os_arch_idle();
+        OS_ENTER_CRITICAL(sr);
+        now = os_time_get();
+        sticks = os_sched_wakeup_ticks(now);
+        cticks = os_callout_wakeup_ticks(now);
+        iticks = min(sticks, cticks);
+        if (iticks < MIN_IDLE_TICKS) {
+            iticks = 0;
+        } else if (iticks > MAX_IDLE_TICKS) {
+            iticks = MAX_IDLE_TICKS;
+        } else {
+            /* NOTHING */
+        }
+        os_arch_idle(iticks);
+        OS_EXIT_CRITICAL(sr);
     }
 }