You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2017/03/30 21:45:06 UTC

[3/5] incubator-mynewt-core git commit: Low power timer. Only nrf52 right now.

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

Branch: refs/heads/develop
Commit: 507f493ab86266528c7f921784978e63a07ddd33
Parents: 8158805
Author: William San Filippo <wi...@runtime.io>
Authored: Thu Feb 16 16:12:39 2017 -0800
Committer: William San Filippo <wi...@runtime.io>
Committed: Thu Mar 30 14:09:52 2017 -0700

----------------------------------------------------------------------
 apps/bletest/src/main.c                         |   2 +-
 hw/drivers/nimble/nrf52/include/ble/xcvr.h      |  12 +-
 hw/drivers/nimble/nrf52/src/ble_phy.c           | 438 +++++++++++++++++--
 kernel/os/include/os/os_cputime.h               |   8 +
 kernel/os/src/os_cputime.c                      |  50 +++
 .../controller/include/controller/ble_ll.h      |  51 ++-
 .../controller/include/controller/ble_ll_conn.h |   5 +
 .../include/controller/ble_ll_sched.h           |  32 +-
 .../controller/include/controller/ble_ll_xcvr.h |  48 ++
 .../controller/include/controller/ble_phy.h     |  31 +-
 net/nimble/controller/src/ble_ll.c              |  37 ++
 net/nimble/controller/src/ble_ll_adv.c          |  86 +++-
 net/nimble/controller/src/ble_ll_conn.c         | 265 +++++++++--
 net/nimble/controller/src/ble_ll_conn_priv.h    |   3 +-
 net/nimble/controller/src/ble_ll_scan.c         | 145 +++++-
 net/nimble/controller/src/ble_ll_sched.c        | 354 +++++++++++----
 net/nimble/controller/src/ble_ll_xcvr.c         | 153 +++++++
 net/nimble/controller/syscfg.yml                |   8 +
 net/nimble/host/src/ble_hs_hci_evt.c            |   6 +-
 net/nimble/include/nimble/ble.h                 |   3 +
 20 files changed, 1531 insertions(+), 206 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/apps/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/main.c b/apps/bletest/src/main.c
index e2519eb..efb3fd4 100755
--- a/apps/bletest/src/main.c
+++ b/apps/bletest/src/main.c
@@ -172,7 +172,7 @@ bletest_multi_adv_instances[BLETEST_CFG_ADV_TEST_INSTANCES] = {
 #define BLETEST_CFG_MAX_CE_LEN          (BLETEST_CFG_CONN_ITVL)
 #define BLETEST_CFG_CONN_PEER_ADDR_TYPE (BLE_HCI_CONN_PEER_ADDR_PUBLIC)
 #define BLETEST_CFG_CONN_OWN_ADDR_TYPE  (BLE_HCI_ADV_OWN_ADDR_PUBLIC)
-#define BLETEST_CFG_CONCURRENT_CONNS    (1)
+#define BLETEST_CFG_CONCURRENT_CONNS    (8)
 
 /* Test packet config */
 #define BLETEST_CFG_RAND_PKT_SIZE       (1)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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..2b6d7ea 100644
--- a/hw/drivers/nimble/nrf52/include/ble/xcvr.h
+++ b/hw/drivers/nimble/nrf52/include/ble/xcvr.h
@@ -24,10 +24,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/507f493a/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..8d8b0e1 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,133 @@ 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;
+}
+
+/**
+ * Function is used to set PPI so that we can time out waiting for a reception
+ * to occur. This happens for two reasons: we have sent a packet and we are
+ * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are
+ * starting a connection event and we are a slave and we are waiting for the
+ * master to send us a packet (txrx should be set to ENABLE_RX).
+ *
+ * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there
+ * is no additional time to wait; we know when we should receive the address of
+ * the received frame.
+ *
+ * @param txrx Flag denoting if this wfr is a txrx turn-around or not.
+ * @param wfr_usecs Amount of usecs to wait.
+ */
+void
+ble_phy_wfr_enable(int txrx, uint32_t wfr_usecs)
+{
+    uint32_t end_time;
+
+    if (txrx == BLE_PHY_WFR_ENABLE_TXRX) {
+        /*
+         * Timeout occurs an IFS time plus time it takes to receive address
+         * from the transmit end. We add additional time to make sure the
+         * address event comes before the compare. Note that transmit end
+         * is captured in CC[2]
+         *
+         * XXX: this assumes 1Mbps as 40 usecs is header rx time for 1Mbps
+         */
+        end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS + 40 + 16;
+    } else {
+        /* CC[0] is set to when RXEN occurs. NOTE: the extra 16 usecs is
+           jitter */
+        end_time = NRF_TIMER0->CC[0] + XCVR_RX_START_DELAY_USECS + wfr_usecs +
+            40 + 16;
+    }
+
+    /* wfr_secs is the time from rxen until timeout */
+    NRF_TIMER0->CC[3] = end_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;
+}
+#endif
+
 /**
  * Setup transceiver for receive.
  */
@@ -360,14 +490,18 @@ 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 txstart;
+#endif
 
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768)
     /*
      * 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,14 +510,20 @@ 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, NRF_TIMER0->CC[2]);
+#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;
     NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
     NRF_RADIO->EVENTS_END = 0;
     wfr_time = NRF_RADIO->SHORTS;
+    (void)wfr_time;
 
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
     /*
@@ -416,13 +556,28 @@ ble_phy_tx_end_isr(void)
         if (txlen && was_encrypted) {
             txlen += BLE_LL_DATA_MIC_LEN;
         }
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+        ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, 0);
+#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 +661,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 +721,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 +756,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();
@@ -606,6 +807,8 @@ int
 ble_phy_init(void)
 {
     int rc;
+
+#if !defined(BLE_XCVR_RFCLK)
     uint32_t os_tmo;
 
     /* Make sure HFXO is started */
@@ -620,6 +823,7 @@ ble_phy_init(void)
             return BLE_PHY_ERR_INIT;
         }
     }
+#endif
 
     /* Set phy channel to an invalid channel so first set channel works */
     g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
@@ -657,8 +861,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 +886,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 +1015,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 +1025,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 +1071,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 +1179,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 +1201,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 +1211,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 +1390,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)
 {
@@ -1168,3 +1514,17 @@ ble_phy_resolv_list_disable(void)
     g_ble_phy_data.phy_privacy = 0;
 }
 #endif
+
+#ifdef BLE_XCVR_RFCLK
+void
+ble_phy_rfclk_enable(void)
+{
+    NRF_CLOCK->TASKS_HFCLKSTART = 1;
+}
+
+void
+ble_phy_rfclk_disable(void)
+{
+    NRF_CLOCK->TASKS_HFCLKSTOP = 1;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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/507f493a/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/507f493a/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..acc201d 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -22,13 +22,41 @@
 
 #include "stats/stats.h"
 #include "os/os_eventq.h"
+#include "os/os_callout.h"
 #include "os/os_cputime.h"
 #include "nimble/nimble_opt.h"
+#include "controller/ble_phy.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/*
+ * XXX:
+ * I guess this should not depend on the 32768 crystal to be honest. This
+ * should be done for TIMER0 as well since the rf clock chews up more current.
+ * Deal with this later.
+ *
+ * Another note: BLE_XTAL_SETTLE_TIME should be bsp related (I guess). There
+ * should be a note in there that the converted usecs to ticks value of this
+ * should not be 0. Thus: if you are using a 32.768 os cputime freq, the min
+ * value of settle time should be 31 usecs. I would suspect all settling times
+ * would exceed 31 usecs.
+ */
+
+/* Determines if we need to turn on/off rf clock */
+#undef BLE_XCVR_RFCLK
+
+/* Transceiver specific definitions */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+
+/* We will turn on/off rf clock */
+#if MYNEWT_VAL(BLE_XTAL_SETTLE_TIME) != 0
+#define BLE_XCVR_RFCLK
+#endif
+
+#endif
+
 /* Controller revision. */
 #define BLE_LL_SUB_VERS_NR      (0x0000)
 
@@ -61,11 +89,22 @@ struct ble_ll_obj
 
     /* Number of ACL data packets supported */
     uint8_t ll_num_acl_pkts;
+
+#ifdef BLE_XCVR_RFCLK
+    uint8_t ll_rfclk_state;
+    uint16_t ll_xtal_ticks;
+#else
     uint8_t _pad;
+    uint16_t _pad16;
+#endif
 
     /* ACL data packet size */
     uint16_t ll_acl_pkt_size;
-    uint16_t _pad16;
+
+#ifdef BLE_XCVR_RFCLK
+    uint32_t ll_rfclk_start_time;
+    struct hal_timer ll_rfclk_timer;
+#endif
 
     /* Task event queue */
     struct os_eventq ll_evq;
@@ -362,6 +401,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 +425,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)
@@ -405,6 +447,11 @@ int ble_ll_rand_start(void);
 #define BLE_LL_LOG_ID_ADV_TXBEG         (50)
 #define BLE_LL_LOG_ID_ADV_TXDONE        (60)
 #define BLE_LL_LOG_ID_SCHED             (80)
+#define BLE_LL_LOG_ID_RFCLK_START       (90)
+#define BLE_LL_LOG_ID_RFCLK_ENABLE      (91)
+#define BLE_LL_LOG_ID_RFCLK_STOP        (95)
+#define BLE_LL_LOG_ID_RFCLK_SCHED_DIS   (96)
+#define BLE_LL_LOG_ID_RFCLK_SCAN_DIS    (97)
 
 #ifdef BLE_LL_LOG
 void ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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/507f493a/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..d2321b7 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);
@@ -128,6 +149,11 @@ int ble_ll_sched_next_time(uint32_t *next_event_time);
 /* Stop the scheduler */
 void ble_ll_sched_stop(void);
 
+#ifdef BLE_XCVR_RFCLK
+/* Check if RF clock needs to be restarted */
+void ble_ll_sched_rfclk_chk_restart(void);
+#endif
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_xcvr.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_xcvr.h b/net/nimble/controller/include/controller/ble_ll_xcvr.h
new file mode 100644
index 0000000..c59b009
--- /dev/null
+++ b/net/nimble/controller/include/controller/ble_ll_xcvr.h
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_LL_XCVR_
+#define H_BLE_LL_XCVR_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef BLE_XCVR_RFCLK
+
+/* RF clock states */
+#define BLE_RFCLK_STATE_OFF     (0)
+#define BLE_RFCLK_STATE_ON      (1)
+#define BLE_RFCLK_STATE_SETTLED (2)
+
+int ble_ll_xcvr_rfclk_state(void);
+void ble_ll_xcvr_rfclk_start_now(uint32_t now);
+void ble_ll_xcvr_rfclk_stop(void);
+void ble_ll_xcvr_rfclk_enable(void);
+void ble_ll_xcvr_rfclk_disable(void);
+uint32_t ble_ll_xcvr_rfclk_time_till_settled(void);
+void ble_ll_xcvr_rfclk_timer_exp(void *arg);
+void ble_ll_xcvr_rfclk_timer_start(uint32_t cputime);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_LL_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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..e62b216 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,27 @@ 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(int txrx, uint32_t wfr_usecs);
+#define BLE_PHY_WFR_ENABLE_RX       (0)
+#define BLE_PHY_WFR_ENABLE_TXRX     (1)
+#else
+#define ble_phy_stop_usec_timer()
+#endif
+
+/* Starts rf clock */
+void ble_phy_rfclk_enable(void);
+
+/* Stops rf clock */
+void ble_phy_rfclk_disable(void);
+
+/*
+ * 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/507f493a/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..3204ff2 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -39,6 +39,7 @@
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_whitelist.h"
 #include "controller/ble_ll_resolv.h"
+#include "controller/ble_ll_xcvr.h"
 #include "ble_ll_conn_priv.h"
 
 /* XXX:
@@ -51,6 +52,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 +542,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 +553,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 +796,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) {
@@ -1167,6 +1182,11 @@ ble_ll_reset(void)
     /* Set state to standby */
     ble_ll_state_set(BLE_LL_STATE_STANDBY);
 
+#ifdef BLE_XCVR_RFCLK
+    /* Stops rf clock and rfclock timer */
+    ble_ll_xcvr_rfclk_stop();
+#endif
+
     /* Reset our random address */
     memset(g_random_addr, 0, BLE_DEV_ADDR_LEN);
 
@@ -1211,11 +1231,26 @@ ble_ll_init(void)
 {
     int rc;
     uint8_t features;
+#ifdef BLE_XCVR_RFCLK
+    uint32_t xtal_ticks;
+#endif
     struct ble_ll_obj *lldata;
 
     /* Ensure this function only gets called by sysinit. */
     SYSINIT_ASSERT_ACTIVE();
 
+#ifdef BLE_XCVR_RFCLK
+    /* Settling time of crystal, in ticks */
+    xtal_ticks = MYNEWT_VAL(BLE_XTAL_SETTLE_TIME);
+    assert(xtal_ticks != 0);
+    g_ble_ll_data.ll_xtal_ticks = os_cputime_usecs_to_ticks(xtal_ticks);
+
+    /* Initialize rf clock timer */
+    os_cputime_timer_init(&g_ble_ll_data.ll_rfclk_timer,
+                          ble_ll_xcvr_rfclk_timer_exp, NULL);
+
+#endif
+
     /* Get pointer to global data object */
     lldata = &g_ble_ll_data;
 
@@ -1241,9 +1276,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/507f493a/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..8240d7a 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);
 }
 
 /**
@@ -745,6 +746,10 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
             ble_ll_wfr_disable();
             ble_ll_state_set(BLE_LL_STATE_STANDBY);
             g_ble_ll_cur_adv_sm = NULL;
+            ble_ll_scan_chk_resume();
+#ifdef BLE_XCVR_RFCLK
+            ble_ll_sched_rfclk_chk_restart();
+#endif
         }
 #else
         if (ble_ll_state_get() == BLE_LL_STATE_ADV) {
@@ -752,6 +757,10 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
             ble_ll_wfr_disable();
             ble_ll_state_set(BLE_LL_STATE_STANDBY);
             g_ble_ll_cur_adv_sm = NULL;
+            ble_ll_scan_chk_resume();
+#ifdef BLE_XCVR_RFCLK
+            ble_ll_sched_rfclk_chk_restart();
+#endif
         }
 #endif
         OS_EXIT_CRITICAL(sr);
@@ -872,10 +881,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 +906,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;
 
@@ -1489,6 +1516,11 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
         /* Check if we need to resume scanning */
         ble_ll_scan_chk_resume();
 
+        /* Turn off the clock if not doing anything else */
+#ifdef BLE_XCVR_RFCLK
+        ble_ll_sched_rfclk_chk_restart();
+#endif
+
         /* This event is over. Set adv channel to first one */
         advsm->adv_chan = ble_ll_adv_first_chan(advsm);
 
@@ -1511,8 +1543,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 +1579,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 +1611,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
@@ -1580,9 +1620,15 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
     if (resched_pdu) {
         rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch);
     } else {
+        /* Reschedule advertising event */
         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/507f493a/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 1d2714a..d7f926e 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,35 @@ 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.
+             * NOTES:
+             * 1) the 61 we add is for the two ticks mentioned above.
+             * 2) The address rx time and jitter is accounted for in the
+             * phy function
              */
+            usecs = connsm->slave_cur_tx_win_usecs + 61 +
+                (2 * connsm->slave_cur_window_widening);
+            ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 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 +1320,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 +1356,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 +1435,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 +1578,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 +1729,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 +1752,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 +1791,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 +1873,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 +1951,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 +1991,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)) {
@@ -1870,6 +2052,10 @@ ble_ll_conn_event_end(struct os_event *ev)
     /* Check if we need to resume scanning */
     ble_ll_scan_chk_resume();
 
+#ifdef BLE_XCVR_RFCLK
+    ble_ll_sched_rfclk_chk_restart();
+#endif
+
     /* If we have transmitted the terminate IND successfully, we are done */
     if ((connsm->csmflags.cfbit.terminate_ind_txd) ||
         (connsm->csmflags.cfbit.terminate_ind_rxd)) {
@@ -1958,6 +2144,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 +2438,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 +2552,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 +2575,6 @@ init_rx_isr_exit:
      */
     rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN);
     if (rxpdu == NULL) {
-        ble_phy_disable();
-
         /*
          * XXX: possible allocate the PDU when we start initiating?
          * I cannot say I like this solution, but if we cannot allocate a PDU
@@ -2405,8 +2586,7 @@ init_rx_isr_exit:
             CONN_F_CONN_REQ_TXD(connsm) = 0;
             ble_ll_sched_rmv_elem(&connsm->conn_sch);
         }
-
-        ble_phy_rx();
+        ble_phy_restart_rx();
         rc = 0;
     } else {
         ble_phy_rxpdu_copy(rxbuf, rxpdu);
@@ -2498,6 +2678,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;
@@ -2659,6 +2842,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;
@@ -2689,8 +2873,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
@@ -2861,7 +3051,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);
     }
 
@@ -3045,7 +3235,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
  */
@@ -3269,3 +3458,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/507f493a/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/507f493a/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..f5eca7f 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -37,6 +37,7 @@
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_whitelist.h"
 #include "controller/ble_ll_resolv.h"
+#include "controller/ble_ll_xcvr.h"
 #include "hal/hal_gpio.h"
 
 /*
@@ -588,8 +589,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) {
@@ -612,6 +619,37 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan)
     }
 }
 
+#ifdef BLE_XCVR_RFCLK
+static void
+ble_ll_scan_rfclk_chk_stop(void)
+{
+    int stop;
+    int32_t time_till_next;
+    os_sr_t sr;
+    uint32_t next_time;
+
+    stop = 0;
+    OS_ENTER_CRITICAL(sr);
+    if (ble_ll_sched_next_time(&next_time)) {
+        /*
+         * If the time until the next event is too close, dont bother to turn
+         * off the clock
+         */
+        time_till_next = (int32_t)(next_time - os_cputime_get32());
+        if (time_till_next > g_ble_ll_data.ll_xtal_ticks) {
+            stop = 1;
+        }
+    } else {
+        stop = 1;
+    }
+    if (stop) {
+        ble_ll_log(BLE_LL_LOG_ID_RFCLK_SCAN_DIS, g_ble_ll_data.ll_rfclk_state,0,0);
+        ble_ll_xcvr_rfclk_disable();
+    }
+    OS_EXIT_CRITICAL(sr);
+}
+#endif
+
 /**
  * Called to determine if we are inside or outside the scan window. If we
  * are inside the scan window it means that the device should be receiving
@@ -629,6 +667,7 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
     int rc;
     uint8_t chan;
     uint32_t itvl;
+    uint32_t dt;
     uint32_t win_start;
 
     itvl = os_cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
@@ -645,7 +684,13 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
     rc = 0;
     if (scansm->scan_window != scansm->scan_itvl) {
         itvl = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
-        if ((cputime - win_start) >= itvl) {
+        dt = cputime - win_start;
+        if (dt >= itvl) {
+#ifdef BLE_XCVR_RFCLK
+            if (dt < (scansm->scan_itvl - g_ble_ll_data.ll_xtal_ticks)) {
+                ble_ll_scan_rfclk_chk_stop();
+            }
+#endif
             rc = 1;
         }
     }
@@ -688,6 +733,11 @@ ble_ll_scan_sm_stop(int chk_disable)
 
             /* Set LL state to standby */
             ble_ll_state_set(BLE_LL_STATE_STANDBY);
+
+            /* May need to stop the rfclk */
+#ifdef BLE_XCVR_RFCLK
+            ble_ll_scan_rfclk_chk_stop();
+#endif
         }
         OS_EXIT_CRITICAL(sr);
     }
@@ -757,6 +807,9 @@ ble_ll_scan_event_proc(struct os_event *ev)
     uint32_t win_start;
     uint32_t scan_itvl;
     uint32_t next_event_time;
+#ifdef BLE_XCVR_RFCLK
+    uint32_t xtal_ticks;
+#endif
     struct ble_ll_scan_sm *scansm;
 
     /*
@@ -786,12 +839,19 @@ ble_ll_scan_event_proc(struct os_event *ev)
     dt = now - win_start;
     scansm->scan_chan = chan;
     scansm->scan_win_start_time = win_start;
+    if (scansm->scan_window != scansm->scan_itvl) {
+        win = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+    } else {
+        win = 0;
+    }
 
     /* Determine on/off state based on scan window */
     rxstate = 1;
     next_event_time = win_start + scan_itvl;
-    if (scansm->scan_window != scansm->scan_itvl) {
-        win = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (win != 0) {
         if (dt >= win) {
             rxstate = 0;
         } else {
@@ -799,7 +859,6 @@ ble_ll_scan_event_proc(struct os_event *ev)
         }
     }
 
-    OS_ENTER_CRITICAL(sr);
     /*
      * If we are not in the standby state it means that the scheduled
      * scanning event was overlapped in the schedule. In this case all we do
@@ -815,6 +874,9 @@ ble_ll_scan_event_proc(struct os_event *ev)
     case BLE_LL_STATE_SCANNING:
         /* Must disable PHY since we will move to a new channel */
         ble_phy_disable();
+        if (!rxstate) {
+            ble_ll_state_set(BLE_LL_STATE_STANDBY);
+        }
         break;
     case BLE_LL_STATE_STANDBY:
         break;
@@ -822,11 +884,70 @@ ble_ll_scan_event_proc(struct os_event *ev)
         assert(0);
         break;
     }
+
+#ifdef BLE_XCVR_RFCLK
+    if (rxstate == 0) {
+        /*
+         * We need to wake up before we need to start scanning in order
+         * to make sure the rfclock is on. If we are close to being on,
+         * enable the rfclock. If not, set wakeup time.
+         */
+        if (dt >= (scan_itvl - g_ble_ll_data.ll_xtal_ticks)) {
+            /* Start the clock if necessary */
+            if (start_scan) {
+                if (ble_ll_xcvr_rfclk_state() == BLE_RFCLK_STATE_OFF) {
+                    ble_ll_xcvr_rfclk_start_now(now);
+                    next_event_time = now + g_ble_ll_data.ll_xtal_ticks;
+                }
+            }
+        } else {
+            next_event_time -= g_ble_ll_data.ll_xtal_ticks;
+            if (start_scan) {
+                ble_ll_scan_rfclk_chk_stop();
+            }
+        }
+    }
+#endif
+
     if (start_scan && rxstate) {
+#ifdef BLE_XCVR_RFCLK
+        /* NOTE: reuse rxstate */
+        rxstate = ble_ll_xcvr_rfclk_state();
+        if (rxstate != BLE_RFCLK_STATE_SETTLED) {
+            if (rxstate == BLE_RFCLK_STATE_OFF) {
+                xtal_ticks = g_ble_ll_data.ll_xtal_ticks;
+            } else {
+                xtal_ticks = ble_ll_xcvr_rfclk_time_till_settled();
+            }
+
+            /*
+             * Only bother if we have enough time to receive anything
+             * here. The next event time will turn off the clock.
+             */
+            if (win != 0) {
+                if ((win - dt) <= xtal_ticks)  {
+                    goto rfclk_not_settled;
+                }
+            }
+
+            /*
+             * If clock off, start clock. Set next event time to now plus
+             * the clock setting time.
+             */
+            if (rxstate == BLE_RFCLK_STATE_OFF) {
+                ble_ll_xcvr_rfclk_start_now(now);
+            }
+            next_event_time = now + xtal_ticks;
+            goto rfclk_not_settled;
+        }
+#endif
         ble_ll_scan_start(scansm, scansm->scan_chan);
     }
-    OS_EXIT_CRITICAL(sr);
 
+#ifdef BLE_XCVR_RFCLK
+rfclk_not_settled:
+#endif
+    OS_EXIT_CRITICAL(sr);
     os_cputime_timer_start(&scansm->scan_timer, next_event_time);
 }
 
@@ -929,8 +1050,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 +1201,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 +1209,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();
 }
 
 /**
@@ -1480,7 +1599,7 @@ ble_ll_scan_init(void)
     scansm->scan_itvl = BLE_HCI_SCAN_ITVL_DEF;
     scansm->scan_window = BLE_HCI_SCAN_WINDOW_DEF;
 
-    /* Initialize connection supervision timer */
+    /* Initialize scanning timer */
     os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm);
 
     /* Get a scan request mbuf (packet header) and attach to state machine */