From 58f4180f7496dbc253aa6e61f706839be6677a11 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 10 Jun 2021 23:32:51 +0200 Subject: [PATCH 1/3] WIP adding hal_jump_to_the_future_us() --- src/hal/hal.cpp | 7 +++++++ src/lmic/hal.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index 6e72a585..4b4e2cca 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -223,6 +223,12 @@ static void hal_time_init () { // Nothing to do } +uint32_t delta_ticks = 0; +void hal_jump_to_the_future_us (uint32_t us) { + delta_ticks += us >> US_PER_OSTICK_EXPONENT; + //overflow += +} + u4_t hal_ticks () { // Because micros() is scaled down in this function, micros() will // overflow before the tick timer should, causing the tick timer to @@ -248,6 +254,7 @@ u4_t hal_ticks () { // Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0, // the others will be the lower bits of our return value. uint32_t scaled = micros() >> US_PER_OSTICK_EXPONENT; + scaled += delta_ticks; // Most significant byte of scaled uint8_t msb = scaled >> 24; // Mask pointing to the overlapping bit in msb and overflow. diff --git a/src/lmic/hal.h b/src/lmic/hal.h index f2324808..a48db514 100644 --- a/src/lmic/hal.h +++ b/src/lmic/hal.h @@ -180,6 +180,8 @@ static void inline hal_pollPendingIRQs(void) #endif /* !defined(LMIC_USE_INTERRUPTS) */ } +void hal_jump_to_the_future_us (uint32_t us); + #ifdef __cplusplus } // extern "C" #endif From 5d6dca0c2f5083b6f482b81ca9216e5241df6c61 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 11 Jun 2021 12:07:11 +0200 Subject: [PATCH 2/3] non-invasive: integration conditioned to the macro HAL_ALLOW_FUTURE_JUMP --- src/hal/hal.cpp | 17 +++++++++++------ src/lmic/hal.h | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index 4b4e2cca..fb11c94b 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -223,11 +223,14 @@ static void hal_time_init () { // Nothing to do } -uint32_t delta_ticks = 0; -void hal_jump_to_the_future_us (uint32_t us) { - delta_ticks += us >> US_PER_OSTICK_EXPONENT; - //overflow += +#if defined(HAL_ALLOW_FUTURE_JUMP) +static uint32_t delta_usec = 0; +void hal_jump_to_the_future_us (uint32_t usec) { + delta_usec += usec; } +#else +#define delta_usec (0) +#endif u4_t hal_ticks () { // Because micros() is scaled down in this function, micros() will @@ -249,12 +252,14 @@ u4_t hal_ticks () { // jumps, which should result in efficient code. By avoiding shifts // other than by multiples of 8 as much as possible, this is also // efficient on AVR (which only has 1-bit shifts). + // This discussion is still valid when (micros()+delta_usec) is + // considered instead of micros() only: The sum is also constantly + // increasing and overflowing. static uint8_t overflow = 0; // Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0, // the others will be the lower bits of our return value. - uint32_t scaled = micros() >> US_PER_OSTICK_EXPONENT; - scaled += delta_ticks; + uint32_t scaled = (micros() + delta_usec) >> US_PER_OSTICK_EXPONENT; // Most significant byte of scaled uint8_t msb = scaled >> 24; // Mask pointing to the overlapping bit in msb and overflow. diff --git a/src/lmic/hal.h b/src/lmic/hal.h index a48db514..8ea28eef 100644 --- a/src/lmic/hal.h +++ b/src/lmic/hal.h @@ -180,7 +180,9 @@ static void inline hal_pollPendingIRQs(void) #endif /* !defined(LMIC_USE_INTERRUPTS) */ } +#if defined(HAL_ALLOW_FUTURE_JUMP) void hal_jump_to_the_future_us (uint32_t us); +#endif #ifdef __cplusplus } // extern "C" From e32b2341d7959ea1c29cd1e0fda8815bcd231f53 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 11 Jun 2021 23:44:31 +0200 Subject: [PATCH 3/3] Properly handle overflows of "future" microsec additions including when they occur at the same of "micros()" overflow. overall cost when enabled: around 130 flash bytes on AVR --- src/hal/hal.cpp | 51 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index fb11c94b..0f9fa0c9 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -224,15 +224,44 @@ static void hal_time_init () { } #if defined(HAL_ALLOW_FUTURE_JUMP) -static uint32_t delta_usec = 0; + +static uint32_t future_usec = 0; + +typedef decltype(micros()) micros_t; + +u4_t hal_ticks (micros_t); + +u4_t hal_ticks () { + return hal_ticks(micros() + future_usec); +} + void hal_jump_to_the_future_us (uint32_t usec) { - delta_usec += usec; + // It is needed to independantly handle + // overflowing of `micros()` and `future_usec`. + + // First, handle possible past overflow of `micros()`: + micros_t now_us = micros(); + (void)hal_ticks(now_us + future_usec); + + // Then handle possible `future_usec` overflow + // while retaining micros() in a temporary constant + future_usec += usec; + (void)hal_ticks(now_us + future_usec); } -#else -#define delta_usec (0) -#endif -u4_t hal_ticks () { +#define HAL_TICKS_PARAM micros_t micros_now +#define HAL_TICKS_MICROS micros_now + +#else // !defined(HAL_ALLOW_FUTURE_JUMP) + +// legacy code without `hal_jump_to_the_future_us()` +#define HAL_TICKS_PARAM void +#define HAL_TICKS_MICROS micros() + +#endif // !defined(HAL_ALLOW_FUTURE_JUMP) + +u4_t hal_ticks (HAL_TICKS_PARAM) { + // (by default HAL_TICKS_PARAM is void and HAL_TICKS_MICROS is micros()). // Because micros() is scaled down in this function, micros() will // overflow before the tick timer should, causing the tick timer to // miss a significant part of its values if not corrected. To fix @@ -252,14 +281,16 @@ u4_t hal_ticks () { // jumps, which should result in efficient code. By avoiding shifts // other than by multiples of 8 as much as possible, this is also // efficient on AVR (which only has 1-bit shifts). - // This discussion is still valid when (micros()+delta_usec) is - // considered instead of micros() only: The sum is also constantly - // increasing and overflowing. + // + // Additional note: + // When HAL_TICKS_MICROS is (micros()+future_usec), this reasoning is + // still valid when overflows of micros() and future_usec are + // independently taken care of (see hal_jump_to_the_future_us()). static uint8_t overflow = 0; // Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0, // the others will be the lower bits of our return value. - uint32_t scaled = (micros() + delta_usec) >> US_PER_OSTICK_EXPONENT; + uint32_t scaled = (HAL_TICKS_MICROS) >> US_PER_OSTICK_EXPONENT; // Most significant byte of scaled uint8_t msb = scaled >> 24; // Mask pointing to the overlapping bit in msb and overflow.