You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2022/02/04 13:25:55 UTC

[mynewt-nimble] 01/02: nimble/ll: Add ll_tmr

This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 22b38ccab9bb037ab5738a250cb21660d6a65248
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Fri Jan 28 00:43:20 2022 +0100

    nimble/ll: Add ll_tmr
    
    This adds generic API for LL timer which replaces explicit os_cputime
    usage in LL.
    
    Short term, this allows for more consistent and simpler code since new
    API introduces few helpers to perform add/sub operations on timers with
    proper usecs wrapping.
    
    Long term, this will allow LL to work natively with timers that are not
    based on 32768Hz clock, as e.g. Dialog CMAC.
---
 nimble/controller/include/controller/ble_ll.h      |  14 +-
 .../controller/include/controller/ble_ll_rfmgmt.h  |   4 +-
 nimble/controller/include/controller/ble_ll_scan.h |   4 +-
 nimble/controller/include/controller/ble_ll_tmr.h  | 159 +++++++++++++++++++++
 nimble/controller/src/ble_ll.c                     |   1 -
 nimble/controller/src/ble_ll_adv.c                 |  96 ++++++-------
 nimble/controller/src/ble_ll_conn.c                | 101 +++++--------
 nimble/controller/src/ble_ll_ctrl.c                |   4 +-
 nimble/controller/src/ble_ll_dtm.c                 |  19 +--
 nimble/controller/src/ble_ll_rfmgmt.c              |  26 ++--
 nimble/controller/src/ble_ll_scan.c                |  32 ++---
 nimble/controller/src/ble_ll_sched.c               | 124 ++++++----------
 nimble/controller/src/ble_ll_sync.c                |  52 +++----
 nimble/controller/src/ble_ll_utils.c               |   3 +-
 nimble/drivers/nrf52/src/ble_phy.c                 |   2 +
 15 files changed, 344 insertions(+), 297 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll.h b/nimble/controller/include/controller/ble_ll.h
index f4b8517..d148fbe 100644
--- a/nimble/controller/include/controller/ble_ll.h
+++ b/nimble/controller/include/controller/ble_ll.h
@@ -21,7 +21,6 @@
 #define H_BLE_LL_
 
 #include "stats/stats.h"
-#include "os/os_cputime.h"
 #include "nimble/nimble_opt.h"
 #include "nimble/nimble_npl.h"
 #include "controller/ble_phy.h"
@@ -30,6 +29,9 @@
 #include "controller/ble_ll_ctrl.h"
 #include "hal/hal_system.h"
 #endif
+#ifdef RIOT_VERSION
+#include "hal/hal_timer.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -123,9 +125,6 @@ struct ble_ll_obj
     /* Task event queue */
     struct ble_npl_eventq ll_evq;
 
-    /* Wait for response timer */
-    struct hal_timer ll_wfr_timer;
-
     /* Packet receive queue (and event). Holds received packets from PHY */
     struct ble_npl_event ll_rx_pkt_ev;
     struct ble_ll_pkt_q ll_rx_pkt_q;
@@ -612,13 +611,6 @@ ble_ll_get_addr_type(uint8_t txrxflag)
     return BLE_HCI_ADV_OWN_ADDR_PUBLIC;
 }
 
-/* Convert usecs to ticks and round up to nearest tick */
-static inline uint32_t
-ble_ll_usecs_to_ticks_round_up(uint32_t usecs)
-{
-    return os_cputime_usecs_to_ticks(usecs + 30);
-}
-
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
 /* LTK 0x4C68384139F574D836BCF34E9DFB01BF */
 extern const uint8_t g_bletest_LTK[];
diff --git a/nimble/controller/include/controller/ble_ll_rfmgmt.h b/nimble/controller/include/controller/ble_ll_rfmgmt.h
index 5e2d636..1aa1c4b 100644
--- a/nimble/controller/include/controller/ble_ll_rfmgmt.h
+++ b/nimble/controller/include/controller/ble_ll_rfmgmt.h
@@ -24,6 +24,8 @@
 extern "C" {
 #endif
 
+#include "controller/ble_ll_tmr.h"
+
 void ble_ll_rfmgmt_init(void);
 
 #if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0
@@ -51,7 +53,7 @@ static inline void ble_ll_rfmgmt_reset(void) { }
 static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { }
 static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { }
 static inline void ble_ll_rfmgmt_release(void) { }
-static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return os_cputime_get32(); }
+static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return ble_ll_tmr_get(); }
 static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; }
 
 #endif
diff --git a/nimble/controller/include/controller/ble_ll_scan.h b/nimble/controller/include/controller/ble_ll_scan.h
index a44e431..34bcd60 100644
--- a/nimble/controller/include/controller/ble_ll_scan.h
+++ b/nimble/controller/include/controller/ble_ll_scan.h
@@ -21,7 +21,7 @@
 #define H_BLE_LL_SCAN_
 
 #include "controller/ble_ll_sched.h"
-#include "hal/hal_timer.h"
+#include "controller/ble_ll_tmr.h"
 #include "syscfg/syscfg.h"
 #include "nimble/nimble_npl.h"
 
@@ -135,7 +135,7 @@ struct ble_ll_scan_sm
     uint16_t backoff_count;
     uint32_t scan_win_start_time;
     struct ble_npl_event scan_sched_ev;
-    struct hal_timer scan_timer;
+    struct ble_ll_tmr scan_timer;
     struct ble_npl_event scan_interrupted_ev;
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
diff --git a/nimble/controller/include/controller/ble_ll_tmr.h b/nimble/controller/include/controller/ble_ll_tmr.h
new file mode 100644
index 0000000..9dd6ab4
--- /dev/null
+++ b/nimble/controller/include/controller/ble_ll_tmr.h
@@ -0,0 +1,159 @@
+/*
+ * 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_TMR_
+#define H_BLE_LL_TMR_
+
+#include "os/os_cputime.h"
+#include "controller/ble_ll.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define USECS_PER_TICK          (31)
+
+#define LL_TMR_LT(_t1, _t2)     ((int32_t)((_t1) - (_t2)) < 0)
+#define LL_TMR_GT(_t1, _t2)     ((int32_t)((_t1) - (_t2)) > 0)
+#define LL_TMR_GEQ(_t1, _t2)    ((int32_t)((_t1) - (_t2)) >= 0)
+#define LL_TMR_LEQ(_t1, _t2)    ((int32_t)((_t1) - (_t2)) <= 0)
+
+typedef void (ble_ll_tmr_cb)(void *arg);
+
+struct ble_ll_tmr {
+    struct hal_timer t;
+};
+
+static inline uint32_t
+ble_ll_tmr_get(void)
+{
+    return os_cputime_get32();
+}
+
+static inline uint32_t
+ble_ll_tmr_t2u(uint32_t ticks)
+{
+    return os_cputime_ticks_to_usecs(ticks);
+}
+
+static inline uint32_t
+ble_ll_tmr_u2t(uint32_t usecs)
+{
+    if (usecs <= 31249) {
+        return (usecs * 137439) / 4194304;
+    }
+
+    return os_cputime_usecs_to_ticks(usecs);
+}
+
+static inline uint32_t
+ble_ll_tmr_u2t_up(uint32_t usecs)
+{
+    return ble_ll_tmr_u2t(usecs + (USECS_PER_TICK - 1));
+}
+
+static inline uint32_t
+ble_ll_tmr_u2t_r(uint32_t usecs, uint8_t *rem_us)
+{
+    uint32_t ticks;
+
+    ticks = ble_ll_tmr_u2t(usecs);
+    *rem_us = usecs - ble_ll_tmr_t2u(ticks);
+    if (*rem_us == USECS_PER_TICK) {
+        *rem_us = 0;
+        ticks++;
+    }
+
+    return ticks;
+}
+
+static inline void
+ble_ll_tmr_add(uint32_t *ticks, uint8_t *rem_us, uint32_t usecs)
+{
+    uint32_t t_ticks;
+    uint8_t t_rem_us;
+
+    t_ticks = ble_ll_tmr_u2t_r(usecs, &t_rem_us);
+
+    *ticks += t_ticks;
+    *rem_us += t_rem_us;
+    if (*rem_us >= USECS_PER_TICK) {
+        *rem_us -= USECS_PER_TICK;
+        *ticks += 1;
+    }
+}
+
+static inline void
+ble_ll_tmr_add_u(uint32_t *ticks, uint8_t *rem_us, uint8_t usecs)
+{
+    BLE_LL_ASSERT(usecs < USECS_PER_TICK);
+
+    *rem_us += usecs;
+    if (*rem_us >= USECS_PER_TICK) {
+        *rem_us -= USECS_PER_TICK;
+        *ticks += 1;
+    }
+}
+
+static inline void
+ble_ll_tmr_sub(uint32_t *ticks, uint8_t *rem_us, uint32_t usecs)
+{
+    uint32_t t_ticks;
+    uint8_t t_rem_us;
+
+    if (usecs <= *rem_us) {
+        *rem_us -= usecs;
+        return;
+    }
+
+    usecs -= *rem_us;
+    *rem_us = 0;
+
+    t_ticks = ble_ll_tmr_u2t_r(usecs, &t_rem_us);
+    if (t_rem_us) {
+        t_ticks += 1;
+        *rem_us = USECS_PER_TICK - t_rem_us;
+    }
+
+    *ticks -= t_ticks;
+}
+
+static inline void
+ble_ll_tmr_init(struct ble_ll_tmr *tmr, ble_ll_tmr_cb *cb, void *arg)
+{
+    os_cputime_timer_init(&tmr->t, cb, arg);
+}
+
+static inline void
+ble_ll_tmr_start(struct ble_ll_tmr *tmr, uint32_t tgt)
+{
+    os_cputime_timer_start(&tmr->t, tgt);
+}
+
+static inline void
+ble_ll_tmr_stop(struct ble_ll_tmr *tmr)
+{
+    os_cputime_timer_stop(&tmr->t);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_BLE_LL_TMR_ */
\ No newline at end of file
diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c
index ce82c0d..34c0c77 100644
--- a/nimble/controller/src/ble_ll.c
+++ b/nimble/controller/src/ble_ll.c
@@ -24,7 +24,6 @@
 #include "sysinit/sysinit.h"
 #include "syscfg/syscfg.h"
 #include "os/os.h"
-#include "os/os_cputime.h"
 #include "stats/stats.h"
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c
index 813db38..caa817e 100644
--- a/nimble/controller/src/ble_ll_adv.c
+++ b/nimble/controller/src/ble_ll_adv.c
@@ -22,7 +22,6 @@
 #include <assert.h>
 #include "syscfg/syscfg.h"
 #include "os/os.h"
-#include "os/os_cputime.h"
 #include "ble/xcvr.h"
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
@@ -37,6 +36,7 @@
 #include "controller/ble_ll_scan.h"
 #include "controller/ble_ll_whitelist.h"
 #include "controller/ble_ll_resolv.h"
+#include "controller/ble_ll_tmr.h"
 #include "controller/ble_ll_trace.h"
 #include "controller/ble_ll_utils.h"
 #include "controller/ble_ll_rfmgmt.h"
@@ -587,7 +587,7 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
 
     /* AuxPtr */
     if (AUX_CURRENT(advsm)->sch.enqueued) {
-        offset = os_cputime_ticks_to_usecs(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time);
+        offset = ble_ll_tmr_t2u(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time);
     } else {
         offset = 0;
     }
@@ -620,11 +620,11 @@ ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm,
         conn_cnt = connsm->event_cntr;
 
         /* get anchor for conn event that is before periodic_adv_event_start_time */
-        while (CPUTIME_GT(anchor, advsm->periodic_adv_event_start_time)) {
+        while (LL_TMR_GT(anchor, advsm->periodic_adv_event_start_time)) {
             ble_ll_conn_get_anchor(connsm, --conn_cnt, &anchor, &anchor_usecs);
         }
 
-        offset = os_cputime_ticks_to_usecs(advsm->periodic_adv_event_start_time - anchor);
+        offset = ble_ll_tmr_t2u(advsm->periodic_adv_event_start_time - anchor);
         offset -= anchor_usecs;
         offset += advsm->periodic_adv_event_start_time_remainder;
 
@@ -639,12 +639,12 @@ ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm,
          * happen if advertising event is interleaved with periodic advertising
          * event (when chaining).
          */
-        while (CPUTIME_GT(AUX_CURRENT(advsm)->start_time, anchor)) {
+        while (LL_TMR_GT(AUX_CURRENT(advsm)->start_time, anchor)) {
             anchor += advsm->periodic_adv_itvl_ticks;
             event_cnt_off++;
         }
 
-        offset = os_cputime_ticks_to_usecs(anchor - AUX_CURRENT(advsm)->start_time);
+        offset = ble_ll_tmr_t2u(anchor - AUX_CURRENT(advsm)->start_time);
         offset += advsm->periodic_adv_event_start_time_remainder;
         offset += advsm->periodic_adv_itvl_rem_usec;
     }
@@ -776,10 +776,10 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
              */
             offset = 0;
         } else if (advsm->rx_ble_hdr) {
-            offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime);
+            offset = ble_ll_tmr_t2u(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime);
             offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS);
         } else {
-            offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - aux->start_time);
+            offset = ble_ll_tmr_t2u(AUX_NEXT(advsm)->start_time - aux->start_time);
         }
 
         ble_ll_adv_put_aux_ptr(AUX_NEXT(advsm)->chan, advsm->sec_phy,
@@ -1226,8 +1226,7 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm)
 
     sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
     sch->remainder = 0;
-    sch->end_time = advsm->adv_pdu_start_time +
-                    ble_ll_usecs_to_ticks_round_up(max_usecs);
+    sch->end_time = advsm->adv_pdu_start_time + ble_ll_tmr_u2t_up(max_usecs);
 }
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
@@ -1520,13 +1519,13 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm)
     max_usecs = ble_ll_pdu_tx_time_get(aux_next->payload_len, advsm->sec_phy);
 
     aux_next->start_time = aux->sch.end_time +
-                           ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY));
+                           ble_ll_tmr_u2t_up(BLE_LL_MAFS +
+                                             MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY));
 
     sch = &aux_next->sch;
     sch->start_time = aux_next->start_time - g_ble_ll_sched_offset_ticks;
     sch->remainder = 0;
-    sch->end_time = aux_next->start_time +
-                    ble_ll_usecs_to_ticks_round_up(max_usecs);
+    sch->end_time = aux_next->start_time + ble_ll_tmr_u2t_up(max_usecs);
     ble_ll_sched_adv_new(&aux_next->sch, ble_ll_adv_aux_scheduled, aux_next);
 
     /*
@@ -1535,7 +1534,7 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm)
      * so advertising will stop after current aux.
      */
     if (advsm->duration &&
-        CPUTIME_GT(aux_next->sch.end_time, advsm->adv_end_time)) {
+        LL_TMR_GT(aux_next->sch.end_time, advsm->adv_end_time)) {
         ble_ll_sched_rmv_elem(&aux_next->sch);
     }
 }
@@ -1595,7 +1594,7 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm)
     sch = &aux->sch;
     sch->start_time = aux->start_time - g_ble_ll_sched_offset_ticks;
     sch->remainder = 0;
-    sch->end_time = aux->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs);
+    sch->end_time = aux->start_time + ble_ll_tmr_u2t_up(max_usecs);
     ble_ll_sched_adv_new(sch, ble_ll_adv_aux_scheduled, aux);
 }
 
@@ -1641,7 +1640,8 @@ ble_ll_adv_aux_set_start_time(struct ble_ll_adv_sm *advsm)
     adv_event_dur = (adv_pdu_dur * chans) + (9 * (chans - 1));
 
     advsm->aux[0].start_time = advsm->adv_event_start_time + adv_event_dur +
-                               ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY));
+                               ble_ll_tmr_u2t_up(BLE_LL_MAFS +
+                                                 MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY));
 }
 
 static void
@@ -1665,7 +1665,7 @@ ble_ll_adv_aux_schedule(struct ble_ll_adv_sm *advsm)
      * not start extended advertising event which we cannot finish in time.
      */
     if (advsm->duration &&
-        CPUTIME_GT(AUX_CURRENT(advsm)->sch.end_time, advsm->adv_end_time)) {
+        LL_TMR_GT(AUX_CURRENT(advsm)->sch.end_time, advsm->adv_end_time)) {
         ble_ll_adv_sm_stop_timeout(advsm);
     }
 }
@@ -2031,14 +2031,14 @@ ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start, void *arg)
      */
     if (advsm->duration) {
         advsm->adv_end_time = advsm->adv_event_start_time +
-                             os_cputime_usecs_to_ticks(advsm->duration * 10000);
+                             ble_ll_tmr_u2t(advsm->duration * 10000);
     }
 #else
     /* Set the time at which we must end directed, high-duty cycle advertising.
      */
     if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
         advsm->adv_end_time = advsm->adv_event_start_time +
-                     os_cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000);
+                     ble_ll_tmr_u2t(BLE_LL_ADV_STATE_HD_MAX * 1000);
     }
 #endif
 }
@@ -2085,7 +2085,8 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
              */
             offset = 0;
         } else {
-            offset = os_cputime_ticks_to_usecs(SYNC_NEXT(advsm)->start_time - sync->start_time);
+            offset = ble_ll_tmr_t2u(SYNC_NEXT(advsm)->start_time -
+                                    sync->start_time);
         }
 
         ble_ll_adv_put_aux_ptr(SYNC_NEXT(advsm)->chan, advsm->sec_phy,
@@ -2327,15 +2328,13 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm,
 
     sch = &sync->sch;
 
-    advsm->periodic_adv_event_start_time_remainder += advsm->periodic_adv_itvl_rem_usec;
-    if (advsm->periodic_adv_event_start_time_remainder >= 31) {
-        advsm->periodic_adv_event_start_time++;
-        advsm->periodic_adv_event_start_time_remainder -= 31;
-    }
+    ble_ll_tmr_add_u(&advsm->periodic_adv_event_start_time,
+                     &advsm->periodic_adv_event_start_time_remainder,
+                     advsm->periodic_adv_itvl_rem_usec);
 
     sch->start_time = advsm->periodic_adv_event_start_time;
     sch->remainder = advsm->periodic_adv_event_start_time_remainder;
-    sch->end_time = sch->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs);
+    sch->end_time = sch->start_time + ble_ll_tmr_u2t_up(max_usecs);
     sch->start_time -= g_ble_ll_sched_offset_ticks;
 
     rc = ble_ll_sched_periodic_adv(sch, first_pdu);
@@ -2415,22 +2414,22 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm)
     max_usecs = ble_ll_pdu_tx_time_get(sync_next->payload_len, advsm->sec_phy);
 
     sync_next->start_time = sync->sch.end_time +
-                            ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY));
+                            ble_ll_tmr_u2t_up(BLE_LL_MAFS +
+                                              MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY));
 
     sch = &sync_next->sch;
     sch->start_time = sync_next->start_time - g_ble_ll_sched_offset_ticks;
 
     /* adjust for previous packets remainder */
     sch->remainder = sync->sch.remainder;
-    sch->end_time = sync_next->start_time +
-                    ble_ll_usecs_to_ticks_round_up(max_usecs);
+    sch->end_time = sync_next->start_time + ble_ll_tmr_u2t_up(max_usecs);
 
     /* here we can use ble_ll_sched_adv_new as we don't care about timing */
     ble_ll_sched_adv_new(&sync_next->sch, ble_ll_adv_sync_next_scheduled,
                          sync_next);
 
     /* if we are pass advertising interval, drop chain */
-    if (CPUTIME_GT(sch->end_time, advsm->periodic_adv_event_start_time +
+    if (LL_TMR_GT(sch->end_time, advsm->periodic_adv_event_start_time +
                                   advsm->periodic_adv_itvl_ticks)) {
         STATS_INC(ble_ll_stats, periodic_chain_drop_event);
         ble_ll_sched_rmv_elem(&sync->sch);
@@ -2532,7 +2531,6 @@ static void
 ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm)
 {
     uint32_t usecs;
-    uint32_t ticks;
 
     /*
      * The Advertising DID is not required to change when a SyncInfo field is
@@ -2560,21 +2558,16 @@ ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm)
     advsm->periodic_crcinit = ble_ll_rand() & 0xffffff;
 
     usecs = (uint32_t)advsm->periodic_adv_itvl_max * BLE_LL_ADV_PERIODIC_ITVL;
-    ticks = os_cputime_usecs_to_ticks(usecs);
 
-    advsm->periodic_adv_itvl_rem_usec = (usecs - os_cputime_ticks_to_usecs(ticks));
-    if (advsm->periodic_adv_itvl_rem_usec == 31) {
-        advsm->periodic_adv_itvl_rem_usec = 0;
-        ticks++;
-    }
-    advsm->periodic_adv_itvl_ticks = ticks;
+    advsm->periodic_adv_itvl_ticks = ble_ll_tmr_u2t_r(usecs,
+                                                      &advsm->periodic_adv_itvl_rem_usec);
 
     /* There is no point in starting periodic advertising until next advertising
      * event since SyncInfo is needed for synchronization
      */
     advsm->periodic_adv_event_start_time_remainder = 0;
     advsm->periodic_adv_event_start_time = advsm->adv_pdu_start_time +
-                      os_cputime_usecs_to_ticks(advsm->adv_itvl_usecs + 5000);
+                      ble_ll_tmr_u2t(advsm->adv_itvl_usecs + 5000);
 
     ble_ll_adv_sync_schedule(advsm, true);
 }
@@ -2747,8 +2740,8 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
     earliest_start_time = ble_ll_rfmgmt_enable_now();
 
     start_delay_us = ble_ll_rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000);
-    advsm->adv_pdu_start_time = os_cputime_get32() +
-                                os_cputime_usecs_to_ticks(start_delay_us);
+    advsm->adv_pdu_start_time = ble_ll_tmr_get() +
+                                ble_ll_tmr_u2t(start_delay_us);
 
     ble_ll_adv_set_sched(advsm);
 
@@ -3760,8 +3753,8 @@ ble_ll_adv_periodic_check_data_itvl(uint16_t payload_len, uint16_t props,
         pdu_len = ble_ll_adv_sync_get_pdu_len(payload_len, &offset, props);
 
         max_usecs += ble_ll_pdu_tx_time_get(pdu_len, phy);
-        max_usecs += ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS +
-                                MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY));
+        max_usecs += ble_ll_tmr_u2t_up(BLE_LL_MAFS +
+                                       MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY));
     }
 
     itvl_usecs = (uint32_t)itvl * BLE_LL_ADV_PERIODIC_ITVL;
@@ -4630,8 +4623,7 @@ ble_ll_adv_reschedule_event(struct ble_ll_adv_sm *advsm)
         if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
             max_delay_ticks = 0;
         } else {
-            max_delay_ticks =
-                    os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000);
+            max_delay_ticks = ble_ll_tmr_u2t(BLE_LL_ADV_DELAY_MS_MAX * 1000);
         }
 
         rc = ble_ll_sched_adv_reschedule(sch, max_delay_ticks);
@@ -4718,7 +4710,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
          * add the random advDelay as the scheduling code will do that.
          */
         itvl = advsm->adv_itvl_usecs;
-        tick_itvl = os_cputime_usecs_to_ticks(itvl);
+        tick_itvl = ble_ll_tmr_u2t(itvl);
         advsm->adv_event_start_time += tick_itvl;
         advsm->adv_pdu_start_time = advsm->adv_event_start_time;
 
@@ -4728,7 +4720,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
          */
         start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
 
-        delta_t = (int32_t)(start_time - os_cputime_get32());
+        delta_t = (int32_t)(start_time - ble_ll_tmr_get());
         if (delta_t < 0) {
             /*
              * NOTE: we just the same interval that we calculated earlier.
@@ -4757,14 +4749,14 @@ 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 = ble_ll_tmr_get() +
                                     g_ble_ll_sched_offset_ticks;
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
         /* If we're past aux (unlikely, but can happen), just drop an event */
         if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) &&
                 advsm->aux_active &&
-                CPUTIME_GT(advsm->adv_pdu_start_time,
+                LL_TMR_GT(advsm->adv_pdu_start_time,
                            AUX_CURRENT(advsm)->start_time)) {
             ble_ll_adv_drop_event(advsm);
             return;
@@ -4777,7 +4769,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
     /* check if advertising timed out */
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
     if (advsm->duration &&
-        CPUTIME_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) {
+        LL_TMR_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) {
         /* Legacy PDUs need to be stop here.
          * For ext adv it will be stopped when AUX is done (unless it was
          * dropped so check if AUX is active here as well).
@@ -4791,7 +4783,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
     }
 #else
     if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) &&
-        CPUTIME_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) {
+        LL_TMR_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) {
         ble_ll_adv_sm_stop_timeout(advsm);
         return;
     }
@@ -4896,7 +4888,7 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm)
 
     /* Check if advertising timed out */
     if (advsm->duration &&
-        CPUTIME_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) {
+        LL_TMR_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) {
         ble_ll_adv_sm_stop_timeout(advsm);
         return;
     }
diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c
index 2fb6586..d3579ed 100644
--- a/nimble/controller/src/ble_ll_conn.c
+++ b/nimble/controller/src/ble_ll_conn.c
@@ -23,7 +23,6 @@
 #include <assert.h>
 #include "syscfg/syscfg.h"
 #include "os/os.h"
-#include "os/os_cputime.h"
 #include "nimble/ble.h"
 #include "nimble/hci_common.h"
 #include "nimble/ble_hci_trans.h"
@@ -37,6 +36,7 @@
 #include "controller/ble_ll_adv.h"
 #include "controller/ble_ll_trace.h"
 #include "controller/ble_ll_rfmgmt.h"
+#include "controller/ble_ll_tmr.h"
 #include "controller/ble_phy.h"
 #include "controller/ble_ll_utils.h"
 #include "ble_ll_conn_priv.h"
@@ -428,19 +428,7 @@ void
 ble_ll_conn_itvl_to_ticks(uint32_t itvl, uint32_t *itvl_ticks,
                           uint8_t *itvl_usecs)
 {
-    uint32_t ticks;
-    uint32_t usecs;
-
-    usecs = itvl * BLE_LL_CONN_ITVL_USECS;
-    ticks = os_cputime_usecs_to_ticks(usecs);
-    usecs = usecs - os_cputime_ticks_to_usecs(ticks);
-    if (usecs == 31) {
-        usecs = 0;
-        ++ticks;
-    }
-
-    *itvl_ticks = ticks;
-    *itvl_usecs = usecs;
+    *itvl_ticks = ble_ll_tmr_u2t_r(itvl * BLE_LL_CONN_ITVL_USECS, itvl_usecs);
 }
 
 /**
@@ -495,7 +483,7 @@ ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2)
     int rc;
 
     /* Set time that we last serviced the schedule */
-    if (CPUTIME_LT(s1->last_scheduled, s2->last_scheduled)) {
+    if (LL_TMR_LT(s1->last_scheduled, s2->last_scheduled)) {
         rc = 1;
     } else {
         rc = 0;
@@ -518,7 +506,7 @@ ble_ll_conn_get_ce_end_time(void)
     if (g_ble_ll_conn_cur_sm) {
         ce_end_time = g_ble_ll_conn_cur_sm->ce_end_time;
     } else {
-        ce_end_time = os_cputime_get32();
+        ce_end_time = ble_ll_tmr_get();
     }
     return ce_end_time;
 }
@@ -779,17 +767,17 @@ ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm)
 #else
     uint32_t ce_end;
     uint32_t next_sched_time;
+    uint8_t rem_us;
 
     /* Calculate time at which next connection event will start */
     /* 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;
-    }
+    rem_us = connsm->anchor_point_usecs;
+    ble_ll_tmr_add_u(&ce_end, &rem_us, connsm->conn_itvl_usecs);
 
     if (ble_ll_sched_next_time(&next_sched_time)) {
-        if (CPUTIME_LT(next_sched_time, ce_end)) {
+        if (LL_TMR_LT(next_sched_time, ce_end)) {
             ce_end = next_sched_time;
         }
     }
@@ -1112,8 +1100,8 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm)
         }
 #endif
 
-        ticks = os_cputime_usecs_to_ticks(ticks);
-        if (CPUTIME_LT(os_cputime_get32() + ticks, next_event_time)) {
+        ticks = ble_ll_tmr_u2t(ticks);
+        if (LL_TMR_LT(ble_ll_tmr_get() + ticks, next_event_time)) {
             md = 1;
         }
     }
@@ -1447,7 +1435,7 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
     }
 
     /* Set time that we last serviced the schedule */
-    connsm->last_scheduled = os_cputime_get32();
+    connsm->last_scheduled = ble_ll_tmr_get();
     return rc;
 }
 
@@ -1517,7 +1505,7 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime,
         usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
 
         ticks = (uint32_t)(next_sched_time - begtime);
-        allowed_usecs = os_cputime_ticks_to_usecs(ticks);
+        allowed_usecs = ble_ll_tmr_t2u(ticks);
         if ((usecs + add_usecs) >= allowed_usecs) {
             rc = 0;
         }
@@ -2004,26 +1992,19 @@ void
 ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
                        uint32_t *anchor, uint8_t *anchor_usecs)
 {
-    uint32_t ticks;
     uint32_t itvl;
 
     itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
 
+    *anchor = connsm->anchor_point;
+    *anchor_usecs = connsm->anchor_point_usecs;
+
     if ((int16_t)(conn_event - connsm->event_cntr) < 0) {
         itvl *= connsm->event_cntr - conn_event;
-        ticks = os_cputime_usecs_to_ticks(itvl);
-        *anchor = connsm->anchor_point - ticks;
+        ble_ll_tmr_sub(anchor, anchor_usecs, itvl);
     } else {
         itvl *= conn_event - connsm->event_cntr;
-        ticks = os_cputime_usecs_to_ticks(itvl);
-        *anchor = connsm->anchor_point + ticks;
-    }
-
-    *anchor_usecs = connsm->anchor_point_usecs;
-    *anchor_usecs += (itvl - os_cputime_ticks_to_usecs(ticks));
-    if (*anchor_usecs >= 31) {
-        (*anchor)++;
-        *anchor_usecs -= 31;
+        ble_ll_tmr_add(anchor, anchor_usecs, itvl);
     }
 }
 #endif
@@ -2047,7 +2028,6 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
     uint32_t max_ww;
 #endif
     struct ble_ll_conn_upd_req *upd;
-    uint32_t ticks;
     uint32_t usecs;
 
     /* XXX: deal with connection request procedure here as well */
@@ -2096,15 +2076,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
     /* 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;
+        ble_ll_tmr_add_u(&connsm->anchor_point, &connsm->anchor_point_usecs,
+                         connsm->conn_itvl_usecs);
     } else {
-        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;
+        ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs,
+                       itvl);
     }
 
     /*
@@ -2140,14 +2116,8 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *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;
-            }
+            ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs,
+                           usecs);
         }
 
         /* Reset the starting point of the connection supervision timeout */
@@ -2266,7 +2236,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
         }
         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 += ble_ll_tmr_u2t(cur_ww + connsm->slave_cur_tx_win_usecs);
     }
 #endif
     itvl -= g_ble_ll_sched_offset_ticks;
@@ -2298,7 +2268,6 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
     uint8_t *evbuf;
 #endif
 #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL)
-    uint32_t endtime;
     uint32_t usecs;
 #endif
 
@@ -2311,7 +2280,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
     connsm->csmflags.cfbit.pkt_rxd = 0;
 
     /* Consider time created the last scheduled time */
-    connsm->last_scheduled = os_cputime_get32();
+    connsm->last_scheduled = ble_ll_tmr_get();
 
     /*
      * Set the last rxd pdu time since this is where we want to start the
@@ -2356,25 +2325,22 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
         }
 
         /* 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->anchor_point = rxhdr->beg_cputime;
+        connsm->anchor_point_usecs = 0;
+        ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs,
+                       usecs);
 
         connsm->slave_cur_tx_win_usecs =
             connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
 #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
         connsm->ce_end_time = connsm->anchor_point +
             g_ble_ll_sched_data.sch_ticks_per_period +
-            os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
+            ble_ll_tmr_u2t(connsm->slave_cur_tx_win_usecs) + 1;
 
 #else
         connsm->ce_end_time = connsm->anchor_point +
             (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_TICKS_PER_SLOT)
-            + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
+            + ble_ll_tmr_u2t(connsm->slave_cur_tx_win_usecs) + 1;
 #endif
         connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS;
 
@@ -2571,7 +2537,7 @@ ble_ll_conn_event_end(struct ble_npl_event *ev)
         ble_err = BLE_ERR_CONN_SPVN_TMO;
     }
     /* XXX: Convert to ticks to usecs calculation instead??? */
-    tmo = os_cputime_usecs_to_ticks(tmo);
+    tmo = ble_ll_tmr_u2t(tmo);
     if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) {
         ble_ll_conn_end(connsm, ble_err);
         return;
@@ -3264,8 +3230,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
         connsm->cons_rxd_bad_crc = 0;
 
         /* Set last valid received pdu time (resets supervision timer) */
-        connsm->last_rxd_pdu_cputime = begtime +
-                                        os_cputime_usecs_to_ticks(add_usecs);
+        connsm->last_rxd_pdu_cputime = begtime + ble_ll_tmr_u2t(add_usecs);
 
         /*
          * Check for valid LLID before proceeding. We have seen some weird
diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c
index 432045e..78cf075 100644
--- a/nimble/controller/src/ble_ll_ctrl.c
+++ b/nimble/controller/src/ble_ll_ctrl.c
@@ -29,6 +29,7 @@
 #include "controller/ble_ll_trace.h"
 #include "controller/ble_hw.h"
 #include "controller/ble_ll_sync.h"
+#include "controller/ble_ll_tmr.h"
 #include "ble_ll_conn_priv.h"
 
 #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
@@ -2439,8 +2440,7 @@ ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm)
 
         /* Set terminate "timeout" */
         usecs = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000;
-        connsm->terminate_timeout = os_cputime_get32() +
-            os_cputime_usecs_to_ticks(usecs);
+        connsm->terminate_timeout = ble_ll_tmr_get() + ble_ll_tmr_u2t(usecs);
     }
 }
 
diff --git a/nimble/controller/src/ble_ll_dtm.c b/nimble/controller/src/ble_ll_dtm.c
index 8c91677..2c787da 100644
--- a/nimble/controller/src/ble_ll_dtm.c
+++ b/nimble/controller/src/ble_ll_dtm.c
@@ -29,6 +29,7 @@
 #include "controller/ble_phy.h"
 #include "controller/ble_ll_sched.h"
 #include "controller/ble_ll_rfmgmt.h"
+#include "controller/ble_ll_tmr.h"
 #include "ble_ll_dtm_priv.h"
 
 STATS_SECT_START(ble_ll_dtm_stats)
@@ -153,11 +154,8 @@ ble_ll_dtm_set_next(struct dtm_ctx *ctx)
     struct ble_ll_sched_item *sch = &ctx->sch;
 
     ctx->pdu_start_ticks += ctx->itvl_ticks;
-    ctx->pdu_start_usecs += ctx->itvl_rem_usec;
-    if (ctx->pdu_start_usecs >= 31) {
-       ctx->pdu_start_ticks++;
-       ctx->pdu_start_usecs -= 31;
-    }
+    ble_ll_tmr_add_u(&ctx->pdu_start_ticks, &ctx->pdu_start_usecs,
+                     ctx->itvl_rem_usec);
 
     sch->start_time = ctx->pdu_start_ticks;
     sch->remainder = ctx->pdu_start_usecs;
@@ -278,7 +276,6 @@ ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len,
 {
     uint32_t l;
     uint32_t itvl_usec;
-    uint32_t itvl_ticks;
 
     /* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */
     l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode);
@@ -290,13 +287,7 @@ ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len,
     }
 #endif
 
-    itvl_ticks = os_cputime_usecs_to_ticks(itvl_usec);
-    ctx->itvl_rem_usec = (itvl_usec - os_cputime_ticks_to_usecs(itvl_ticks));
-    if (ctx->itvl_rem_usec == 31) {
-        ctx->itvl_rem_usec = 0;
-        ++itvl_ticks;
-    }
-    ctx->itvl_ticks = itvl_ticks;
+    ctx->itvl_ticks = ble_ll_tmr_u2t_r(itvl_usec, &ctx->itvl_rem_usec);
 }
 
 static int
@@ -410,7 +401,7 @@ ble_ll_dtm_rx_start(void)
 #endif
 
     OS_ENTER_CRITICAL(sr);
-    rc = ble_phy_rx_set_start_time(os_cputime_get32(), 0);
+    rc = ble_phy_rx_set_start_time(ble_ll_tmr_get(), 0);
     OS_EXIT_CRITICAL(sr);
     if (rc && rc != BLE_PHY_ERR_RX_LATE) {
         return rc;
diff --git a/nimble/controller/src/ble_ll_rfmgmt.c b/nimble/controller/src/ble_ll_rfmgmt.c
index 986645f..f73f6b3 100644
--- a/nimble/controller/src/ble_ll_rfmgmt.c
+++ b/nimble/controller/src/ble_ll_rfmgmt.c
@@ -22,11 +22,11 @@
 #include <assert.h>
 #include <stddef.h>
 #include "syscfg/syscfg.h"
-#include "os/os_cputime.h"
 #include "controller/ble_phy.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_sched.h"
 #include "controller/ble_ll_rfmgmt.h"
+#include "controller/ble_ll_tmr.h"
 #include "ble_ll_priv.h"
 
 #if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0
@@ -41,7 +41,7 @@ struct ble_ll_rfmgmt_data {
     enum ble_ll_rfmgmt_state state;
     uint16_t ticks_to_enabled;
 
-    struct hal_timer timer;
+    struct ble_ll_tmr timer;
     bool timer_scheduled;
     uint32_t timer_scheduled_at;
 
@@ -64,7 +64,7 @@ ble_ll_rfmgmt_enable(void)
 
     if (g_ble_ll_rfmgmt_data.state == RFMGMT_STATE_OFF) {
         g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_ENABLING;
-        g_ble_ll_rfmgmt_data.enabled_at = os_cputime_get32();
+        g_ble_ll_rfmgmt_data.enabled_at = ble_ll_tmr_get();
         ble_phy_rfclk_enable();
         BLE_LL_DEBUG_GPIO(RFMGMT, 1);
     }
@@ -101,7 +101,7 @@ ble_ll_rfmgmt_timer_reschedule(void)
         enable_at = rfmgmt->enable_sched_at;
     } else {
         rfmgmt->timer_scheduled = false;
-        os_cputime_timer_stop(&rfmgmt->timer);
+        ble_ll_tmr_stop(&rfmgmt->timer);
         return;
     }
 
@@ -118,7 +118,7 @@ ble_ll_rfmgmt_timer_reschedule(void)
         }
 
         rfmgmt->timer_scheduled = false;
-        os_cputime_timer_stop(&rfmgmt->timer);
+        ble_ll_tmr_stop(&rfmgmt->timer);
     }
 
     /*
@@ -128,14 +128,14 @@ ble_ll_rfmgmt_timer_reschedule(void)
      * such case it's absolutely harmless since we already have clock enabled
      * and this will do nothing.
      */
-    if (CPUTIME_LEQ(enable_at, os_cputime_get32())) {
+    if (CPUTIME_LEQ(enable_at, ble_ll_tmr_get())) {
         ble_ll_rfmgmt_enable();
         return;
     }
 
     rfmgmt->timer_scheduled = true;
     rfmgmt->timer_scheduled_at = enable_at;
-    os_cputime_timer_start(&rfmgmt->timer, enable_at);
+    ble_ll_tmr_start(&rfmgmt->timer, enable_at);
 }
 
 static void
@@ -156,7 +156,7 @@ ble_ll_rfmgmt_release_ev(struct ble_npl_event *ev)
 
     OS_ENTER_CRITICAL(sr);
 
-    now = os_cputime_get32();
+    now = ble_ll_tmr_get();
 
     can_disable = true;
     lls = ble_ll_state_get();
@@ -191,7 +191,7 @@ ble_ll_rfmgmt_ticks_to_enabled(void)
         rem_ticks = rfmgmt->ticks_to_enabled;
         break;
     case RFMGMT_STATE_ENABLING:
-        now = os_cputime_get32();
+        now = ble_ll_tmr_get();
         if (CPUTIME_LT(now, rfmgmt->enabled_at + rfmgmt->ticks_to_enabled)) {
             rem_ticks = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled - now;
             break;
@@ -220,10 +220,10 @@ ble_ll_rfmgmt_init(void)
     rfmgmt->state = RFMGMT_STATE_OFF;
 
     rfmgmt->ticks_to_enabled =
-            ble_ll_usecs_to_ticks_round_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME));
+            ble_ll_tmr_u2t_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME));
 
     rfmgmt->timer_scheduled = false;
-    os_cputime_timer_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL);
+    ble_ll_tmr_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL);
 
     ble_npl_event_init(&rfmgmt->release_ev, ble_ll_rfmgmt_release_ev, NULL);
 }
@@ -235,7 +235,7 @@ ble_ll_rfmgmt_reset(void)
 
     rfmgmt->timer_scheduled = false;
     rfmgmt->timer_scheduled_at = 0;
-    os_cputime_timer_stop(&rfmgmt->timer);
+    ble_ll_tmr_stop(&rfmgmt->timer);
 
     ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
 
@@ -312,7 +312,7 @@ ble_ll_rfmgmt_enable_now(void)
     ble_ll_rfmgmt_enable();
 
     if (rfmgmt->state == RFMGMT_STATE_ENABLED) {
-        enabled_at = os_cputime_get32();
+        enabled_at = ble_ll_tmr_get();
     } else {
         enabled_at = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled + 1;
     }
diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c
index 987ab46..f96aae6 100644
--- a/nimble/controller/src/ble_ll_scan.c
+++ b/nimble/controller/src/ble_ll_scan.c
@@ -23,7 +23,6 @@
 #include <assert.h>
 #include "syscfg/syscfg.h"
 #include "os/os.h"
-#include "os/os_cputime.h"
 #include "nimble/ble.h"
 #include "nimble/hci_common.h"
 #include "nimble/ble_hci_trans.h"
@@ -35,6 +34,7 @@
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
 #include "controller/ble_ll_scan_aux.h"
 #endif
+#include "controller/ble_ll_tmr.h"
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_whitelist.h"
 #include "controller/ble_ll_resolv.h"
@@ -138,7 +138,7 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm);
 static inline uint32_t
 ble_ll_scan_time_hci_to_ticks(uint16_t value)
 {
-    return os_cputime_usecs_to_ticks(value * BLE_HCI_SCAN_ITVL);
+    return ble_ll_tmr_u2t(value * BLE_HCI_SCAN_ITVL);
 }
 
 /* See Vol 6 Part B Section 4.4.3.2. Active scanning backoff */
@@ -182,7 +182,7 @@ ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm)
     ble_npl_time_t now;
 
     now = ble_npl_time_get();
-    if (CPUTIME_GEQ(now, scansm->scan_nrpa_timer)) {
+    if (LL_TMR_GEQ(now, scansm->scan_nrpa_timer)) {
         /* Generate new NRPA */
         ble_ll_rand_data_get(scansm->scan_nrpa, BLE_DEV_ADDR_LEN);
         scansm->scan_nrpa[5] &= ~0xc0;
@@ -781,7 +781,7 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
     ble_phy_mode_set(phy_mode, phy_mode);
 #endif
 
-    rc = ble_phy_rx_set_start_time(os_cputime_get32() +
+    rc = ble_phy_rx_set_start_time(ble_ll_tmr_get() +
                                    g_ble_ll_sched_offset_ticks, 0);
     if (!rc || rc == BLE_PHY_ERR_RX_LATE) {
         /* If we are late here, it is still OK because we keep scanning.
@@ -824,7 +824,7 @@ ble_ll_scan_move_window_to(struct ble_ll_scan_phy *scanp, uint32_t time)
      */
 
     end_time = scanp->timing.start_time + scanp->timing.window;
-    while (CPUTIME_GEQ(time, end_time)) {
+    while (LL_TMR_GEQ(time, end_time)) {
         scanp->timing.start_time += scanp->timing.interval;
         scanp->scan_chan = ble_ll_scan_get_next_adv_prim_chan(scanp->scan_chan);
         end_time = scanp->timing.start_time + scanp->timing.window;
@@ -846,8 +846,8 @@ ble_ll_scan_is_inside_window(struct ble_ll_scan_phy *scanp, uint32_t time)
         return true;
     }
 
-    return CPUTIME_GEQ(time, start_time) &&
-           CPUTIME_LT(time, start_time + scanp->timing.window);
+    return LL_TMR_GEQ(time, start_time) &&
+           LL_TMR_LT(time, start_time + scanp->timing.window);
 }
 
 /**
@@ -862,7 +862,7 @@ ble_ll_scan_sm_stop(int chk_disable)
 
     /* Stop the scanning timer  */
     scansm = &g_ble_ll_scan_sm;
-    os_cputime_timer_stop(&scansm->scan_timer);
+    ble_ll_tmr_stop(&scansm->scan_timer);
 
     /* Only set state if we are currently in a scan window */
     if (chk_disable) {
@@ -965,7 +965,7 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
     }
 
     /* Start scan at 1st window */
-    os_cputime_timer_start(&scansm->scan_timer, scanp->timing.start_time);
+    ble_ll_tmr_start(&scansm->scan_timer, scanp->timing.start_time);
 
     return BLE_ERR_SUCCESS;
 }
@@ -1025,7 +1025,7 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev)
 
     OS_ENTER_CRITICAL(sr);
     if (!scansm->scan_enabled) {
-        os_cputime_timer_stop(&scansm->scan_timer);
+        ble_ll_tmr_stop(&scansm->scan_timer);
         ble_ll_rfmgmt_scan_changed(false, 0);
         ble_ll_rfmgmt_release();
         OS_EXIT_CRITICAL(sr);
@@ -1040,7 +1040,7 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev)
         return;
     }
 
-    now = os_cputime_get32();
+    now = ble_ll_tmr_get();
 
     inside_window = ble_ll_scan_is_inside_window(scanp, now);
 
@@ -1054,8 +1054,8 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev)
          * inside window or has next window earlier than current PHY.
          */
         if (!inside_window &&
-            ((inside_window_next || CPUTIME_LEQ(scanp_next->timing.start_time,
-                                                scanp->timing.start_time)))) {
+            ((inside_window_next || LL_TMR_LEQ(scanp_next->timing.start_time,
+                                               scanp->timing.start_time)))) {
             scansm->scanp = scanp_next;
             scansm->scanp_next = scanp;
             scanp = scansm->scanp;
@@ -1126,7 +1126,7 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev)
     }
 
     OS_EXIT_CRITICAL(sr);
-    os_cputime_timer_start(&scansm->scan_timer, next_proc_time);
+    ble_ll_tmr_start(&scansm->scan_timer, next_proc_time);
 }
 
 /**
@@ -1675,7 +1675,7 @@ ble_ll_scan_chk_resume(void)
             return;
         }
 
-        now = os_cputime_get32();
+        now = ble_ll_tmr_get();
         if (ble_ll_state_get() == BLE_LL_STATE_STANDBY &&
             ble_ll_scan_is_inside_window(scansm->scanp, now)) {
             /* Turn on the receiver and set state */
@@ -2643,7 +2643,7 @@ ble_ll_scan_common_init(void)
 #endif
 
     /* Initialize scanning timer */
-    os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm);
+    ble_ll_tmr_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm);
 
     /* Initialize extended scan timers */
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c
index cd60014..94b45e8 100644
--- a/nimble/controller/src/ble_ll_sched.c
+++ b/nimble/controller/src/ble_ll_sched.c
@@ -20,7 +20,6 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <string.h>
-#include "os/os_cputime.h"
 #include "ble/xcvr.h"
 #include "controller/ble_phy.h"
 #include "controller/ble_ll.h"
@@ -30,13 +29,14 @@
 #include "controller/ble_ll_scan_aux.h"
 #include "controller/ble_ll_rfmgmt.h"
 #include "controller/ble_ll_trace.h"
+#include "controller/ble_ll_tmr.h"
 #include "controller/ble_ll_sync.h"
 #include "ble_ll_priv.h"
 #include "ble_ll_conn_priv.h"
 
 #define BLE_LL_SCHED_MAX_DELAY_ANY      (0x7fffffff)
 
-static struct hal_timer g_ble_ll_sched_timer;
+static struct ble_ll_tmr g_ble_ll_sched_timer;
 
 uint8_t g_ble_ll_sched_offset_ticks;
 
@@ -102,8 +102,8 @@ ble_ll_sched_check_overlap(struct ble_ll_sched_item *sch1,
     /* Note: item ranges are defined as [start, end) so items do not overlap
      *       if one item starts at the same time as another ends.
      */
-    return CPUTIME_GT(sch1->end_time, sch2->start_time) &&
-           CPUTIME_GT(sch2->end_time, sch1->start_time);
+    return LL_TMR_GT(sch1->end_time, sch2->start_time) &&
+           LL_TMR_GT(sch2->end_time, sch1->start_time);
 }
 
 static void
@@ -171,7 +171,7 @@ ble_ll_sched_q_head_changed(void)
 
     g_ble_ll_sched_q_head_changed = 1;
 
-    os_cputime_timer_stop(&g_ble_ll_sched_timer);
+    ble_ll_tmr_stop(&g_ble_ll_sched_timer);
 }
 
 static inline void
@@ -190,7 +190,7 @@ ble_ll_sched_restart(void)
     ble_ll_rfmgmt_sched_changed(first);
 
     if (first) {
-        os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time);
+        ble_ll_tmr_start(&g_ble_ll_sched_timer, first->start_time);
     }
 }
 
@@ -219,7 +219,7 @@ ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay,
     }
 
     TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
-        if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
+        if (LL_TMR_LEQ(sch->end_time, entry->start_time)) {
             TAILQ_INSERT_BEFORE(entry, sch, link);
             sch->enqueued = 1;
             goto done;
@@ -251,7 +251,7 @@ ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay,
                  */
                 sch->start_time = entry->end_time + 1;
 
-                if ((max_delay == 0) || CPUTIME_GEQ(sch->start_time,
+                if ((max_delay == 0) || LL_TMR_GEQ(sch->start_time,
                                                     max_start_time)) {
                     sch->enqueued = 0;
                     goto done;
@@ -301,14 +301,14 @@ ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1,
     int rc;
 
     rc = 1;
-    if (CPUTIME_LT(s1->start_time, s2->start_time)) {
+    if (LL_TMR_LT(s1->start_time, s2->start_time)) {
         /* Make sure this event does not overlap current event */
-        if (CPUTIME_LEQ(s1->end_time, s2->start_time)) {
+        if (LL_TMR_LEQ(s1->end_time, s2->start_time)) {
             rc = 0;
         }
     } else {
         /* Check for overlap */
-        if (CPUTIME_GEQ(s1->start_time, s2->end_time)) {
+        if (LL_TMR_GEQ(s1->start_time, s2->end_time)) {
             rc = 0;
         }
     }
@@ -330,7 +330,7 @@ ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch)
 
     if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
         ce_end_time = ble_ll_conn_get_ce_end_time();
-        if (CPUTIME_GT(ce_end_time, sch->start_time)) {
+        if (LL_TMR_GT(ce_end_time, sch->start_time)) {
             rc = 1;
         }
     }
@@ -377,7 +377,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
 #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL)
     case BLE_LL_CONN_ROLE_SLAVE:
         usecs = connsm->slave_cur_window_widening;
-        sch->start_time -= (os_cputime_usecs_to_ticks(usecs) + 1);
+        sch->start_time -= (ble_ll_tmr_u2t(usecs) + 1);
         sch->remainder = 0;
         break;
 #endif
@@ -389,7 +389,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
     sch->end_time = connsm->ce_end_time;
 
     /* Better be past current time or we just leave */
-    if (CPUTIME_LT(sch->start_time, os_cputime_get32())) {
+    if (LL_TMR_LT(sch->start_time, ble_ll_tmr_get())) {
         return -1;
     }
 
@@ -491,8 +491,8 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
      * 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 = os_cputime_usecs_to_ticks(g_ble_ll_sched_data.sch_ticks_per_period);
-    adv_rxend = os_cputime_get32();
+    dur = ble_ll_tmr_u2t(g_ble_ll_sched_data.sch_ticks_per_period);
+    adv_rxend = ble_ll_tmr_get();
     if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) {
         /*
          * We received packet on advertising channel which means this is a legacy
@@ -584,14 +584,14 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
         rc = 0;
         connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET);
     } else {
-        os_cputime_timer_stop(&g_ble_ll_sched_timer);
+        ble_ll_tmr_stop(&g_ble_ll_sched_timer);
         TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
             /* Set these because overlap function needs them to be set */
             sch->start_time = earliest_start;
             sch->end_time = earliest_end;
 
             /* We can insert if before entry in list */
-            if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
+            if (LL_TMR_LEQ(sch->end_time, entry->start_time)) {
                 if ((earliest_start - initial_start) <= itvl_t) {
                     rc = 0;
                     TAILQ_INSERT_BEFORE(entry, sch, link);
@@ -623,7 +623,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
              * 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);
+            dur = ble_ll_tmr_t2u(earliest_start - initial_start);
             connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS;
         }
     }
@@ -650,7 +650,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
 
     OS_EXIT_CRITICAL(sr);
 
-    os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+    ble_ll_tmr_start(&g_ble_ll_sched_timer, sch->start_time);
 
     return rc;
 }
@@ -712,7 +712,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
      * 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.
      */
-    adv_rxend = os_cputime_get32();
+    adv_rxend = ble_ll_tmr_get();
     if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) {
         /*
          * We received packet on advertising channel which means this is a legacy
@@ -762,8 +762,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
     rc = ble_ll_sched_insert(sch, max_delay, preempt_none);
 
     if (rc == 0) {
-        connsm->tx_win_off = os_cputime_ticks_to_usecs(sch->start_time -
-                                                       orig_start_time) /
+        connsm->tx_win_off = ble_ll_tmr_t2u(sch->start_time - orig_start_time) /
                              BLE_LL_CONN_TX_OFF_USECS;
 
         connsm->anchor_point = sch->start_time + g_ble_ll_sched_offset_ticks;
@@ -807,7 +806,7 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
      * 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;
+                      ble_ll_tmr_u2t(connsm->slave_cur_window_widening) - 1;
     sch->end_time = connsm->ce_end_time;
     sch->remainder = 0;
 
@@ -822,22 +821,6 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
     return rc;
 }
 
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-static inline uint32_t
-usecs_to_ticks_fast(uint32_t usecs)
-{
-    uint32_t ticks;
-
-    if (usecs <= 31249) {
-        ticks = (usecs * 137439) / 4194304;
-    } else {
-        ticks = os_cputime_usecs_to_ticks(usecs);
-    }
-
-    return ticks;
-}
-#endif
-
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER)
 /*
  * Determines if the schedule item overlaps the currently running schedule
@@ -863,7 +846,7 @@ ble_ll_sched_sync_overlaps_current(struct ble_ll_sched_item *sch)
         return 0;
     }
 
-    return CPUTIME_GT(end_time, sch->start_time);
+    return LL_TMR_GT(end_time, sch->start_time);
 }
 
 int
@@ -873,31 +856,20 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch,
                              int8_t phy_mode)
 {
     uint8_t start_time_rem_usecs;
-    uint8_t window_rem_usecs;
-    uint32_t window_ticks;
     uint32_t start_time;
     uint32_t end_time;
     uint32_t dur;
     int rc = 0;
     os_sr_t sr;
 
-    window_ticks = os_cputime_usecs_to_ticks(window_widening);
-    window_rem_usecs = window_widening - os_cputime_ticks_to_usecs(window_ticks);
-
-    /* adjust for subtraction */
-    anchor_point_usecs += 31;
-    anchor_point--;
+    start_time = anchor_point;
+    start_time_rem_usecs = anchor_point_usecs;
 
-    start_time = anchor_point - window_ticks;
-    start_time_rem_usecs = anchor_point_usecs - window_rem_usecs;
-    if (start_time_rem_usecs >= 31) {
-        start_time++;
-        start_time_rem_usecs -= 31;
-    }
+    ble_ll_tmr_sub(&start_time, &start_time_rem_usecs, window_widening);
 
     dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN),
                                  phy_mode);
-    end_time = start_time + os_cputime_usecs_to_ticks(dur);
+    end_time = start_time + ble_ll_tmr_u2t(dur);
 
     start_time -= g_ble_ll_sched_offset_ticks;
 
@@ -907,7 +879,7 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch,
     sch->end_time = end_time;
 
     /* Better be past current time or we just leave */
-    if (CPUTIME_LEQ(sch->start_time, os_cputime_get32())) {
+    if (LL_TMR_LEQ(sch->start_time, ble_ll_tmr_get())) {
         return -1;
     }
 
@@ -932,28 +904,21 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch,
                   uint32_t beg_cputime, uint32_t rem_usecs,
                   uint32_t offset, int8_t phy_mode)
 {
-    uint32_t start_time_rem_usecs;
-    uint32_t off_rem_usecs;
+    uint8_t start_time_rem_usecs;
     uint32_t start_time;
-    uint32_t off_ticks;
     uint32_t end_time;
     uint32_t dur;
     os_sr_t sr;
     int rc = 0;
 
-    off_ticks = usecs_to_ticks_fast(offset);
-    off_rem_usecs = offset - os_cputime_ticks_to_usecs(off_ticks);
+    start_time = beg_cputime;
+    start_time_rem_usecs = rem_usecs;
 
-    start_time = beg_cputime + off_ticks;
-    start_time_rem_usecs = rem_usecs + off_rem_usecs;
-    if (start_time_rem_usecs >= 31) {
-        start_time++;
-        start_time_rem_usecs -= 31;
-    }
+    ble_ll_tmr_add(&start_time, &start_time_rem_usecs, offset);
 
     dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN),
                                   phy_mode);
-    end_time = start_time + usecs_to_ticks_fast(dur);
+    end_time = start_time + ble_ll_tmr_u2t(dur);
 
     start_time -= g_ble_ll_sched_offset_ticks;
 
@@ -1042,7 +1007,7 @@ ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch,
     if (rc == 0) {
         next = TAILQ_NEXT(sch, link);
         if (next) {
-            if (CPUTIME_LT(next->start_time, max_end_time)) {
+            if (LL_TMR_LT(next->start_time, max_end_time)) {
                 max_end_time = next->start_time;
             }
             rand_ticks = max_end_time - sch->end_time;
@@ -1198,7 +1163,7 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch)
 
     lls = ble_ll_state_get();
 
-    ble_ll_trace_u32x3(BLE_LL_TRACE_ID_SCHED, lls, os_cputime_get32(),
+    ble_ll_trace_u32x3(BLE_LL_TRACE_ID_SCHED, lls, ble_ll_tmr_get(),
                        sch->start_time);
 
     if (lls == BLE_LL_STATE_STANDBY) {
@@ -1282,7 +1247,7 @@ ble_ll_sched_run(void *arg)
         int32_t dt;
 
         /* Make sure we have passed the start time of the first event */
-        dt = (int32_t)(os_cputime_get32() - sch->start_time);
+        dt = (int32_t)(ble_ll_tmr_get() - sch->start_time);
         if (dt > g_ble_ll_sched_max_late) {
             g_ble_ll_sched_max_late = dt;
         }
@@ -1343,12 +1308,12 @@ ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch, uint32_t pdu_time,
     int rc;
 
     offset_us += pdu_time_rem;
-    offset_ticks = usecs_to_ticks_fast(offset_us);
+    offset_ticks = ble_ll_tmr_u2t(offset_us);
 
     sch->start_time = pdu_time + offset_ticks - g_ble_ll_sched_offset_ticks;
-    sch->remainder = offset_us - os_cputime_ticks_to_usecs(offset_ticks);
+    sch->remainder = offset_us - ble_ll_tmr_t2u(offset_ticks);
     /* TODO: make some sane slot reservation */
-    sch->end_time = sch->start_time + usecs_to_ticks_fast(5000);
+    sch->end_time = sch->start_time + ble_ll_tmr_u2t(5000);
 
     OS_ENTER_CRITICAL(sr);
 
@@ -1389,7 +1354,7 @@ int ble_ll_sched_dtm(struct ble_ll_sched_item *sch)
 void
 ble_ll_sched_stop(void)
 {
-    os_cputime_timer_stop(&g_ble_ll_sched_timer);
+    ble_ll_tmr_stop(&g_ble_ll_sched_timer);
 }
 
 /**
@@ -1417,16 +1382,15 @@ ble_ll_sched_init(void)
      * 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.
      */
-    g_ble_ll_sched_offset_ticks =
-        (uint8_t) os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS + 30);
+    g_ble_ll_sched_offset_ticks = ble_ll_tmr_u2t_up(XCVR_TX_SCHED_DELAY_USECS);
 
     /* Initialize cputimer for the scheduler */
-    os_cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
+    ble_ll_tmr_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
 
 #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
     memset(&g_ble_ll_sched_data, 0, sizeof(struct ble_ll_sched_obj));
     g_ble_ll_sched_data.sch_ticks_per_period =
-        os_cputime_usecs_to_ticks(MYNEWT_VAL(BLE_LL_USECS_PER_PERIOD));
+        ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_USECS_PER_PERIOD));
     g_ble_ll_sched_data.sch_ticks_per_epoch = BLE_LL_SCHED_PERIODS *
         g_ble_ll_sched_data.sch_ticks_per_period;
 #endif
diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c
index 7b6208c..31e9984 100644
--- a/nimble/controller/src/ble_ll_sync.c
+++ b/nimble/controller/src/ble_ll_sync.c
@@ -32,6 +32,7 @@
 #include "controller/ble_ll_scan.h"
 #include "controller/ble_ll_resolv.h"
 #include "controller/ble_ll_rfmgmt.h"
+#include "controller/ble_ll_tmr.h"
 
 #include "nimble/ble.h"
 #include "nimble/hci_common.h"
@@ -837,7 +838,7 @@ ble_ll_sync_get_event_end_time(void)
     if (g_ble_ll_sync_sm_current) {
         end_time = g_ble_ll_sync_sm_current->sch.end_time;
     } else {
-        end_time = os_cputime_get32();
+        end_time = ble_ll_tmr_get();
     }
     return end_time;
 }
@@ -1138,14 +1139,12 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust)
 {
     uint32_t cur_ww;
     uint32_t max_ww;
-    uint32_t ticks;
     uint32_t itvl;
-    uint8_t usecs;
     uint16_t skip = sm->skip;
 
     /* don't skip if are establishing sync or we missed last event */
     if (skip && ((sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) ||
-                  CPUTIME_LT(sm->last_anchor_point, sm->anchor_point))) {
+                  LL_TMR_LT(sm->last_anchor_point, sm->anchor_point))) {
         skip = 0;
     }
 
@@ -1153,19 +1152,12 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust)
      * interval if not skipping
      */
     if (skip == 0) {
-        ticks = sm->itvl_ticks;
-        usecs = sm->itvl_usecs;
+        sm->anchor_point += sm->itvl_ticks;
+        ble_ll_tmr_add_u(&sm->anchor_point, &sm->anchor_point_usecs,
+                         sm->itvl_usecs);
     } else {
         itvl = sm->itvl * BLE_LL_SYNC_ITVL_USECS * (1 + skip);
-        ticks = os_cputime_usecs_to_ticks(itvl);
-        usecs = itvl - os_cputime_ticks_to_usecs(ticks);
-    }
-
-    sm->anchor_point += ticks;
-    sm->anchor_point_usecs += usecs;
-    if (sm->anchor_point_usecs >= 31) {
-        sm->anchor_point++;
-        sm->anchor_point_usecs -= 31;
+        ble_ll_tmr_add(&sm->anchor_point, &sm->anchor_point_usecs, itvl);
     }
 
     /* Set event counter to the next event */
@@ -1212,7 +1204,7 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust)
      * BLE_LL_SYNC_ESTABLISH_CNT events before failing regardless of timeout
      */
     if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING)) {
-        if (CPUTIME_GT(sm->anchor_point - os_cputime_usecs_to_ticks(cur_ww),
+        if (LL_TMR_GT(sm->anchor_point - ble_ll_tmr_u2t(cur_ww),
                        sm->last_anchor_point + sm->timeout )) {
             return -1;
         }
@@ -1378,13 +1370,7 @@ ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd,
 
     /* precalculate interval ticks and usecs */
     usecs = sm->itvl * BLE_LL_SYNC_ITVL_USECS;
-    sm->itvl_ticks = os_cputime_usecs_to_ticks(usecs);
-    sm->itvl_usecs = (uint8_t)(usecs -
-                               os_cputime_ticks_to_usecs(sm->itvl_ticks));
-    if (sm->itvl_usecs == 31) {
-        sm->itvl_usecs = 0;
-        sm->itvl_ticks++;
-    }
+    sm->itvl_ticks = ble_ll_tmr_u2t_r(usecs, &sm->itvl_usecs);
 
     /* Channels Mask (37 bits) */
     sm->chanmap[0] = syncinfo[4];
@@ -1417,7 +1403,7 @@ ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd,
     }
 
     /* from now on we only need timeout in ticks */
-    sm->timeout = os_cputime_usecs_to_ticks(sm->timeout);
+    sm->timeout = ble_ll_tmr_u2t(sm->timeout);
 
     sm->phy_mode = rxhdr->rxinfo.phy_mode;
     sm->window_widening = BLE_LL_JITTER_USECS;
@@ -1906,7 +1892,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
     }
 
     /* set params from transfer */
-    sm->timeout = os_cputime_usecs_to_ticks(sync_timeout);
+    sm->timeout = ble_ll_tmr_u2t(sync_timeout);
     sm->skip = max_skip;
     sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT;
     sm->transfer_id = get_le16(sync_ind); /* first two bytes */
@@ -1936,13 +1922,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
     sm->itvl = itvl;
 
     /* precalculate interval ticks and usecs */
-    sm->itvl_ticks = os_cputime_usecs_to_ticks(itvl_usecs);
-    sm->itvl_usecs = (uint8_t)(itvl_usecs -
-                               os_cputime_ticks_to_usecs(sm->itvl_ticks));
-    if (sm->itvl_usecs == 31) {
-        sm->itvl_usecs = 0;
-        sm->itvl_ticks++;
-    }
+    sm->itvl_ticks = ble_ll_tmr_u2t_r(itvl_usecs, &sm->itvl_usecs);
 
     /* Channels Mask (37 bits) */
     sm->chanmap[0] = syncinfo[4];
@@ -1997,8 +1977,8 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
                                                   sync_anchor, sca);
 
     /* spin until we get anchor in future */
-    future = os_cputime_get32() + g_ble_ll_sched_offset_ticks;
-    while (CPUTIME_LT(sm->anchor_point, future)) {
+    future = ble_ll_tmr_get() + g_ble_ll_sched_offset_ticks;
+    while (LL_TMR_LT(sm->anchor_point, future)) {
         if (ble_ll_sync_next_event(sm, ww_adjust) < 0) {
             /* release SM if this failed */
             ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT);
@@ -2040,11 +2020,11 @@ ble_ll_sync_put_syncinfo(struct ble_ll_sync_sm *syncsm,
     conn_cnt = connsm->event_cntr;
 
     /* get anchor for conn event that is before periodic_adv_event_start_time */
-    while (CPUTIME_GT(anchor, syncsm->anchor_point)) {
+    while (LL_TMR_GT(anchor, syncsm->anchor_point)) {
         ble_ll_conn_get_anchor(connsm, --conn_cnt, &anchor, &anchor_usecs);
     }
 
-    offset = os_cputime_ticks_to_usecs(syncsm->anchor_point - anchor);
+    offset = ble_ll_tmr_t2u(syncsm->anchor_point - anchor);
     offset -= anchor_usecs;
     offset += syncsm->anchor_point_usecs;
 
diff --git a/nimble/controller/src/ble_ll_utils.c b/nimble/controller/src/ble_ll_utils.c
index ccdf377..e2fe50c 100644
--- a/nimble/controller/src/ble_ll_utils.c
+++ b/nimble/controller/src/ble_ll_utils.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include "nimble/ble.h"
 #include "controller/ble_ll.h"
+#include "controller/ble_ll_tmr.h"
 #include "controller/ble_ll_utils.h"
 
 /* 37 bits require 5 bytes */
@@ -291,7 +292,7 @@ ble_ll_utils_calc_window_widening(uint32_t anchor_point,
 
     time_since_last_anchor = (int32_t)(anchor_point - last_anchor_point);
     if (time_since_last_anchor > 0) {
-        delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
+        delta_msec = ble_ll_tmr_t2u(time_since_last_anchor) / 1000;
         total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] + MYNEWT_VAL(BLE_LL_SCA);
         window_widening = (total_sca_ppm * delta_msec) / 1000;
     }
diff --git a/nimble/drivers/nrf52/src/ble_phy.c b/nimble/drivers/nrf52/src/ble_phy.c
index 3c7b626..7a12bb5 100644
--- a/nimble/drivers/nrf52/src/ble_phy.c
+++ b/nimble/drivers/nrf52/src/ble_phy.c
@@ -22,6 +22,8 @@
 #include <assert.h>
 #include "syscfg/syscfg.h"
 #include "os/os.h"
+/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */
+#include "os/os_cputime.h"
 #include "ble/xcvr.h"
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"