Skip to content

Commit 00b8e24

Browse files
committed
Fix rollover handling in ticker frequency test
To handle timer rollovers the test tests-mbed_hal-common_tickers_freq calls intf->set_interrupt(0). For this to work correctly the ticker implementation must fire an interrupt on every rollover event though intf->set_interrupt(0) was called only once. Whether an interrupt will fire only once or multiple times is undefined behavior which cannot be relied upon. To avoid this undefined behavior this patch continually schedules an interrupt and performs overflow detection on every read. This also removes the possibility of race conditions due to overflowCounter incrementing at the wrong time.
1 parent f68958d commit 00b8e24

File tree

1 file changed

+42
-19
lines changed
  • TESTS/mbed_hal/common_tickers_freq

1 file changed

+42
-19
lines changed

TESTS/mbed_hal/common_tickers_freq/main.cpp

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,51 @@
3939
using namespace utest::v1;
4040

4141
const ticker_interface_t *intf;
42+
uint32_t intf_mask;
43+
uint32_t intf_last_tick;
44+
uint32_t intf_elapsed_ticks;
4245
ticker_irq_handler_type prev_handler;
4346

44-
static volatile unsigned int overflowCounter;
45-
4647
uint32_t ticks_to_us(uint32_t ticks, uint32_t freq)
4748
{
4849
return (uint32_t)((uint64_t)ticks * US_PER_S / freq);
4950
}
5051

51-
void ticker_event_handler_stub(const ticker_data_t *const ticker)
52+
void elapsed_ticks_reset()
5253
{
53-
if (ticker == get_us_ticker_data()) {
54-
us_ticker_clear_interrupt();
55-
} else {
56-
#if DEVICE_LPTICKER
57-
lp_ticker_clear_interrupt();
58-
#endif
59-
}
54+
core_util_critical_section_enter();
55+
56+
const uint32_t ticker_bits = intf->get_info()->bits;
6057

61-
overflowCounter++;
58+
intf_mask = (1 << ticker_bits) - 1;
59+
intf_last_tick = intf->read();
60+
intf_elapsed_ticks = 0;
61+
62+
core_util_critical_section_exit();
63+
}
64+
65+
uint32_t elapsed_ticks_update()
66+
{
67+
core_util_critical_section_enter();
68+
69+
const uint32_t current_tick = intf->read();
70+
intf_elapsed_ticks += (current_tick - intf_last_tick) & intf_mask;
71+
intf_last_tick = current_tick;
72+
73+
/* Schedule next interrupt half way to overflow */
74+
uint32_t next = (current_tick + intf_mask / 2) & intf_mask;
75+
intf->set_interrupt(next);
76+
77+
uint32_t elapsed = intf_elapsed_ticks;
78+
79+
core_util_critical_section_exit();
80+
return elapsed;
81+
}
82+
83+
void ticker_event_handler_stub(const ticker_data_t *const ticker)
84+
{
85+
intf->clear_interrupt();
86+
elapsed_ticks_update();
6287
}
6388

6489
/* Test that the ticker is operating at the frequency it specifies. */
@@ -68,13 +93,13 @@ void ticker_frequency_test()
6893
char _value[128] = { };
6994
int expected_key = 1;
7095
const uint32_t ticker_freq = intf->get_info()->frequency;
71-
const uint32_t ticker_bits = intf->get_info()->bits;
72-
const uint32_t ticker_max = (1 << ticker_bits) - 1;
7396

7497
intf->init();
7598

99+
elapsed_ticks_reset();
100+
76101
/* Detect overflow for tickers with lower counters width. */
77-
intf->set_interrupt(0);
102+
elapsed_ticks_update();
78103

79104
greentea_send_kv("timing_drift_check_start", 0);
80105

@@ -84,19 +109,17 @@ void ticker_frequency_test()
84109
expected_key = strcmp(_key, "base_time");
85110
} while (expected_key);
86111

87-
overflowCounter = 0;
88-
89-
const uint32_t begin_ticks = intf->read();
112+
const uint32_t begin_ticks = elapsed_ticks_update();
90113

91114
/* Assume that there was no overflow at this point - we are just after init. */
92115
greentea_send_kv(_key, ticks_to_us(begin_ticks, ticker_freq));
93116

94117
/* Wait for 2nd signal from host. */
95118
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
96119

97-
const uint32_t end_ticks = intf->read();
120+
const uint32_t end_ticks = elapsed_ticks_update();
98121

99-
greentea_send_kv(_key, ticks_to_us(end_ticks + overflowCounter * ticker_max, ticker_freq));
122+
greentea_send_kv(_key, ticks_to_us(end_ticks, ticker_freq));
100123

101124
/* Get the results from host. */
102125
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));

0 commit comments

Comments
 (0)