Skip to content

Commit 972dac1

Browse files
decsnykartben
authored andcommitted
tests: spi_loopback: Add timing testcase
Add testcase to ensure some aspects of the timing is correct. If the transfer happens faster than it should, fail the test. If the transfer takes way longer than it should, fail the test. Signed-off-by: Declan Snyder <[email protected]>
1 parent 4b7ba78 commit 972dac1

File tree

1 file changed

+63
-0
lines changed
  • tests/drivers/spi/spi_loopback/src

1 file changed

+63
-0
lines changed

tests/drivers/spi/spi_loopback/src/spi.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,69 @@ ZTEST(spi_loopback, test_spi_complete_multiple)
214214
buffer_print_tx2, buffer_print_rx2);
215215
}
216216

217+
/* same as the test_spi_complete_multiple test, but seeing if there is any unreasonable latency */
218+
ZTEST(spi_loopback, test_spi_complete_multiple_timed)
219+
{
220+
struct spi_dt_spec *spec = loopback_specs[spec_idx];
221+
const struct spi_buf_set tx = spi_loopback_setup_xfer(tx_bufs_pool, 2,
222+
buffer_tx, BUF_SIZE,
223+
buffer2_tx, BUF2_SIZE);
224+
const struct spi_buf_set rx = spi_loopback_setup_xfer(rx_bufs_pool, 2,
225+
buffer_rx, BUF_SIZE,
226+
buffer2_rx, BUF2_SIZE);
227+
uint32_t freq = spec->config.frequency;
228+
uint32_t start_time, end_time, cycles_spent;
229+
uint64_t time_spent_us, expected_transfer_time_us;
230+
231+
/* since this is a test program, there shouldn't be much to interfere with measurement */
232+
start_time = k_cycle_get_32();
233+
spi_loopback_transceive(spec, &tx, &rx);
234+
end_time = k_cycle_get_32();
235+
236+
if (end_time >= start_time) {
237+
cycles_spent = end_time - start_time;
238+
} else {
239+
/* number of cycles from start to counter reset + rest of cycles */
240+
cycles_spent = (UINT32_MAX - start_time) + end_time;
241+
}
242+
243+
time_spent_us = k_cyc_to_us_ceil64(cycles_spent);
244+
245+
/* Number of bits to transfer * usec per bit */
246+
expected_transfer_time_us = (uint64_t)(BUF_SIZE + BUF2_SIZE) * BITS_PER_BYTE *
247+
USEC_PER_SEC / freq;
248+
249+
TC_PRINT("Transfer took %llu us vs theoretical minimum %llu us\n",
250+
time_spent_us, expected_transfer_time_us);
251+
252+
/* For comparing the lower bound, some kernel timer implementations
253+
* do not actually update the elapsed cycles until a tick boundary,
254+
* so we need to account for that by subtracting one tick from the comparison metric
255+
*/
256+
uint64_t us_per_kernel_tick = k_ticks_to_us_ceil64(1);
257+
uint32_t minimum_transfer_time_us;
258+
259+
if (expected_transfer_time_us > us_per_kernel_tick) {
260+
minimum_transfer_time_us = expected_transfer_time_us - us_per_kernel_tick;
261+
} else {
262+
minimum_transfer_time_us = 0;
263+
}
264+
265+
/* Fail if transfer is faster than theoretically possible */
266+
zassert_true(time_spent_us >= minimum_transfer_time_us,
267+
"Transfer faster than theoretically possible");
268+
269+
TC_PRINT("Latency measurement: %llu us\n", time_spent_us - expected_transfer_time_us);
270+
271+
/* Allow some overhead, but not too much */
272+
zassert_true(time_spent_us <= expected_transfer_time_us * 8, "Very high latency");
273+
274+
spi_loopback_compare_bufs(buffer_tx, buffer_rx, BUF_SIZE,
275+
buffer_print_tx, buffer_print_rx);
276+
spi_loopback_compare_bufs(buffer2_tx, buffer2_rx, BUF2_SIZE,
277+
buffer_print_tx2, buffer_print_rx2);
278+
}
279+
217280
void spi_loopback_test_mode(struct spi_dt_spec *spec, bool cpol, bool cpha)
218281
{
219282
const struct spi_buf_set tx = spi_loopback_setup_xfer(tx_bufs_pool, 1,

0 commit comments

Comments
 (0)