@@ -214,6 +214,69 @@ ZTEST(spi_loopback, test_spi_complete_multiple)
214
214
buffer_print_tx2 , buffer_print_rx2 );
215
215
}
216
216
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
+
217
280
void spi_loopback_test_mode (struct spi_dt_spec * spec , bool cpol , bool cpha )
218
281
{
219
282
const struct spi_buf_set tx = spi_loopback_setup_xfer (tx_bufs_pool , 1 ,
0 commit comments