|
| 1 | +From 2ec69171e77ebd105064c8c2c9ba4df58bb1a992 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Simon Arlott <sa.me.uk> |
| 3 | +Date: Mon, 19 May 2025 18:59:40 +0100 |
| 4 | +Subject: [PATCH 2/2] RP2040: us_ticker: don't modify the system uptime |
| 5 | + |
| 6 | +There is only one user of this API, the mbed timer queue. It sets targets |
| 7 | +a maximum of (2**32)//16*7 microseconds in the future. Assuming there are |
| 8 | +no other timer events to be scheduled, after 3 instances of this at 5637s |
| 9 | +uptime the 64-bit uptime gets wrapped. |
| 10 | + |
| 11 | +Never modify the system uptime because that makes it unusable when the |
| 12 | +64-bit uptime that should never wrap, unexpectedly does. With the uptime |
| 13 | +proceeding as normal into large 64-bit values the 32-bit timestamp needs |
| 14 | +special handling. |
| 15 | + |
| 16 | +It's ambiguous what the 32-bit timestamp means because time advances while |
| 17 | +the ticker functions are being called, so the 64-bit time could wrap |
| 18 | +between calculating the next 32-bit timestamp and setting it as the target |
| 19 | +time. |
| 20 | + |
| 21 | +The only way to avoid this is to know for certain what the caller meant by |
| 22 | +keeping track of the last 32-bit value that was read. This relies on there |
| 23 | +only being caller but other mbed timer implementations already keep track |
| 24 | +of the last call to us_ticker_read() to handle ambiguity in timestamp |
| 25 | +values. |
| 26 | + |
| 27 | +Track the last read of the full 64-bit time too, so that we can always |
| 28 | +prepare the correct 64-bit time value. Avoid reading the current time |
| 29 | +repeatedly because it could change between calls. |
| 30 | + |
| 31 | +If the timestamp is in the near future it's possible that it has been set |
| 32 | +too late and the time has been missed. Force a timer interrupt when this |
| 33 | +happens. |
| 34 | +--- |
| 35 | + .../TARGET_RP2040/us_ticker.c | 39 ++++++++++--------- |
| 36 | + 1 file changed, 21 insertions(+), 18 deletions(-) |
| 37 | + |
| 38 | +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c |
| 39 | +index 3a5e1f1686f..2062ac36118 100644 |
| 40 | +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c |
| 41 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c |
| 42 | +@@ -54,6 +54,7 @@ const ticker_info_t* us_ticker_get_info() |
| 43 | + } |
| 44 | + |
| 45 | + static const uint8_t alarm_num = 0; |
| 46 | ++static uint64_t last_read_u64 = 0; |
| 47 | + |
| 48 | + static void us_ticker_irq_handler_internal(uint alarm_src) { |
| 49 | + if (alarm_num == alarm_src) { |
| 50 | +@@ -69,30 +70,32 @@ void us_ticker_init(void) |
| 51 | + |
| 52 | + uint32_t us_ticker_read() |
| 53 | + { |
| 54 | +- return time_us_32(); |
| 55 | ++ uint64_t now_u64 = time_us_64(); |
| 56 | ++ |
| 57 | ++ core_util_critical_section_enter(); |
| 58 | ++ last_read_u64 = now_u64; |
| 59 | ++ core_util_critical_section_exit(); |
| 60 | ++ |
| 61 | ++ return now_u64; |
| 62 | + } |
| 63 | + |
| 64 | +-void us_ticker_set_interrupt(timestamp_t timestamp) |
| 65 | ++void us_ticker_set_interrupt(timestamp_t timestamp_u32) |
| 66 | + { |
| 67 | + core_util_critical_section_enter(); |
| 68 | + |
| 69 | +- uint64_t _timestamp = (uint64_t)timestamp; |
| 70 | +- |
| 71 | +- if (timestamp < time_us_32()) { |
| 72 | +- //32 bit timestamp has been wrapped |
| 73 | +- //We need to provide a 64 bit timestamp able to fire the irq for this round |
| 74 | +- _timestamp = (((time_us_64() >> 32) + 1) << 32) + timestamp; |
| 75 | +- } else { |
| 76 | +- //Then, at the next round, wrap the 64 bit timer to follow the 32 bit one |
| 77 | +- if ((time_us_64() >> 32) > 0) { |
| 78 | +- uint64_t current_time = time_us_64(); |
| 79 | +- uint64_t wrapped_time = current_time - 0xFFFFFFFF; |
| 80 | +- timer_hw->timelw = (uint32_t)wrapped_time; |
| 81 | +- timer_hw->timehw = 0; |
| 82 | +- } |
| 83 | ++ uint32_t last_read_u32 = (uint32_t)last_read_u64; |
| 84 | ++ uint64_t timestamp_u64 = (uint64_t)timestamp_u32 | (last_read_u64 & 0xFFFFFFFF00000000ULL); |
| 85 | ++ |
| 86 | ++ if (timestamp_u32 < last_read_u32) { |
| 87 | ++ timestamp_u64 += 1ULL << 32; |
| 88 | ++ } |
| 89 | ++ |
| 90 | ++ absolute_time_t target = { timestamp_u64 }; |
| 91 | ++ bool missed = hardware_alarm_set_target(alarm_num, target); |
| 92 | ++ |
| 93 | ++ if (missed) { |
| 94 | ++ us_ticker_fire_interrupt(); |
| 95 | + } |
| 96 | +- absolute_time_t target = { _timestamp }; |
| 97 | +- hardware_alarm_set_target(alarm_num, target); |
| 98 | + |
| 99 | + core_util_critical_section_exit(); |
| 100 | + } |
0 commit comments