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 2021/04/20 13:34:13 UTC

[mynewt-core] branch master updated: hw/mcu/cmac: Fix os_cputime and LLT wrap around handling

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-core.git


The following commit(s) were added to refs/heads/master by this push:
     new c9f7279  hw/mcu/cmac: Fix os_cputime and LLT wrap around handling
c9f7279 is described below

commit c9f72793d712365e6bdc0b5a3386f6e3caebee11
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Fri Apr 16 12:08:56 2021 +0200

    hw/mcu/cmac: Fix os_cputime and LLT wrap around handling
    
    os_cputime runs at 32768Hz but it uses LLT internally which runs at
    1MHz. This means both timers will wrap around at different time. This
    means after one of timers wraps around (os_cputime wraps earlier),
    calculations that use values converted between both timers will fail.
    
    To fix this we "manually" extend LLT value to 64-bit internally so it
    takes zillion of years before it wraps around. Also conversions from
    os_cputime (a.k.a. HAL) value to LLT value take os_cputime value wrap
    around into account and return proper 64-bit LLT value.
---
 hw/mcu/dialog/cmac/include/mcu/cmac_timer.h | 70 +++++++++++++++++++++++++++--
 hw/mcu/dialog/cmac/src/cmac_timer.c         |  3 +-
 hw/mcu/dialog/cmac/src/hal_os_tick.c        |  1 +
 hw/mcu/dialog/cmac/src/hal_timer.c          | 25 +++++++++--
 4 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h b/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h
index 6a30378..8e5ad8d 100644
--- a/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h
+++ b/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h
@@ -27,9 +27,27 @@
 extern "C" {
 #endif
 
+/*
+ * Equals to LLT value after HAL timer wrapped around,
+ * i.e. os_cputime(0xffffffff "+1")
+ */
+#define CMAC_TIMER_LLT_AT_HAL_WRAP_AROUND_VAL   (0x1e84800000)
+
+#define CMAC_TIMER_HAL_GT(_t1, _t2)             ((int32_t)((_t1) - (_t2)) > 0)
+#define CMAC_TIMER_HAL_LT(_t1, _t2)             ((int32_t)((_t1) - (_t2)) < 0)
+
+struct cmac_timer_ctrl {
+    uint32_t llt_last_hi_val;
+    uint64_t llt_corr;
+
+    uint32_t hal_last_val;
+    uint64_t hal_to_llt_corr;
+};
+
 typedef void (cmac_timer_int_func_t)(void);
 
 extern volatile uint32_t cm_ll_int_stat_reg;
+extern struct cmac_timer_ctrl g_cmac_timer_ctrl;
 
 void cmac_timer_init(void);
 void cmac_timer_slp_enable(uint32_t ticks);
@@ -87,13 +105,32 @@ cmac_timer_read64(void)
 {
     uint32_t hi;
     uint32_t lo;
+    uint32_t llt_corr;
 
     do {
         hi = cmac_timer_read_hi();
         lo = cmac_timer_read_lo();
     } while (hi != cmac_timer_read_hi());
 
-    return ((uint64_t)hi << 10) | lo;
+    __disable_irq();
+
+    /*
+     * We extend LLT value manually to full 64-bit timer, this gives us plenty
+     * of resolution so we don't really need to care about wrap around. Note
+     * that we keep track of hi-word correction only (bits 63:37) so there is
+     * no need for 64-bit calculations on correction value - final shift by 32
+     * bits is optimized by a compiler to a simple 32-bit operation on hi-word.
+     */
+
+    if (hi < g_cmac_timer_ctrl.llt_last_hi_val) {
+        g_cmac_timer_ctrl.llt_corr += 1 << 5;
+    }
+    g_cmac_timer_ctrl.llt_last_hi_val = hi;
+    llt_corr = g_cmac_timer_ctrl.llt_corr;
+
+    __enable_irq();
+
+    return ((uint64_t)llt_corr << 32) | ((uint64_t)hi << 10) | lo;
 }
 
 static inline void
@@ -134,9 +171,13 @@ cmac_timer_disable_eq_hal_timer(void)
 static inline void
 cmac_timer_write_eq_hal_os_tick(uint64_t val)
 {
-    CMAC->CM_LL_TIMER1_36_10_EQ_Y_REG = val >> 10;
+    uint32_t val_hi;
+
+    val_hi = (val >> 10) & 0x7ffffff;
+
+    CMAC->CM_LL_TIMER1_36_10_EQ_Y_REG = val_hi;
 
-    if ((int32_t)((val >> 10) - cmac_timer_read_hi()) <= 0) {
+    if ((int32_t)(val_hi - cmac_timer_read_hi()) <= 0) {
         cm_ll_int_stat_reg = CMAC_CM_LL_INT_STAT_REG_LL_TIMER1_36_10_EQ_Y_SEL_Msk;
         NVIC_SetPendingIRQ(LL_TIMER2LLC_IRQn);
     }
@@ -160,7 +201,28 @@ cmac_timer_convert_llt2tck(uint64_t val)
 static inline uint64_t
 cmac_timer_convert_hal2llt(uint32_t val)
 {
-    return ((uint64_t)val * 15625) >> 9;
+    uint64_t llt;
+    uint32_t v1, v2;
+    int64_t dt;
+
+    /*
+     * Use known HAL timer value and LLT value pair as a base, then apply
+     * correction based on delta between known HAL timer value and value being
+     * converted.
+     */
+
+    __disable_irq();
+
+    v1 = g_cmac_timer_ctrl.hal_last_val;
+    v2 = val;
+    llt = g_cmac_timer_ctrl.hal_to_llt_corr;
+
+    __enable_irq();
+
+    dt = (int32_t)(v2 - v1);
+    llt += (dt * 15625) / 512;
+
+    return llt;
 }
 
 /* Convert os_tick value to ll_timer value */
diff --git a/hw/mcu/dialog/cmac/src/cmac_timer.c b/hw/mcu/dialog/cmac/src/cmac_timer.c
index ce23c1a..6c51789 100644
--- a/hw/mcu/dialog/cmac/src/cmac_timer.c
+++ b/hw/mcu/dialog/cmac/src/cmac_timer.c
@@ -49,6 +49,7 @@ struct cmac_timer_slp {
 };
 
 static struct cmac_timer_slp g_cmac_timer_slp;
+struct cmac_timer_ctrl g_cmac_timer_ctrl;
 
 static cmac_timer_int_func_t *cmac_timer_int_hal_timer;
 static cmac_timer_int_func_t *cmac_timer_int_hal_os_tick;
@@ -283,7 +284,7 @@ cmac_timer_get_hal_os_tick(void)
     uint32_t rem_val;
     uint32_t ret;
 
-    val = (uint64_t)cmac_timer_read_hi() << 10;
+    val = cmac_timer_read64();
 
     if (SYNC_TICK_VAL_INTERVAL == 2000000) {
         while (val >= sync_tick_val_next) {
diff --git a/hw/mcu/dialog/cmac/src/hal_os_tick.c b/hw/mcu/dialog/cmac/src/hal_os_tick.c
index ab9c527..9eb3046 100644
--- a/hw/mcu/dialog/cmac/src/hal_os_tick.c
+++ b/hw/mcu/dialog/cmac/src/hal_os_tick.c
@@ -65,6 +65,7 @@ os_tick_handle_tick(void)
 
     cur_tick = cmac_timer_get_hal_os_tick();
     delta = cur_tick - g_os_tick_last;
+
     os_time_advance(delta);
 
     g_os_tick_last = cur_tick;
diff --git a/hw/mcu/dialog/cmac/src/hal_timer.c b/hw/mcu/dialog/cmac/src/hal_timer.c
index 29fa94b..1860ba1 100644
--- a/hw/mcu/dialog/cmac/src/hal_timer.c
+++ b/hw/mcu/dialog/cmac/src/hal_timer.c
@@ -49,7 +49,7 @@ hal_timer_expiry_get(struct hal_timer *timer)
 {
     uint64_t ret;
 
-    ret = (uint64_t)POINTER_TO_UINT(timer->bsp_timer) << 10;
+    ret = (uint64_t)POINTER_TO_UINT(timer->bsp_timer) << 32;
     ret |= timer->expiry;
 
     return ret;
@@ -58,8 +58,8 @@ hal_timer_expiry_get(struct hal_timer *timer)
 static inline void
 hal_timer_expiry_set(struct hal_timer *timer, uint64_t val)
 {
-    timer->expiry = val & 0x3ff;
-    timer->bsp_timer = UINT_TO_POINTER(val >> 10);
+    timer->expiry = val;
+    timer->bsp_timer = UINT_TO_POINTER(val >> 32);
 }
 
 static void
@@ -208,7 +208,24 @@ hal_timer_stop(struct hal_timer *timer)
 uint32_t
 hal_timer_read(int timer_num)
 {
+    uint64_t llt;
+    uint32_t val;
+
     assert(timer_num == 0);
 
-    return cmac_timer_convert_llt2hal(cmac_timer_read64());
+    llt = cmac_timer_read64();
+    val = cmac_timer_convert_llt2hal(llt);
+
+    __disable_irq();
+
+    /*
+     * Store current LLT value and converted HAL timer value, we'll use it as
+     * a base for subsequent HAL->LLT conversions.
+     */
+    g_cmac_timer_ctrl.hal_last_val = val;
+    g_cmac_timer_ctrl.hal_to_llt_corr = llt;
+
+    __enable_irq();
+
+    return val;
 }