Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/nrf_cputime [created] 6db66772c


First pass at low power timer. Only nrf52 right now.


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/94a59a3c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/94a59a3c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/94a59a3c

Branch: refs/heads/nrf_cputime
Commit: 94a59a3c317cd3a067d2480336b53af4cee32ff9
Parents: 0f93b4d
Author: William San Filippo <[email protected]>
Authored: Thu Feb 16 16:12:39 2017 -0800
Committer: William San Filippo <[email protected]>
Committed: Mon Feb 27 13:13:31 2017 -0800

----------------------------------------------------------------------
 hw/drivers/nimble/nrf52/include/ble/xcvr.h      |  11 +-
 hw/drivers/nimble/nrf52/src/ble_phy.c           | 408 +++++++++++++++++--
 kernel/os/include/os/os_cputime.h               |   8 +
 kernel/os/src/os_cputime.c                      |  50 +++
 .../controller/include/controller/ble_ll.h      |   5 +-
 .../controller/include/controller/ble_ll_conn.h |   5 +
 .../include/controller/ble_ll_sched.h           |  27 +-
 .../controller/include/controller/ble_phy.h     |  23 +-
 net/nimble/controller/src/ble_ll.c              |  16 +
 net/nimble/controller/src/ble_ll_adv.c          |  72 +++-
 net/nimble/controller/src/ble_ll_conn.c         | 256 ++++++++++--
 net/nimble/controller/src/ble_ll_conn_priv.h    |   3 +-
 net/nimble/controller/src/ble_ll_scan.c         |  18 +-
 net/nimble/controller/src/ble_ll_sched.c        | 246 +++++++----
 net/nimble/include/nimble/ble.h                 |   3 +
 15 files changed, 959 insertions(+), 192 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/hw/drivers/nimble/nrf52/include/ble/xcvr.h
----------------------------------------------------------------------
diff --git a/hw/drivers/nimble/nrf52/include/ble/xcvr.h 
b/hw/drivers/nimble/nrf52/include/ble/xcvr.h
index 6a35124..effe81d 100644
--- a/hw/drivers/nimble/nrf52/include/ble/xcvr.h
+++ b/hw/drivers/nimble/nrf52/include/ble/xcvr.h
@@ -25,9 +25,18 @@ extern "C" {
 #endif
 
 /* Transceiver specific definitions */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+/*
+ * NOTE: we have to account for the RTC output compare issue, which is why
+ * this number is much larger when using the 32.768 crystal for cputime. We
+ * want it to be 5 ticks.
+ */
+#define XCVR_PROC_DELAY_USECS         (153)
+#else
+#define XCVR_PROC_DELAY_USECS         (50)
+#endif
 #define XCVR_RX_START_DELAY_USECS     (140)
 #define XCVR_TX_START_DELAY_USECS     (140)
-#define XCVR_PROC_DELAY_USECS         (50)
 #define XCVR_TX_SCHED_DELAY_USECS     \
     (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
 #define XCVR_RX_SCHED_DELAY_USECS     \

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/hw/drivers/nimble/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/hw/drivers/nimble/nrf52/src/ble_phy.c 
b/hw/drivers/nimble/nrf52/src/ble_phy.c
index 8771f49..410e0dc 100644
--- a/hw/drivers/nimble/nrf52/src/ble_phy.c
+++ b/hw/drivers/nimble/nrf52/src/ble_phy.c
@@ -78,6 +78,9 @@ struct ble_phy_obj
     struct ble_mbuf_hdr rxhdr;
     void *txend_arg;
     ble_phy_tx_end_func txend_cb;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    uint32_t phy_start_cputime;
+#endif
 };
 struct ble_phy_obj g_ble_phy_data;
 
@@ -280,6 +283,102 @@ nrf_wait_disabled(void)
     }
 }
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+/**
+ *
+ *
+ */
+int
+ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+    uint32_t next_cc;
+    uint32_t cur_cc;
+    uint32_t cntr;
+    uint32_t delta;
+
+    /*
+     * XXX: The TXEN time is 140 usecs but there may be additional delays
+     * Need to look at this.
+     */
+
+    /*
+     * With the 32.768 kHz crystal, we may need to adjust the RTC compare
+     * value by 1 tick due to the time it takes for TXEN. The code uses a 5 RTC
+     * tick offset, which is 152.5 usecs. The TXEN time is 140 usecs. This
+     * means that with a remainder of 0, TIMER0 should be set to 12 or 13 (as
+     * TIMER0 counts at 1MHz). A remainder of 19 or more we will need to add
+     * 1 tick. We dont need to add 1 tick per se, but it does give us slightly
+     * more time and thus less of a chance to miss a tick. Another note: we
+     * cant set TIMER0 CC to 0 as the compare wont occur; it must be 1 or more.
+     * This is why we subtract 18 (as opposed to 19) as rem_uses will be >= 1.
+     */
+    if (rem_usecs <= 18) {
+        cputime -= 5;
+        rem_usecs += 12;
+    } else {
+        cputime -= 4;
+        rem_usecs -= 18;
+    }
+
+    /*
+     * Can we set the RTC compare to start TIMER0? We can do it if:
+     *      a) Current compare value is not N+1 or N+2 ticks from current
+     *      counter.
+     *      b) The value we want to set is not at least N+2 from current
+     *      counter.
+     *
+     * NOTE: since the counter can tick 1 while we do these calculations we
+     * need to account for it.
+     */
+    next_cc = cputime & 0xffffff;
+    cur_cc = NRF_RTC0->CC[0];
+    cntr = NRF_RTC0->COUNTER;
+
+    delta = (cur_cc - cntr) & 0xffffff;
+    if ((delta <= 3) && (delta != 0)) {
+        return -1;
+    }
+    delta = (next_cc - cntr) & 0xffffff;
+    if ((delta & 0x800000) || (delta < 3)) {
+        return -1;
+    }
+
+    /* Clear and set TIMER0 to fire off at proper time */
+    NRF_TIMER0->TASKS_CLEAR = 1;
+    NRF_TIMER0->CC[0] = rem_usecs;
+    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+
+    /* Set RTC compare to start TIMER0 */
+    NRF_RTC0->EVENTS_COMPARE[0] = 0;
+    NRF_RTC0->CC[0] = next_cc;
+    NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
+
+    /* Enable PPI */
+    NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk;
+
+    /* Store the cputime at which we set the RTC */
+    g_ble_phy_data.phy_start_cputime = cputime;
+
+    return 0;
+}
+
+void
+ble_phy_wfr_enable(uint32_t wfr_usecs)
+{
+    uint32_t start;
+
+    /* CC[0] is set to when RXEN occurs */
+    start = NRF_TIMER0->CC[0];
+
+    /* wfr_secs is the time from rxen until timeout */
+    NRF_TIMER0->CC[3] = start + XCVR_RX_START_DELAY_USECS + wfr_usecs;
+    NRF_TIMER0->EVENTS_COMPARE[3] = 0;
+
+    /* Enable wait for response PPI */
+    NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+}
+#endif
+
 /**
  * Setup transceiver for receive.
  */
@@ -360,14 +459,23 @@ ble_phy_tx_end_isr(void)
     uint8_t transition;
     uint8_t txlen;
     uint32_t wfr_time;
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+    uint32_t txend;
+#else
     uint32_t txstart;
+#endif
 
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+    /* Read captured end time */
+    txend = NRF_TIMER0->CC[2];
+#else
     /*
      * Read captured tx start time. This is not the actual transmit start
      * time but it is the time at which the address event occurred
      * (after transmission of access address)
      */
     txstart = NRF_TIMER0->CC[1];
+#endif
 
     /* If this transmission was encrypted we need to remember it */
     was_encrypted = g_ble_phy_data.phy_encrypted;
@@ -376,8 +484,13 @@ ble_phy_tx_end_isr(void)
     assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
 
     /* Log the event */
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+    ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len,
+               was_encrypted, txend);
+#else
     ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len,
                was_encrypted, txstart);
+#endif
 
     /* Clear events and clear interrupt on disabled event */
     NRF_RADIO->EVENTS_DISABLED = 0;
@@ -416,13 +529,42 @@ ble_phy_tx_end_isr(void)
         if (txlen && was_encrypted) {
             txlen += BLE_LL_DATA_MIC_LEN;
         }
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+        /*
+         * Set TIMER0 CC[3] to wait for response timeout. This occurs an IFS
+         * time plus the time it takes to receive the address from the transmit
+         * end. We add additional time to make sure the address event comes
+         * before the compare.
+         */
+        wfr_time = BLE_LL_IFS + 40 + 16;
+        NRF_TIMER0->CC[3] = txend + wfr_time;
+        NRF_TIMER0->EVENTS_COMPARE[3] = 0;
+
+        /* Enable wait for response PPI */
+        NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+
+        /* Enable the disabled interrupt so we time out on events compare */
+        NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
+#else
         wfr_time = BLE_LL_WFR_USECS - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
         wfr_time += BLE_TX_DUR_USECS_M(txlen);
         wfr_time = os_cputime_usecs_to_ticks(wfr_time);
         ble_ll_wfr_enable(txstart + wfr_time);
+#endif
     } else {
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+        /*
+         * XXX: not sure we need to stop the timer here all the time. Or that
+         * it should be stopped here.
+         */
+        NRF_TIMER0->TASKS_STOP = 1;
+        NRF_TIMER0->TASKS_SHUTDOWN = 1;
+        NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
+                           PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk;
+#else
         /* Disable automatic TXEN */
         NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+#endif
         assert(transition == BLE_PHY_TRANSITION_NONE);
     }
 }
@@ -506,12 +648,48 @@ ble_phy_rx_start_isr(void)
 {
     int rc;
     uint32_t state;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    uint32_t usecs;
+    uint32_t ticks;
+#endif
     struct ble_mbuf_hdr *ble_hdr;
 
     /* Clear events and clear interrupt */
     NRF_RADIO->EVENTS_ADDRESS = 0;
+
+    /* Clear wfr timer channels and DISABLED interrupt */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | 
RADIO_INTENCLR_ADDRESS_Msk;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk;
+#else
     NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk;
+#endif
+
+    /* Initialize the ble mbuf header */
+    ble_hdr = &g_ble_phy_data.rxhdr;
+    ble_hdr->rxinfo.flags = ble_ll_state_get();
+    ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
+    ble_hdr->rxinfo.handle = 0;
+
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+    /*
+     * Calculate receive start time. We assume that the header time is
+     * 40 usecs (only 1 mbps supported right now).
+     *
+     * XXX: possibly use other routine with remainder!
+     */
+    usecs = NRF_TIMER0->CC[1] - 40;
+    ticks = os_cputime_usecs_to_ticks(usecs);
+    ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks);
+    ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime + ticks;
+#else
+    ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
+        os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET));
+#endif
 
+    /* XXX: I wonder if we always have the 1st byte. If we need to wait for
+     * rx chain delay, it could be 18 usecs from address interrupt. The
+       nrf52 may be able to get here early. */
     /* Wait to get 1st byte of frame */
     while (1) {
         state = NRF_RADIO->STATE;
@@ -530,14 +708,6 @@ ble_phy_rx_start_isr(void)
         }
     }
 
-    /* Initialize flags, channel and state in ble header at rx start */
-    ble_hdr = &g_ble_phy_data.rxhdr;
-    ble_hdr->rxinfo.flags = ble_ll_state_get();
-    ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
-    ble_hdr->rxinfo.handle = 0;
-    ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
-        os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET));
-
     /* Call Link Layer receive start function */
     rc = ble_ll_rx_start((uint8_t *)&g_ble_phy_rx_buf[0] + 3,
                          g_ble_phy_data.phy_chan,
@@ -573,16 +743,34 @@ ble_phy_isr(void)
     /* Read irq register to determine which interrupts are enabled */
     irq_en = NRF_RADIO->INTENCLR;
 
-    /* Check for disabled event. This only happens for transmits now */
-    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
-        ble_phy_tx_end_isr();
-    }
+    /*
+     * NOTE: order of checking is important! Possible, if things get delayed,
+     * we have both an ADDRESS and DISABLED interrupt in rx state. If we get
+     * an address, we disable the DISABLED interrupt.
+     */
 
     /* We get this if we have started to receive a frame */
     if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        irq_en &= ~RADIO_INTENCLR_DISABLED_Msk;
+#endif
         ble_phy_rx_start_isr();
     }
 
+    /* Check for disabled event. This only happens for transmits now */
+    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) {
+            NRF_RADIO->EVENTS_DISABLED = 0;
+            ble_ll_wfr_timer_exp(NULL);
+        } else {
+            ble_phy_tx_end_isr();
+        }
+#else
+        ble_phy_tx_end_isr();
+#endif
+    }
+
     /* Receive packet end (we dont enable this for transmit) */
     if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) {
         ble_phy_rx_end_isr();
@@ -657,8 +845,13 @@ ble_phy_init(void)
     /* Configure IFS */
     NRF_RADIO->TIFS = BLE_LL_IFS;
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
+    NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk;
+#else
     /* Captures tx/rx start in timer0 capture 1 */
     NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk;
+#endif
 
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
     NRF_CCM->INTENCLR = 0xffffffff;
@@ -677,6 +870,27 @@ ble_phy_init(void)
     NRF_AAR->NIRK = 0;
 #endif
 
+    /* TIMER0 setup for PHY when using RTC */
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+    NRF_TIMER0->TASKS_STOP = 1;
+    NRF_TIMER0->TASKS_SHUTDOWN = 1;
+    NRF_TIMER0->BITMODE = 3;    /* 32-bit timer */
+    NRF_TIMER0->MODE = 0;       /* Timer mode */
+    NRF_TIMER0->PRESCALER = 4;  /* gives us 1 MHz */
+
+    /*
+     * PPI setup.
+     * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
+     *            to cancel the wait for response timer.
+     * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
+     *            for response timer.
+     */
+    NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
+    NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]);
+    NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]);
+    NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE);
+#endif
+
     /* Set isr in vector table and enable interrupt */
     NVIC_SetPriority(RADIO_IRQn, 0);
     NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
@@ -785,6 +999,7 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void 
*arg)
     g_ble_phy_data.txend_arg = arg;
 }
 
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
 /**
  * Called to set the start time of a transmission.
  *
@@ -794,28 +1009,38 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void 
*arg)
  * NOTE: care must be taken when calling this function. The channel should
  * already be set.
  *
- * @param cputime
- *
+ * @param cputime   This is the tick at which the 1st bit of the preamble
+ *                  should be transmitted
+ * @param rem_usecs This is used only when the underlying timing uses a 32.768
+ *                  kHz crystal. It is the # of usecs from the cputime tick
+ *                  at which the first bit of the preamble should be
+ *                  transmitted.
  * @return int
  */
 int
-ble_phy_tx_set_start_time(uint32_t cputime)
+ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
 {
     int rc;
 
-    NRF_TIMER0->CC[0] = cputime;
-    NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
+    /* XXX: This should not be necessary, but paranoia is good! */
+    /* Clear timer0 compare to RXEN since we are transmitting */
     NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
-    if ((int32_t)(os_cputime_get32() - cputime) >= 0) {
+
+    /*
+     * XXX: The TXEN time is 140 usecs but there may be additional delays
+     * Need to look at this.
+     */
+    if (ble_phy_set_start_time(cputime, rem_usecs) != 0) {
         STATS_INC(ble_phy_stats, tx_late);
         ble_phy_disable();
-        rc =  BLE_PHY_ERR_TX_LATE;
+        rc = BLE_PHY_ERR_TX_LATE;
     } else {
+        /* Enable PPI to automatically start TXEN */
+        NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
         rc = 0;
     }
     return rc;
 }
-
 /**
  * Called to set the start time of a reception
  *
@@ -830,23 +1055,90 @@ ble_phy_tx_set_start_time(uint32_t cputime)
  * @return int
  */
 int
-ble_phy_rx_set_start_time(uint32_t cputime)
+ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
 {
     int rc;
 
+    /* XXX: This should not be necessary, but paranoia is good! */
+    /* Clear timer0 compare to TXEN since we are transmitting */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+
+    /*
+     * XXX: The RXEN time is 138 usecs but there may be additional delays
+     * Need to look at this.
+     */
+    if (ble_phy_set_start_time(cputime, rem_usecs) != 0) {
+        STATS_INC(ble_phy_stats, rx_late);
+        NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
+        NRF_RADIO->TASKS_RXEN = 1;
+        rc = BLE_PHY_ERR_RX_LATE;
+    } else {
+        /* Enable PPI to automatically start RXEN */
+        NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
+
+        /* Start rx */
+        rc = ble_phy_rx();
+    }
+    return rc;
+}
+#else
+/**
+ * Called to set the start time of a transmission.
+ *
+ * This function is called to set the start time when we are not going from
+ * rx to tx automatically.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime   This is the tick at which the 1st bit of the preamble
+ *                  should be transmitted
+ * @return int
+ */
+int
+ble_phy_tx_set_start_time(uint32_t cputime)
+{
+    int rc;
+
+    cputime -= os_cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS);
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
     NRF_TIMER0->CC[0] = cputime;
+    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+    NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
+    if ((int32_t)(os_cputime_get32() - cputime) >= 0) {
+        STATS_INC(ble_phy_stats, tx_late);
+        ble_phy_disable();
+        rc = BLE_PHY_ERR_TX_LATE;
+    } else {
+        rc = 0;
+    }
+
+    return rc;
+}
+
+#if 0
+int
+ble_phy_rx_set_start_time(void)
+{
+    /*
+     * XXX: For now, we dont use this function if we are not using the
+     * RTC. Keeping the code around just in case we want to use it later.
+     */
     NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+    NRF_TIMER0->CC[0] = cputime;
+    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
     NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
     if ((int32_t)(os_cputime_get32() - cputime) >= 0) {
         STATS_INC(ble_phy_stats, rx_late);
         NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
         NRF_RADIO->TASKS_RXEN = 1;
-        rc =  BLE_PHY_ERR_TX_LATE;
+        rc =  BLE_PHY_ERR_RX_LATE;
     } else {
         rc = 0;
     }
-    return rc;
 }
+#endif
+#endif
 
 int
 ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
@@ -871,6 +1163,16 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
     ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
     payload_len = ble_hdr->txinfo.pyld_len;
 
+    /*
+     * XXX: Although we may not have to do this here, I clear all the PPI
+     * that should not be used when transmitting. Some of them are only enabled
+     * if encryption and/or privacy is on, but I dont care. Better to be
+     * paranoid, and if you are going to clear one, might as well clear them
+     * all.
+     */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk 
|
+                       PPI_CHEN_CH25_Msk;
+
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
     if (g_ble_phy_data.phy_encrypted) {
         dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
@@ -883,11 +1185,9 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
         NRF_CCM->EVENTS_ERROR = 0;
         NRF_CCM->MODE = CCM_MODE_LENGTH_Msk;
         NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
-        NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk | PPI_CHEN_CH23_Msk;
         NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
     } else {
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
-        NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
         NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
 #endif
         dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
@@ -895,9 +1195,6 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
         pktptr = dptr;
     }
 #else
-#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
-    NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
-#endif
     dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
     ++dptr;
     pktptr = dptr;
@@ -1077,29 +1374,62 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, 
uint32_t crcinit)
     return 0;
 }
 
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
 /**
- * Disable the PHY. This will do the following:
- *  -> Turn off all phy interrupts.
- *  -> Disable internal shortcuts.
- *  -> Disable the radio.
- *  -> Make sure we wont automatically go to rx/tx on output compare
- *  -> Sets phy state to idle.
- *  -> Clears any pending irqs in the NVIC. Might not be necessary but we do
- *  it as a precaution.
+ * Stop the timer used to count microseconds when using RTC for cputime
  */
 void
-ble_phy_disable(void)
+ble_phy_stop_usec_timer(void)
 {
-    ble_ll_log(BLE_LL_LOG_ID_PHY_DISABLE, g_ble_phy_data.phy_state, 0, 0);
+    NRF_TIMER0->TASKS_STOP = 1;
+    NRF_TIMER0->TASKS_SHUTDOWN = 1;
+    NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk;
+}
+#endif
 
+/**
+ * ble phy disable irq and ppi
+ *
+ * This routine is to be called when reception was stopped due to either a
+ * wait for response timeout or a packet being received and the phy is to be
+ * restarted in receive mode. Generally, the disable routine is called to stop
+ * the phy.
+ */
+void
+ble_phy_disable_irq_and_ppi(void)
+{
     NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
     NRF_RADIO->SHORTS = 0;
     NRF_RADIO->TASKS_DISABLE = 1;
-    NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk | PPI_CHEN_CH21_Msk | 
PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk 
|
+          PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH24_Msk |
+          PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk;
     NVIC_ClearPendingIRQ(RADIO_IRQn);
     g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
 }
 
+void
+ble_phy_restart_rx(void)
+{
+    ble_phy_disable_irq_and_ppi();
+    ble_phy_rx();
+}
+
+/**
+ * ble phy disable
+ *
+ * Disables the PHY. This should be called when an event is over. It stops
+ * the usec timer (if used), disables interrupts, disables the RADIO, disables
+ * PPI and sets state to idle.
+ */
+void
+ble_phy_disable(void)
+{
+    ble_ll_log(BLE_LL_LOG_ID_PHY_DISABLE, g_ble_phy_data.phy_state, 0, 0);
+    ble_phy_stop_usec_timer();
+    ble_phy_disable_irq_and_ppi();
+}
+
 /* Gets the current access address */
 uint32_t ble_phy_access_addr_get(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/kernel/os/include/os/os_cputime.h
----------------------------------------------------------------------
diff --git a/kernel/os/include/os/os_cputime.h 
b/kernel/os/include/os/os_cputime.h
index f44c941..022efdc 100644
--- a/kernel/os/include/os/os_cputime.h
+++ b/kernel/os/include/os/os_cputime.h
@@ -45,6 +45,10 @@ extern "C" {
 #define OS_CPUTIME_FREQ_1MHZ
 #endif
 
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+#define OS_CPUTIME_FREQ_32768
+#endif
+
 /* CPUTIME data. */
 struct os_cputime_data
 {
@@ -80,6 +84,7 @@ int os_cputime_init(uint32_t clock_freq);
  */
 uint32_t os_cputime_get32(void);
 
+#if !defined(OS_CPUTIME_FREQ_32768)
 /**
  * os cputime nsecs to ticks
  *
@@ -101,6 +106,7 @@ uint32_t os_cputime_nsecs_to_ticks(uint32_t nsecs);
  * @return uint32_t The number of nanoseconds corresponding to 'ticks'
  */
 uint32_t os_cputime_ticks_to_nsecs(uint32_t ticks);
+#endif
 
 #if defined(OS_CPUTIME_FREQ_1MHZ)
 #define os_cputime_usecs_to_ticks(x)    (x)
@@ -138,6 +144,7 @@ uint32_t os_cputime_ticks_to_usecs(uint32_t ticks);
  */
 void os_cputime_delay_ticks(uint32_t ticks);
 
+#if !defined(OS_CPUTIME_FREQ_32768)
 /**
  * os cputime delay nsecs
  *
@@ -146,6 +153,7 @@ void os_cputime_delay_ticks(uint32_t ticks);
  * @param nsecs The number of nanoseconds to wait.
  */
 void os_cputime_delay_nsecs(uint32_t nsecs);
+#endif
 
 /**
  * os cputime delay usecs

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/kernel/os/src/os_cputime.c
----------------------------------------------------------------------
diff --git a/kernel/os/src/os_cputime.c b/kernel/os/src/os_cputime.c
index 067f1a1..01b15fe 100644
--- a/kernel/os/src/os_cputime.c
+++ b/kernel/os/src/os_cputime.c
@@ -30,7 +30,9 @@
  *   @{
  */
 
+#if !defined(OS_CPUTIME_FREQ_32768) && !defined(OS_CPUTIME_FREQ_1MHZ)
 struct os_cputime_data g_os_cputime;
+#endif
 
 /**
  * os cputime init
@@ -49,11 +51,14 @@ os_cputime_init(uint32_t clock_freq)
     int rc;
 
     /* Set the ticks per microsecond. */
+#if !defined(OS_CPUTIME_FREQ_32768) && !defined(OS_CPUTIME_FREQ_1MHZ)
     g_os_cputime.ticks_per_usec = clock_freq / 1000000U;
+#endif
     rc = hal_timer_config(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), clock_freq);
     return rc;
 }
 
+#if !defined(OS_CPUTIME_FREQ_32768)
 /**
  * os cputime nsecs to ticks
  *
@@ -99,8 +104,50 @@ os_cputime_ticks_to_nsecs(uint32_t ticks)
 
     return nsecs;
 }
+#endif
 
 #if !defined(OS_CPUTIME_FREQ_1MHZ)
+#if defined(OS_CPUTIME_FREQ_32768)
+/**
+ * os cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
+ * @param usecs The number of microseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'usecs'
+ */
+uint32_t
+os_cputime_usecs_to_ticks(uint32_t usecs)
+{
+    uint64_t ticks;
+
+    ticks = ((uint64_t)usecs << 9) / 15625;
+    return (uint32_t)ticks;
+}
+
+/**
+ * cputime ticks to usecs
+ *
+ * Convert the given number of ticks into microseconds.
+ *
+ * @param ticks The number of ticks to convert to microseconds.
+ *
+ * @return uint32_t The number of microseconds corresponding to 'ticks'
+ *
+ * NOTE: This calculation will overflow if the value for ticks is greater
+ * than 140737488. I am not going to check that here because that many ticks
+ * is about 4222 seconds, way more than what this routine should be used for.
+ */
+uint32_t
+os_cputime_ticks_to_usecs(uint32_t ticks)
+{
+    uint32_t usecs;
+
+    usecs = ((ticks >> 9) * 15625) + (((ticks & 0x1ff) * 15625) >> 9);
+    return usecs;
+}
+#else
 /**
  * os cputime usecs to ticks
  *
@@ -138,6 +185,7 @@ os_cputime_ticks_to_usecs(uint32_t ticks)
     return us;
 }
 #endif
+#endif
 
 /**
  * os cputime delay ticks
@@ -157,6 +205,7 @@ os_cputime_delay_ticks(uint32_t ticks)
     }
 }
 
+#if !defined(OS_CPUTIME_FREQ_32768)
 /**
  * os cputime delay nsecs
  *
@@ -172,6 +221,7 @@ os_cputime_delay_nsecs(uint32_t nsecs)
     ticks = os_cputime_nsecs_to_ticks(nsecs);
     os_cputime_delay_ticks(ticks);
 }
+#endif
 
 /**
  * os cputime delay usecs

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/include/controller/ble_ll.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll.h 
b/net/nimble/controller/include/controller/ble_ll.h
index e349d71..d46f722 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -362,6 +362,9 @@ void ble_ll_wfr_enable(uint32_t cputime);
 /* Disable wait for response timer */
 void ble_ll_wfr_disable(void);
 
+/* Wait for response timer expiration callback */
+void ble_ll_wfr_timer_exp(void *arg);
+
 /* Read set of features supported by the Link Layer */
 uint8_t ble_ll_read_supp_features(void);
 
@@ -383,7 +386,7 @@ int ble_ll_rand_start(void);
  * XXX: temporary LL debug log. Will get removed once we transition to real
  * log
  */
-#undef BLE_LL_LOG
+#define BLE_LL_LOG
 #include "console/console.h"
 
 #define BLE_LL_LOG_ID_PHY_SETCHAN       (1)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/include/controller/ble_ll_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h 
b/net/nimble/controller/include/controller/ble_ll_conn.h
index b2e6410..041504d 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -202,6 +202,11 @@ struct ble_ll_conn_sm
     uint16_t max_ce_len;
     uint16_t tx_win_off;
     uint32_t anchor_point;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    uint8_t anchor_point_usecs;     /* XXX: can this be uint8_t ?*/
+    uint8_t conn_itvl_usecs;
+    uint32_t conn_itvl_ticks;
+#endif
     uint32_t last_anchor_point;     /* Slave only */
     uint32_t slave_cur_tx_win_usecs;
     uint32_t slave_cur_window_widening;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/include/controller/ble_ll_sched.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_sched.h 
b/net/nimble/controller/include/controller/ble_ll_sched.h
index 3a05cfe..bf3bc6d 100644
--- a/net/nimble/controller/include/controller/ble_ll_sched.h
+++ b/net/nimble/controller/include/controller/ble_ll_sched.h
@@ -25,7 +25,8 @@ extern "C" {
 #endif
 
 /* Time per BLE scheduler slot */
-#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
+#define BLE_LL_SCHED_USECS_PER_SLOT         (1250)
+#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT   (41)    /* 1 tick = 30.517 usecs */
 
 /*
  * Worst case time needed for scheduled advertising item. This is the longest
@@ -46,6 +47,17 @@ extern "C" {
 #define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS   (502)
 #define BLE_LL_SCHED_MAX_ADV_PDU_USECS      (376)
 
+/* BLE Jitter (+/- 16 useecs) */
+#define BLE_LL_JITTER_USECS                 (16)
+
+/*
+ * This is the offset from the start of the scheduled item until the actual
+ * tx/rx should occur, in ticks.
+ */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+extern uint8_t g_ble_ll_sched_offset_ticks;
+#endif
+
 /*
  * This is the number of slots needed to transmit and receive a maximum
  * size PDU, including an IFS time before each. The actual time is
@@ -69,10 +81,19 @@ extern "C" {
 struct ble_ll_sched_item;
 typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
 
+/*
+ * Schedule item
+ *  sched_type: This is the type of the schedule item.
+ *  enqueued: Flag denoting if item is on the scheduler list. 0: no, 1:yes
+ *  remainder: # of usecs from offset till tx/rx should occur
+ *  txrx_offset: Number of ticks from start time until tx/rx should occur.
+ *
+ */
 struct ble_ll_sched_item
 {
     uint8_t         sched_type;
     uint8_t         enqueued;
+    uint8_t         remainder;
     uint32_t        start_time;
     uint32_t        end_time;
     void            *cb_arg;
@@ -94,8 +115,8 @@ void ble_ll_sched_free_item(struct ble_ll_sched_item *sch);
 
 /* Schedule a new master connection */
 struct ble_ll_conn_sm;
-int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
-                            uint8_t req_slots);
+int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
+                            struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len);
 
 /* Schedule a new slave connection */
 int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/include/controller/ble_phy.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_phy.h 
b/net/nimble/controller/include/controller/ble_phy.h
index 674cbc5..f300a13 100644
--- a/net/nimble/controller/include/controller/ble_phy.h
+++ b/net/nimble/controller/include/controller/ble_phy.h
@@ -70,6 +70,7 @@ struct os_mbuf;
 #define BLE_PHY_ERR_INV_PARAM       (3)
 #define BLE_PHY_ERR_NO_BUFS         (4)
 #define BLE_PHY_ERR_TX_LATE         (5)
+#define BLE_PHY_ERR_RX_LATE         (6)
 
 /* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */
 #define BLE_PHY_MAX_PDU_LEN         (257)
@@ -86,11 +87,16 @@ int ble_phy_reset(void);
 /* Set the PHY channel */
 int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit);
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
 /* Set transmit start time */
-int ble_phy_tx_set_start_time(uint32_t cputime);
+int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
 
 /* Set receive start time */
-int ble_phy_rx_set_start_time(uint32_t cputime);
+int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
+#else
+/* Set transmit start time */
+int ble_phy_tx_set_start_time(uint32_t cputime);
+#endif
 
 /* Set the transmit end callback and argument */
 void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg);
@@ -116,6 +122,19 @@ int ble_phy_txpwr_get(void);
 /* Disable the PHY */
 void ble_phy_disable(void);
 
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+void ble_phy_stop_usec_timer(void);
+void ble_phy_wfr_enable(uint32_t wfr_usecs);
+#else
+#define ble_phy_stop_usec_timer()
+#endif
+
+/*
+ * Used to restart reception on same channel after wfr timer expiration or
+ * frame received.
+ */
+void ble_phy_restart_rx(void);
+
 /* Gets the current state of the PHY */
 int ble_phy_state_get(void);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/src/ble_ll.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll.c 
b/net/nimble/controller/src/ble_ll.c
index 6071d3c..0d1fa07 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -51,6 +51,11 @@
  * 4) Should look into always disabled the wfr interrupt if we receive the
  * start of a frame. Need to look at the various states to see if this is the
  * right thing to do.
+ * 5) I am not sure that if we are passed the output compare that we actually
+ * get the interrupt. Test this.
+ * 6) I am not sure that if we receive a packet while scanning that we actually
+ * go back to scanning. I need to make sure we re-enable the receive.
+ * Put an event in the log!
  */
 
 /* Supported states */
@@ -536,7 +541,9 @@ ble_ll_wfr_timer_exp(void *arg)
 void
 ble_ll_wfr_enable(uint32_t cputime)
 {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
     os_cputime_timer_start(&g_ble_ll_data.ll_wfr_timer, cputime);
+#endif
 }
 
 /**
@@ -545,7 +552,9 @@ ble_ll_wfr_enable(uint32_t cputime)
 void
 ble_ll_wfr_disable(void)
 {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
     os_cputime_timer_stop(&g_ble_ll_data.ll_wfr_timer);
+#endif
 }
 
 /**
@@ -786,7 +795,12 @@ ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct 
ble_mbuf_hdr *rxhdr)
     int rc;
     uint8_t pdu_type;
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, rxhdr->rem_usecs,
+               rxhdr->beg_cputime);
+#else
     ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, 0, rxhdr->beg_cputime);
+#endif
 
     /* Check channel type */
     if (chan < BLE_PHY_NUM_DATA_CHANS) {
@@ -1241,9 +1255,11 @@ ble_ll_init(void)
                     ble_ll_hw_err_timer_cb,
                     NULL);
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
     /* Initialize wait for response timer */
     os_cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp,
                           NULL);
+#endif
 
     /* Initialize LL HCI */
     ble_ll_hci_init();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/src/ble_ll_adv.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_adv.c 
b/net/nimble/controller/src/ble_ll_adv.c
index 203f13a..dd27336 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -430,8 +430,14 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
     assert(rc == 0);
 
     /* Set transmit start time. */
-    txstart = sch->start_time + 
os_cputime_usecs_to_ticks(XCVR_PROC_DELAY_USECS);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    txstart = sch->start_time + g_ble_ll_sched_offset_ticks;
+    rc = ble_phy_tx_set_start_time(txstart, sch->remainder);
+#else
+    txstart = sch->start_time +
+        os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
     rc = ble_phy_tx_set_start_time(txstart);
+#endif
     if (rc) {
         STATS_INC(ble_ll_stats, adv_late_starts);
         goto adv_tx_done;
@@ -498,7 +504,7 @@ adv_tx_done:
 }
 
 static void
-ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
+ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm)
 {
     uint32_t max_usecs;
     struct ble_ll_sched_item *sch;
@@ -529,20 +535,15 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int 
sched_new)
      */
     max_usecs += XCVR_PROC_DELAY_USECS;
 
-    if (sched_new) {
-        /*
-         * We have to add the scheduling delay and tx start delay to the max
-         * time of the event since the pdu does not start at the scheduled 
start.
-         */
-        max_usecs += XCVR_TX_SCHED_DELAY_USECS;
-        sch->start_time = os_cputime_get32();
-        sch->end_time = sch->start_time + os_cputime_usecs_to_ticks(max_usecs);
-    } else {
-        sch->start_time = advsm->adv_pdu_start_time -
-            os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
-        sch->end_time = advsm->adv_pdu_start_time +
-            os_cputime_usecs_to_ticks(max_usecs);
-    }
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
+    sch->remainder = 0;
+#else
+    sch->start_time = advsm->adv_pdu_start_time -
+        os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
+    sch->end_time = advsm->adv_pdu_start_time +
+        os_cputime_usecs_to_ticks(max_usecs);
 }
 
 /**
@@ -872,10 +873,23 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
     advsm->adv_chan = adv_chan;
 
     /*
+     * XXX: while this may not be the most efficient, schedule the first
+     * advertising event some time in the future (5 msecs). This will give
+     * time to start up any clocks or anything and also avoid a bunch of code
+     * to check if we are currently doing anything. Just makes this simple.
+     *
+     * Might also want to align this on a slot in the future.
+     *
+     * NOTE: adv_event_start_time gets set by the sched_adv_new
+     */
+    advsm->adv_pdu_start_time = os_cputime_get32() +
+        os_cputime_usecs_to_ticks(BLE_LL_SCHED_MAX_TXRX_SLOT);
+
+    /*
      * Schedule advertising. We set the initial schedule start and end
      * times to the earliest possible start/end.
      */
-    ble_ll_adv_set_sched(advsm, 1);
+    ble_ll_adv_set_sched(advsm);
     ble_ll_sched_adv_new(&advsm->adv_sch);
 
     return BLE_ERR_SUCCESS;
@@ -884,9 +898,14 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
 void
 ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start)
 {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /* The event start time is when we start transmission of the adv PDU */
+    advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks;
+#else
     /* The event start time is when we start transmission of the adv PDU */
     advsm->adv_event_start_time = sch_start +
         os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
 
     advsm->adv_pdu_start_time = advsm->adv_event_start_time;
 
@@ -1511,8 +1530,12 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
          * The scheduled time better be in the future! If it is not, we will
          * just keep advancing until we the time is in the future
          */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
+#else
         start_time = advsm->adv_pdu_start_time -
             os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
 
         delta_t = (int32_t)(start_time - os_cputime_get32());
         if (delta_t < 0) {
@@ -1543,9 +1566,13 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
          * We will transmit right away. Set next pdu start time to now
          * plus a xcvr start delay just so we dont count late adv starts
          */
-        advsm->adv_pdu_start_time = os_cputime_get32() +
+        advsm->adv_pdu_start_time = os_cputime_get32();
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        advsm->adv_pdu_start_time += g_ble_ll_sched_offset_ticks;
+#else
+        advsm->adv_pdu_start_time +=
             os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
-
+#endif
         resched_pdu = 1;
     }
 
@@ -1571,7 +1598,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
 #endif
 
     /* Schedule advertising transmit */
-    ble_ll_adv_set_sched(advsm, 0);
+    ble_ll_adv_set_sched(advsm);
 
     /*
      * In the unlikely event we cant reschedule this, just post a done
@@ -1583,6 +1610,11 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
         rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time,
                                          max_delay_ticks);
         if (!rc) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+            start_time += g_ble_ll_sched_offset_ticks;
+#else
+            start_time += os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
             advsm->adv_event_start_time = start_time;
             advsm->adv_pdu_start_time = start_time;
         }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c 
b/net/nimble/controller/src/ble_ll_conn.c
index c0cda6d..1f4ab8b 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -95,15 +95,26 @@ extern void bletest_completed_pkt(uint16_t handle);
  * response. Well, it should. If this packet will overrun the next scheduled
  * event, what should we do? Transmit anyway? Not transmit? For now, we just
  * transmit.
+ *
+ * 32kHz crystal
+ * 1) When scheduling, I need to make sure I have time between
+ * this one and the next. Should I deal with this in the sched. Or
+ * is this basically accounted for given a slot? I really just need to
+ * make sure everything is over N ticks before the next sched start!
+ * Just add to end time?
+ *
+ * 2) I think one way to handle the problem of losing up to a microsecond
+ * every time we call ble_ll_conn_next_event in a loop is to do everything by
+ * keeping track of last anchor point. Would need last anchor usecs too. I 
guess
+ * we could also keep last anchor usecs as a uint32 or something and when we
+ * do the next event keep track of the residual using a different ticks to
+ * usecs calculation. Not sure.
  */
 
 /*
  * XXX: How should we deal with a late connection event? We need to determine
  * what we want to do under the following cases:
  *  1) The current connection event has not ended but a schedule item starts
- *  2) The connection event start cb is called but we are later than we
- *  expected. What to do? If we cant transmit at correct point in slot we
- *  are hosed. Well, anchor point can get really messed up!
  */
 
 /*
@@ -218,6 +229,25 @@ STATS_NAME_END(ble_ll_conn_stats)
 
 static void ble_ll_conn_event_end(struct os_event *ev);
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+static void
+ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm)
+{
+    uint32_t ticks;
+    uint32_t usecs;
+
+    /*
+     * Precalculate the number of ticks and remaining microseconds for
+     * the connection interval
+     */
+    usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+    ticks = os_cputime_usecs_to_ticks(usecs);
+    connsm->conn_itvl_ticks = ticks;
+    connsm->conn_itvl_usecs = (uint8_t)(usecs -
+                                        os_cputime_ticks_to_usecs(ticks));
+}
+#endif
+
 /**
  * Get the event buffer allocated to send the connection complete event
  * when we are initiating.
@@ -402,7 +432,6 @@ ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm 
*connsm)
         window_widening = (total_sca_ppm * delta_msec) / 1000;
     }
 
-    /* XXX: spec gives 16 usecs error btw. Probably should add that in */
     return window_widening;
 }
 
@@ -689,7 +718,10 @@ ble_ll_conn_continue_rx_encrypt(void *arg)
  * the current connection event. The current connection event must end before
  * the next scheduled item. However, the current connection itself is not
  * in the scheduler list! Thus, we need to calculate the time at which the
- * next connection will start and not overrun it.
+ * next connection will start (the schedule start time; not the anchor point)
+ * and not overrun it.
+ *
+ * Context: Interrupt
  *
  * @param connsm
  *
@@ -698,13 +730,25 @@ ble_ll_conn_continue_rx_encrypt(void *arg)
 static uint32_t
 ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm)
 {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
     uint32_t itvl;
+#endif
     uint32_t ce_end;
     uint32_t next_sched_time;
 
     /* Calculate time at which next connection event will start */
-    itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /* NOTE: We dont care if this time is tick short. */
+    ce_end = connsm->anchor_point + connsm->conn_itvl_ticks -
+        g_ble_ll_sched_offset_ticks;
+    if ((connsm->anchor_point_usecs + connsm->conn_itvl_usecs) >= 31) {
+        ++ce_end;
+    }
+#else
+    itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS) -
+        XCVR_TX_SCHED_DELAY_USECS;
     ce_end = connsm->anchor_point + os_cputime_usecs_to_ticks(itvl);
+#endif
 
     if (ble_ll_sched_next_time(&next_sched_time)) {
         if (CPUTIME_LT(next_sched_time, ce_end)) {
@@ -1121,8 +1165,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
 {
     int rc;
     uint32_t usecs;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
     uint32_t wfr_time;
-    uint32_t txstart;
+#endif
+    uint32_t start;
     struct ble_ll_conn_sm *connsm;
 
     /* XXX: note that we can extend end time here if we want. Look at this */
@@ -1151,9 +1197,15 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
 #endif
 
     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        /* Set start time of transmission */
+        start = sch->start_time + g_ble_ll_sched_offset_ticks;
+        rc = ble_phy_tx_set_start_time(start, sch->remainder);
+#else
         /* Set start time of transmission */
-        txstart = sch->start_time + 
os_cputime_usecs_to_ticks(XCVR_PROC_DELAY_USECS);
-        rc = ble_phy_tx_set_start_time(txstart);
+        start = sch->start_time + 
os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+        rc = ble_phy_tx_set_start_time(start);
+#endif
         if (!rc) {
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
             if (CONN_F_ENCRYPTED(connsm)) {
@@ -1187,11 +1239,13 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item 
*sch)
                 ble_phy_encrypt_disable();
             }
 #endif
-        /*
-         * XXX: make sure I dont care that I get here early to start receiving.
-         * I could use events compare and all that shit to start rx.
-         */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        /* XXX: what is this really for the slave? */
+        start = sch->start_time + g_ble_ll_sched_offset_ticks;
+        rc = ble_phy_rx_set_start_time(start, sch->remainder);
+#else
         rc = ble_phy_rx();
+#endif
         if (rc) {
             /* End the connection event as we have no more buffers */
             STATS_INC(ble_ll_conn_stats, slave_ce_failures);
@@ -1207,15 +1261,32 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item 
*sch)
              * Set the wait for response time. The anchor point is when we
              * expect the master to start transmitting. Worst-case, we expect
              * to hear a reply within the anchor point plus:
-             *  -> the current tx window size
-             *  -> The current window widening amount
+             *  -> current tx window size
+             *  -> current window widening amount (includes +/- 16 usec jitter)
              *  -> Amount of time it takes to detect packet start.
+             *  -> Some extra time (16 usec) to insure timing is OK
              */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+            /*
+             * For the 32 kHz crystal, the amount of usecs we have to wait
+             * is not from the anchor point; we have to account for the time
+             * from when the receiver is enabled until the anchor point. The
+             * time we start before the anchor point is this:
+             *   -> current window widening.
+             *   -> up to one 32 kHz tick since we discard remainder.
+             *   -> Up to one tick since the usecs to ticks calc can be off
+             *   by up to one tick.
+             * NOTE: the 61 we add is for the two ticks mentioned above.
+             */
+            usecs = connsm->slave_cur_tx_win_usecs + 40 + 16 + 61 +
+                (2 * connsm->slave_cur_window_widening);
+            ble_phy_wfr_enable(usecs);
+#else
             usecs = connsm->slave_cur_tx_win_usecs + BLE_LL_WFR_USECS +
                 connsm->slave_cur_window_widening;
             wfr_time = connsm->anchor_point + os_cputime_usecs_to_ticks(usecs);
             ble_ll_wfr_enable(wfr_time);
-
+#endif
             /* Set next wakeup time to connection event end time */
             rc = BLE_LL_SCHED_STATE_RUNNING;
         }
@@ -1246,15 +1317,20 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item 
*sch)
  * @return int 0: not allowed to send 1: allowed to send
  */
 static int
-ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime)
+ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime,
+                              uint32_t add_usecs)
 {
     int rc;
     uint8_t rem_bytes;
     uint32_t ticks;
+    uint32_t usecs;
     uint32_t next_sched_time;
     struct os_mbuf *txpdu;
     struct os_mbuf_pkthdr *pkthdr;
     struct ble_mbuf_hdr *txhdr;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    uint32_t allowed_usecs;
+#endif
 
     rc = 1;
     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
@@ -1277,16 +1353,25 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm 
*connsm, uint32_t begtime)
             if (rem_bytes > connsm->eff_max_tx_octets) {
                 rem_bytes = connsm->eff_max_tx_octets;
             }
-            ticks = BLE_TX_DUR_USECS_M(rem_bytes);
+            usecs = BLE_TX_DUR_USECS_M(rem_bytes);
         } else {
             /* We will send empty pdu (just a LL header) */
-            ticks = BLE_TX_DUR_USECS_M(0);
+            usecs = BLE_TX_DUR_USECS_M(0);
         }
-        ticks += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
-        ticks = os_cputime_usecs_to_ticks(ticks);
+        usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
+
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        ticks = (uint32_t)(next_sched_time - begtime);
+        allowed_usecs = os_cputime_ticks_to_usecs(ticks);
+        if ((usecs + add_usecs) >= allowed_usecs) {
+            rc = 0;
+        }
+#else
+        ticks = os_cputime_usecs_to_ticks(usecs);
         if ((begtime + ticks) >= next_sched_time) {
             rc = 0;
         }
+#endif
     }
 
     return rc;
@@ -1347,7 +1432,15 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
     connsm->conn_role = BLE_LL_CONN_ROLE_MASTER;
 
     /* Set default ce parameters */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /*
+     * XXX: for now, we need twice the transmit window as our calculations
+     * for the transmit window offset could be off.
+     */
+    connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1;
+#else
     connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN;
+#endif
     connsm->tx_win_off = 0;
     connsm->master_sca = MYNEWT_VAL(BLE_LL_MASTER_SCA);
 
@@ -1482,6 +1575,10 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
                     connsm);
 #endif
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    ble_ll_conn_calc_itvl_ticks(connsm);
+#endif
+
     /* Add to list of active connections */
     SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle);
 }
@@ -1629,6 +1726,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
     uint32_t cur_ww;
     uint32_t max_ww;
     struct ble_ll_conn_upd_req *upd;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    uint32_t ticks;
+    uint32_t usecs;
+#endif
+
 
     /* XXX: deal with connection request procedure here as well */
     ble_ll_conn_chk_csm_flags(connsm);
@@ -1647,7 +1749,24 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
     connsm->event_cntr += latency;
 
     /* Set next connection event start time */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /* We can use pre-calculated values for one interval if latency is 1. */
+    if (latency == 1) {
+        connsm->anchor_point += connsm->conn_itvl_ticks;
+        connsm->anchor_point_usecs += connsm->conn_itvl_usecs;
+    } else {
+        uint32_t ticks;
+        ticks = os_cputime_usecs_to_ticks(itvl);
+        connsm->anchor_point += ticks;
+        connsm->anchor_point_usecs += (itvl - 
os_cputime_ticks_to_usecs(ticks));
+    }
+    if (connsm->anchor_point_usecs >= 31) {
+        ++connsm->anchor_point;
+        connsm->anchor_point_usecs -= 31;
+    }
+#else
     connsm->anchor_point += os_cputime_usecs_to_ticks(itvl);
+#endif
 
     /*
      * If a connection update has been scheduled and the event counter
@@ -1669,15 +1788,30 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
             connsm->csmflags.cfbit.host_expects_upd_event = 1;
         }
 
-        connsm->conn_itvl = upd->interval;
         connsm->supervision_tmo = upd->timeout;
         connsm->slave_latency = upd->latency;
         connsm->tx_win_size = upd->winsize;
         connsm->slave_cur_tx_win_usecs =
             connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
         connsm->tx_win_off = upd->winoffset;
+        connsm->conn_itvl = upd->interval;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        ble_ll_conn_calc_itvl_ticks(connsm);
+        if (upd->winoffset != 0) {
+            usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS;
+            ticks = os_cputime_usecs_to_ticks(usecs);
+            connsm->anchor_point += ticks;
+            usecs = usecs - os_cputime_ticks_to_usecs(ticks);
+            connsm->anchor_point_usecs += usecs;
+            if (connsm->anchor_point_usecs >= 31) {
+                ++connsm->anchor_point;
+                connsm->anchor_point_usecs -= 31;
+            }
+        }
+#else
         connsm->anchor_point +=
             os_cputime_usecs_to_ticks(upd->winoffset * BLE_LL_CONN_ITVL_USECS);
+#endif
 
         /* Reset the starting point of the connection supervision timeout */
         connsm->last_rxd_pdu_cputime = connsm->anchor_point;
@@ -1736,20 +1870,35 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
      * Calculate ce end time. For a slave, we need to add window widening and
      * the transmit window if we still have one.
      */
-    itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * 
BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT;
     if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
         cur_ww = ble_ll_conn_calc_window_widening(connsm);
         max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
         if (cur_ww >= max_ww) {
             return -1;
         }
+        cur_ww += BLE_LL_JITTER_USECS;
         connsm->slave_cur_window_widening = cur_ww;
+        itvl += os_cputime_usecs_to_ticks(cur_ww + 
connsm->slave_cur_tx_win_usecs);
+    }
+    itvl -= g_ble_ll_sched_offset_ticks;
+    connsm->ce_end_time = connsm->anchor_point + itvl;
+#else
+    itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT;
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        cur_ww = ble_ll_conn_calc_window_widening(connsm);
+        max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
+        if (cur_ww >= max_ww) {
+            return -1;
+        }
+        connsm->slave_cur_window_widening = cur_ww + BLE_LL_JITTER_USECS;
         itvl += cur_ww + connsm->slave_cur_tx_win_usecs;
     } else {
-        /* We adjust end time for connection to end of time slot */
         itvl -= XCVR_TX_SCHED_DELAY_USECS;
     }
     connsm->ce_end_time = connsm->anchor_point + 
os_cputime_usecs_to_ticks(itvl);
+#endif
 
     return 0;
 }
@@ -1799,9 +1948,38 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, 
struct ble_mbuf_hdr *rxhdr)
      */
     rc = 1;
     if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        /*
+         * With a 32.768 kHz crystal we dont care about the remaining usecs
+         * when setting last anchor point. The only thing last anchor is used
+         * for is to calculate window widening. The effect of this is
+         * negligible.
+         */
+        connsm->last_anchor_point = rxhdr->beg_cputime;
+
+        usecs = rxhdr->rem_usecs + 1250 +
+            (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) +
+            BLE_TX_DUR_USECS_M(BLE_CONNECT_REQ_LEN);
+
+        /* Anchor point is cputime. */
+        endtime = os_cputime_usecs_to_ticks(usecs);
+        connsm->anchor_point = rxhdr->beg_cputime + endtime;
+        connsm->anchor_point_usecs = usecs - 
os_cputime_ticks_to_usecs(endtime);
+        if (connsm->anchor_point_usecs == 31) {
+            ++connsm->anchor_point;
+            connsm->anchor_point_usecs = 0;
+        }
+
+        connsm->slave_cur_tx_win_usecs =
+            connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
+
+        connsm->ce_end_time = connsm->anchor_point +
+            (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * 
BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT)
+            + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
+#else
+        connsm->last_anchor_point = rxhdr->beg_cputime;
         endtime = rxhdr->beg_cputime +
             os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(BLE_CONNECT_REQ_LEN));
-        connsm->last_anchor_point = endtime;
         connsm->slave_cur_tx_win_usecs =
             connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
         usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
@@ -1810,7 +1988,8 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct 
ble_mbuf_hdr *rxhdr)
             (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT);
         connsm->ce_end_time = connsm->anchor_point +
             os_cputime_usecs_to_ticks(usecs);
-        connsm->slave_cur_window_widening = 0;
+#endif
+        connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS;
 
         /* Start the scheduler for the first connection event */
         while (ble_ll_sched_slave_new(connsm)) {
@@ -1958,6 +2137,7 @@ ble_ll_conn_event_end(struct os_event *ev)
     } else {
         tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000UL;
     }
+    /* XXX: Convert to ticks to usecs calculation instead??? */
     tmo = os_cputime_usecs_to_ticks(tmo);
     if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) 
{
         ble_ll_conn_end(connsm, BLE_ERR_CONN_SPVN_TMO);
@@ -2251,7 +2431,6 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
     uint8_t *init_addr = NULL;
     uint8_t pyld_len;
     uint8_t inita_is_rpa;
-    uint32_t endtime;
     struct os_mbuf *rxpdu;
     struct ble_ll_conn_sm *connsm;
 
@@ -2366,10 +2545,7 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
         }
 
         /* Attempt to schedule new connection. Possible that this might fail */
-        endtime = ble_hdr->beg_cputime +
-            os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(pyld_len));
-        if (!ble_ll_sched_master_new(connsm, endtime,
-                                     MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS))) {
+        if (!ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) {
             /* Setup to transmit the connect request */
             rc = ble_ll_conn_request_send(addr_type, adv_addr,
                                           connsm->tx_win_off, index);
@@ -2392,8 +2568,7 @@ init_rx_isr_exit:
      */
     rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN);
     if (rxpdu == NULL) {
-        ble_phy_disable();
-        ble_phy_rx();
+        ble_phy_restart_rx();
         rc = 0;
     } else {
         ble_phy_rxpdu_copy(rxbuf, rxpdu);
@@ -2485,6 +2660,9 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, 
uint32_t aa)
             connsm->csmflags.cfbit.slave_set_last_anchor = 0;
             connsm->last_anchor_point = rxhdr->beg_cputime;
             connsm->anchor_point = connsm->last_anchor_point;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+            connsm->anchor_point_usecs = rxhdr->rem_usecs;
+#endif
         }
     }
     return 1;
@@ -2646,6 +2824,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct 
ble_mbuf_hdr *rxhdr)
     uint8_t opcode = 0;
     uint8_t rx_pyld_len;
     uint32_t endtime;
+    uint32_t add_usecs;
     struct os_mbuf *txpdu;
     struct ble_ll_conn_sm *connsm;
     struct os_mbuf *rxpdu;
@@ -2676,8 +2855,14 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct 
ble_mbuf_hdr *rxhdr)
     }
 
     /* Calculate the end time of the received PDU */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    endtime = rxhdr->beg_cputime;
+    add_usecs = rxhdr->rem_usecs + BLE_TX_DUR_USECS_M(rx_pyld_len);
+#else
     endtime = rxhdr->beg_cputime +
         os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(rx_pyld_len));
+    add_usecs = 0;
+#endif
 
     /*
      * Check the packet CRC. A connection event can continue even if the
@@ -2848,7 +3033,7 @@ chk_rx_terminate_ind:
     if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) {
         rx_pyld_len += BLE_LL_DATA_MIC_LEN;
     }
-    if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime)) {
+    if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime, add_usecs)) {
         rc = ble_ll_conn_tx_data_pdu(connsm);
     }
 
@@ -3032,7 +3217,6 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, 
uint8_t *chanmap)
  * Context: Link Layer
  *
  * @param rxbuf Pointer to received Connect Request PDU
- * @param conn_req_end receive end time of connect request
  *
  * @return 0: connection not started; 1 connecton started
  */
@@ -3256,3 +3440,5 @@ ble_ll_conn_module_init(void)
     /* Call reset to finish reset of initialization */
     ble_ll_conn_module_reset();
 }
+
+

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h 
b/net/nimble/controller/src/ble_ll_conn_priv.h
index 0913892..02cac60 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -42,12 +42,13 @@ extern "C" {
 #define BLE_LL_CONN_INITIAL_OFFSET          (1250)
 #define BLE_LL_CONN_ITVL_USECS              (1250)
 #define BLE_LL_CONN_TX_WIN_USECS            (1250)
+#define BLE_LL_CONN_TX_OFF_USECS            (1250)
 #define BLE_LL_CONN_CE_USECS                (625)
 #define BLE_LL_CONN_TX_WIN_MIN              (1)         /* in tx win units */
 #define BLE_LL_CONN_SLAVE_LATENCY_MAX       (499)
 
 /* Connection request duration (in usecs) */
-#define BLE_LL_CONN_REQ_DURATION            (352)
+#define BLE_LL_CONN_REQ_DURATION            (352)       /* 1 Mbps only */
 
 /* Connection handle range */
 #define BLE_LL_CONN_MAX_CONN_HANDLE         (0x0EFF)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/src/ble_ll_scan.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_scan.c 
b/net/nimble/controller/src/ble_ll_scan.c
index f732753..306b8cc 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -588,8 +588,14 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t 
chan)
     }
 #endif
 
-    /* Start receiving */
-    rc = ble_phy_rx();
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        /* XXX: probably need to make sure hfxo is running too */
+        /* XXX: can make this better; want to just start asap. */
+        rc = ble_phy_rx_set_start_time(os_cputime_get32() +
+                                       g_ble_ll_sched_offset_ticks, 0);
+#else
+        rc = ble_phy_rx();
+#endif
     if (!rc) {
         /* Enable/disable whitelisting */
         if (scansm->scan_filt_policy & 1) {
@@ -929,8 +935,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
         if (scansm->scan_rsp_pending) {
             ble_ll_scan_req_backoff(scansm, 0);
         }
-        ble_phy_disable();
-        ble_phy_rx();
+        ble_phy_restart_rx();
         return 0;
     }
 
@@ -1081,8 +1086,6 @@ ble_ll_scan_wfr_timer_exp(void)
 {
     struct ble_ll_scan_sm *scansm;
 
-    ble_phy_disable();
-
     /*
      * If we timed out waiting for a response, the scan response pending
      * flag should be set. Deal with scan backoff. Put device back into rx.
@@ -1091,7 +1094,8 @@ ble_ll_scan_wfr_timer_exp(void)
     if (scansm->scan_rsp_pending) {
         ble_ll_scan_req_backoff(scansm, 0);
     }
-    ble_phy_rx();
+
+    ble_phy_restart_rx();
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/controller/src/ble_ll_sched.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_sched.c 
b/net/nimble/controller/src/ble_ll_sched.c
index dd42c3f..2c18e0c 100644
--- a/net/nimble/controller/src/ble_ll_sched.c
+++ b/net/nimble/controller/src/ble_ll_sched.c
@@ -21,6 +21,7 @@
 #include <string.h>
 #include "os/os.h"
 #include "os/os_cputime.h"
+#include "bsp.h"
 #include "ble/xcvr.h"
 #include "controller/ble_phy.h"
 #include "controller/ble_ll.h"
@@ -32,13 +33,17 @@
 /* XXX: this is temporary. Not sure what I want to do here */
 struct hal_timer g_ble_ll_sched_timer;
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+uint8_t g_ble_ll_sched_offset_ticks;
+#endif
+
 #define BLE_LL_SCHED_ADV_WORST_CASE_USECS       \
     (BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS + BLE_LL_SCHED_ADV_MAX_USECS \
      + XCVR_TX_SCHED_DELAY_USECS)
 
-
 #if (BLE_LL_SCHED_DEBUG == 1)
 int32_t g_ble_ll_sched_max_late;
+int32_t g_ble_ll_sched_max_early;
 #endif
 
 /* XXX: TODO:
@@ -155,6 +160,17 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
     /* Get schedule element from connection */
     sch = &connsm->conn_sch;
 
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /* Set schedule start and end times */
+    sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks;
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        usecs = connsm->slave_cur_window_widening;
+        sch->start_time -= (os_cputime_usecs_to_ticks(usecs) + 1);
+        sch->remainder = 0;
+    } else {
+        sch->remainder = connsm->anchor_point_usecs;
+    }
+#else
     /* Set schedule start and end times */
     if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
         usecs = XCVR_RX_SCHED_DELAY_USECS;
@@ -163,6 +179,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
         usecs = XCVR_TX_SCHED_DELAY_USECS;
     }
     sch->start_time = connsm->anchor_point - os_cputime_usecs_to_ticks(usecs);
+#endif
     sch->end_time = connsm->ce_end_time;
 
     /* Better be past current time or we just leave */
@@ -247,67 +264,108 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm 
*connsm)
     return rc;
 }
 
+/**
+ * Called to schedule a connection when the current role is master.
+ *
+ * Context: Interrupt
+ *
+ * @param connsm
+ * @param ble_hdr
+ * @param pyld_len
+ *
+ * @return int
+ */
 int
-ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
-                        uint8_t req_slots)
+ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
+                        struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len)
 {
     int rc;
     os_sr_t sr;
-    uint32_t tps;
+    uint8_t req_slots;
     uint32_t initial_start;
     uint32_t earliest_start;
     uint32_t earliest_end;
     uint32_t dur;
     uint32_t itvl_t;
-    uint32_t ce_end_time;
+    uint32_t adv_rxend;
     struct ble_ll_sched_item *entry;
     struct ble_ll_sched_item *sch;
 
-    /* Better have a connsm */
-    assert(connsm != NULL);
-
     /* Get schedule element from connection */
     rc = -1;
     sch = &connsm->conn_sch;
-
+    req_slots = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS);
+
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /* XXX:
+     * The calculations for the 32kHz crystal bear alot of explanation. The
+     * earliest possible time that the master can start the connection with a
+     * slave is 1.25 msecs from the end of the connection request. The
+     * connection request is sent an IFS time from the end of the advertising
+     * packet that was received plus the time it takes to send the connection
+     * request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks
+     * makes us off ~13 usecs. Since we dont want to actually calculate the
+     * receive end time tick (this would take too long), we assume the end of
+     * the advertising PDU is 'now' (we call os_cputime_get32). We dont know
+     * how much time it will take to service the ISR but if we are more than 
the
+     * rx to tx time of the chip we will not be successful transmitting the
+     * connect request. All this means is that we presume that the slave will
+     * receive the connect request later than we expect but no earlier than
+     * 13 usecs before (this is important).
+     *
+     * The code then attempts to schedule the connection at the
+     * earliest time although this may not be possible. When the actual
+     * schedule start time is determined, the master has to determine if this
+     * time is more than a transmit window offset interval (1.25 msecs). The
+     * master has to tell the slave how many transmit window offsets there are
+     * from the earliest possible time to when the actual transmit start will
+     * occur. Later in this function you will see the calculation. The actual
+     * transmission start has to occur within the transmit window. The transmit
+     * window interval is in units of 1.25 msecs and has to be at least 1. To
+     * make things a bit easier (but less power efficient for the slave), we
+     * use a transmit window of 2. We do this because we dont quite know the
+     * exact start of the transmission and if we are too early or too late we
+     * could miss the transmit window. A final note: the actual transmission
+     * start (the anchor point) is sched offset ticks from the schedule start
+     * time. We dont add this to the calculation when calculating the window
+     * offset. The reason we dont do this is we want to insure we transmit
+     * after the window offset we tell the slave. For example, say we think
+     * we are transmitting 1253 usecs from the earliest start. This would cause
+     * us to send a transmit window offset of 1. Since we are actually
+     * transmitting earlier than the slave thinks we could end up transmitting
+     * before the window offset. Transmitting later is fine since we have the
+     * transmit window to do so. Transmitting before is bad, since the slave
+     * wont be listening. We could do better calculation if we wanted to use
+     * a transmit window of 1 as opposed to 2, but for now we dont care.
+     */
+    dur = req_slots * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT;
+    adv_rxend = os_cputime_get32();
+    earliest_start = adv_rxend + 57;    /* XXX: only works for 1 Mbps */
+    earliest_end = earliest_start + dur;
+    itvl_t = connsm->conn_itvl_ticks;
+#else
+    adv_rxend = ble_hdr->beg_cputime +
+        os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(pyld_len));
     /*
      * The earliest start time is 1.25 msecs from the end of the connect
      * request transmission. Note that adv_rxend is the end of the received
      * advertisement, so we need to add an IFS plus the time it takes to send
-     * the connection request
+     * the connection request. The 1.25 msecs starts from the end of the conn
+     * request.
      */
     dur = os_cputime_usecs_to_ticks(req_slots * BLE_LL_SCHED_USECS_PER_SLOT);
     earliest_start = adv_rxend +
         os_cputime_usecs_to_ticks(BLE_LL_IFS + BLE_LL_CONN_REQ_DURATION +
                                   BLE_LL_CONN_INITIAL_OFFSET);
     earliest_end = earliest_start + dur;
-
     itvl_t = os_cputime_usecs_to_ticks(connsm->conn_itvl * 
BLE_LL_CONN_ITVL_USECS);
+#endif
 
     /* We have to find a place for this schedule */
     OS_ENTER_CRITICAL(sr);
 
     /* The schedule item must occur after current running item (if any) */
     sch->start_time = earliest_start;
-
-    /*
-     * If we are currently in a connection, we add one slot time to the
-     * earliest start so we can end the connection reasonably.
-     */
-    if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
-        tps = os_cputime_usecs_to_ticks(BLE_LL_SCHED_USECS_PER_SLOT);
-        ce_end_time = ble_ll_conn_get_ce_end_time();
-        while ((int32_t)(ce_end_time - os_cputime_get32()) < 0) {
-            ce_end_time += tps;
-        }
-
-        /* Start at next slot boundary past earliest */
-        while ((int32_t)(ce_end_time - earliest_start) < 0) {
-            ce_end_time += tps;
-        }
-        earliest_start = ce_end_time;
-        earliest_end = earliest_start + dur;
-    }
     initial_start = earliest_start;
 
     if (!ble_ll_sched_insert_if_empty(sch)) {
@@ -338,6 +396,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, 
uint32_t adv_rxend,
             }
         }
 
+        /* Must be able to schedule within one connection interval */
         if (!entry) {
             if ((earliest_start - initial_start) <= itvl_t) {
                 rc = 0;
@@ -346,18 +405,38 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, 
uint32_t adv_rxend,
         }
 
         if (!rc) {
-            /* calculate number of connection intervals before start */
+            /* calculate number of window offsets. Each offset is 1.25 ms */
             sch->enqueued = 1;
-            connsm->tx_win_off = (earliest_start - initial_start) /
-                os_cputime_usecs_to_ticks(BLE_LL_CONN_ITVL_USECS);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+            /*
+             * NOTE: we dont add sched offset ticks as we want to 
under-estimate
+             * the transmit window slightly since the window size is currently
+             * 2 when using a 32768 crystal.
+             */
+            dur = os_cputime_ticks_to_usecs(earliest_start - initial_start);
+            connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS;
+#else
+            dur = os_cputime_ticks_to_usecs(earliest_start - initial_start);
+            dur += XCVR_TX_SCHED_DELAY_USECS;
+            connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS;
+#endif
         }
     }
 
     if (!rc) {
         sch->start_time = earliest_start;
         sch->end_time = earliest_end;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+        /*
+         * Since we have the transmit window to transmit in, we dont need
+         * to set the anchor point usecs; just transmit to the nearest tick.
+         */
+        connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks;
+        connsm->anchor_point_usecs = 0;
+#else
         connsm->anchor_point = earliest_start +
             os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
         connsm->ce_end_time = earliest_end;
     }
 
@@ -385,10 +464,22 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
     sch = &connsm->conn_sch;
 
     /* Set schedule start and end times */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    /*
+     * XXX: for now, we dont care about anchor point usecs for the slave. It
+     * does not matter if we turn on the receiver up to one tick before w
+     * need to. We also subtract one extra tick since the conversion from
+     * usecs to ticks could be off by up to 1 tick.
+     */
+    sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks -
+        os_cputime_usecs_to_ticks(connsm->slave_cur_window_widening) - 1;
+#else
     sch->start_time = connsm->anchor_point -
         os_cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS +
                                   connsm->slave_cur_window_widening);
+#endif
     sch->end_time = connsm->ce_end_time;
+    sch->remainder = 0;
 
     /* We have to find a place for this schedule */
     OS_ENTER_CRITICAL(sr);
@@ -450,9 +541,6 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
 {
     int rc;
     os_sr_t sr;
-    uint8_t ll_state;
-    int32_t ticks;
-    uint32_t ce_end_time;
     uint32_t adv_start;
     uint32_t duration;
     struct ble_ll_sched_item *entry;
@@ -463,39 +551,12 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
     orig = sch;
 
     OS_ENTER_CRITICAL(sr);
-
-    /*
-     * If we are currently in a connection, we add one slot time to the
-     * earliest start so we can end the connection reasonably.
-     */
-    ll_state = ble_ll_state_get();
-    if (ll_state == BLE_LL_STATE_CONNECTION) {
-        ticks = (int32_t)os_cputime_usecs_to_ticks(BLE_LL_SCHED_MAX_TXRX_SLOT);
-        ce_end_time = ble_ll_conn_get_ce_end_time();
-        if ((int32_t)(ce_end_time - sch->start_time) < ticks) {
-            ce_end_time += ticks;
-        }
-        sch->start_time = ce_end_time;
-        sch->end_time = ce_end_time + duration;
-    }
-#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
-    else if ((ll_state == BLE_LL_STATE_ADV) && (BLE_LL_ADV_INSTANCES > 1)) {
-        /*
-         * Since we currently dont know how long this item might be scheduled
-         * for we add what we think the worst-case time for the advertising
-         * scheduled item to be over. We add in a IFS for good measure.
-         */
-        sch->start_time += BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS +
-            BLE_LL_SCHED_ADV_MAX_USECS + XCVR_TX_SCHED_DELAY_USECS;
-        sch->end_time = sch->start_time + duration;
-    }
-#endif
-
     entry = ble_ll_sched_insert_if_empty(sch);
     if (!entry) {
         rc = 0;
         adv_start = sch->start_time;
     } else {
+        /* XXX: no need to stop timer if not first on list. Modify code? */
         os_cputime_timer_stop(&g_ble_ll_sched_timer);
         TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
             /* We can insert if before entry in list */
@@ -531,12 +592,6 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
 
     OS_EXIT_CRITICAL(sr);
 
-    /* XXX: some things to test. I am not sure that if we are passed the
-       output compare that we actually get the interrupt. */
-    /* XXX: I am not sure that if we receive a packet while scanning
-     * that we actually go back to scanning. I need to make sure
-       we re-enable the receive. Put an event in the log! */
-
     os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
 
     return rc;
@@ -784,26 +839,33 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch)
 void
 ble_ll_sched_run(void *arg)
 {
-    int32_t dt;
     struct ble_ll_sched_item *sch;
 
     /* Look through schedule queue */
-    while ((sch = TAILQ_FIRST(&g_ble_ll_sched_q)) != NULL) {
+    sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+    if (sch) {
+#if (BLE_LL_SCHED_DEBUG == 1)
+        int32_t dt;
+
         /* Make sure we have passed the start time of the first event */
         dt = (int32_t)(os_cputime_get32() - sch->start_time);
-        if (dt >= 0) {
-#if (BLE_LL_SCHED_DEBUG == 1)
-            if (dt > g_ble_ll_sched_max_late) {
-                g_ble_ll_sched_max_late = dt;
-            }
+        if (dt > g_ble_ll_sched_max_late) {
+            g_ble_ll_sched_max_late = dt;
+        }
+        if (dt < g_ble_ll_sched_max_early) {
+            g_ble_ll_sched_max_early = dt;
+        }
 #endif
-            /* Remove schedule item and execute the callback */
-            TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
-            sch->enqueued = 0;
-            ble_ll_sched_execute_item(sch);
-        } else {
+
+        /* Remove schedule item and execute the callback */
+        TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
+        sch->enqueued = 0;
+        ble_ll_sched_execute_item(sch);
+
+        /* Restart if there is an item on the schedule */
+        sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+        if (sch) {
             os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
-            break;
         }
     }
 }
@@ -857,6 +919,24 @@ ble_ll_sched_stop(void)
 int
 ble_ll_sched_init(void)
 {
+    /*
+     * Initialize max early to large negative number. This is used
+     * to determine the worst-case "early" time the schedule was called. Dont
+     * expect this to be less than -3 or -4.
+     */
+#if (BLE_LL_SCHED_DEBUG == 1)
+    g_ble_ll_sched_max_early = -50000;
+#endif
+
+    /*
+     * This is the offset from the start of the scheduled item until the actual
+     * tx/rx should occur, in ticks. We also "round up" to the nearest tick.
+     */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+    g_ble_ll_sched_offset_ticks =
+        os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS + 30);
+#endif
+
     /* Initialize cputimer for the scheduler */
     os_cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
     return 0;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/94a59a3c/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index b514131..6f29fd4 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -96,6 +96,9 @@ struct ble_mbuf_hdr
         struct ble_mbuf_hdr_txinfo txinfo;
     };
     uint32_t beg_cputime;
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+    uint32_t rem_usecs;
+#endif
 };
 
 #define BLE_MBUF_HDR_CRC_OK(hdr)        \

Reply via email to