1 /*
2 * Copyright (c) 2017 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
8 #include <logging/log.h>
9 LOG_MODULE_REGISTER(main);
10
11 #include <zephyr.h>
12 #include <sys/printk.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <ztest.h>
16
17 #include <drivers/spi.h>
18
19 #define SPI_DRV_NAME CONFIG_SPI_LOOPBACK_DRV_NAME
20 #define SPI_SLAVE CONFIG_SPI_LOOPBACK_SLAVE_NUMBER
21 #define SLOW_FREQ CONFIG_SPI_LOOPBACK_SLOW_FREQ
22 #define FAST_FREQ CONFIG_SPI_LOOPBACK_FAST_FREQ
23
24 #if defined(CONFIG_SPI_LOOPBACK_CS_GPIO)
25 #define CS_CTRL_GPIO_DRV_NAME CONFIG_SPI_LOOPBACK_CS_CTRL_GPIO_DRV_NAME
26 struct spi_cs_control spi_cs = {
27 .gpio_pin = CONFIG_SPI_LOOPBACK_CS_CTRL_GPIO_PIN,
28 .gpio_dt_flags = GPIO_ACTIVE_LOW,
29 .delay = 0,
30 };
31 #define SPI_CS (&spi_cs)
32 #else
33 #define SPI_CS NULL
34 #define CS_CTRL_GPIO_DRV_NAME ""
35 #endif
36
37 /* to run this test, connect MOSI pin to the MISO of the SPI */
38
39 #define STACK_SIZE 512
40 #define BUF_SIZE 17
41 uint8_t buffer_tx[] = "0123456789abcdef\0";
42 uint8_t buffer_rx[BUF_SIZE] = {};
43
44 #define BUF2_SIZE 36
45 uint8_t buffer2_tx[] = "Thequickbrownfoxjumpsoverthelazydog\0";
46 uint8_t buffer2_rx[BUF2_SIZE] = {};
47
48 /*
49 * We need 5x(buffer size) + 1 to print a comma-separated list of each
50 * byte in hex, plus a null.
51 */
52 uint8_t buffer_print_tx[BUF_SIZE * 5 + 1];
53 uint8_t buffer_print_rx[BUF_SIZE * 5 + 1];
54
55 uint8_t buffer_print_tx2[BUF2_SIZE * 5 + 1];
56 uint8_t buffer_print_rx2[BUF2_SIZE * 5 + 1];
57
to_display_format(const uint8_t * src,size_t size,char * dst)58 static void to_display_format(const uint8_t *src, size_t size, char *dst)
59 {
60 size_t i;
61
62 for (i = 0; i < size; i++) {
63 sprintf(dst + 5 * i, "0x%02x,", src[i]);
64 }
65 }
66
67 struct spi_config spi_cfg_slow = {
68 .frequency = SLOW_FREQ,
69 #if CONFIG_SPI_LOOPBACK_MODE_LOOP
70 .operation = SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_LOOP |
71 #else
72 .operation = SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
73 #endif
74 SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE,
75 .slave = SPI_SLAVE,
76 .cs = SPI_CS,
77 };
78
79 struct spi_config spi_cfg_fast = {
80 .frequency = FAST_FREQ,
81 #if CONFIG_SPI_LOOPBACK_MODE_LOOP
82 .operation = SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_LOOP |
83 #else
84 .operation = SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
85 #endif
86 SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE,
87 .slave = SPI_SLAVE,
88 .cs = SPI_CS,
89 };
90
91 #if defined(CONFIG_SPI_LOOPBACK_CS_GPIO)
cs_ctrl_gpio_config(void)92 static int cs_ctrl_gpio_config(void)
93 {
94 spi_cs.gpio_dev = device_get_binding(CS_CTRL_GPIO_DRV_NAME);
95 if (!spi_cs.gpio_dev) {
96 LOG_ERR("Cannot find %s!", CS_CTRL_GPIO_DRV_NAME);
97 zassert_not_null(spi_cs.gpio_dev, "Invalid gpio device");
98 return -1;
99 }
100
101 return 0;
102 }
103 #endif /* CONFIG_SPI_LOOPBACK_CS_GPIO */
104
105 /* test transferring different buffers on the same dma channels */
spi_complete_multiple(const struct device * dev,struct spi_config * spi_conf)106 static int spi_complete_multiple(const struct device *dev,
107 struct spi_config *spi_conf)
108 {
109 struct spi_buf tx_bufs[2];
110 const struct spi_buf_set tx = {
111 .buffers = tx_bufs,
112 .count = ARRAY_SIZE(tx_bufs)
113 };
114 tx_bufs[0].buf = buffer_tx;
115 tx_bufs[0].len = BUF_SIZE;
116
117 tx_bufs[1].buf = buffer2_tx;
118 tx_bufs[1].len = BUF2_SIZE;
119
120
121 struct spi_buf rx_bufs[2];
122 const struct spi_buf_set rx = {
123 .buffers = rx_bufs,
124 .count = ARRAY_SIZE(rx_bufs)
125 };
126
127 rx_bufs[0].buf = buffer_rx;
128 rx_bufs[0].len = BUF_SIZE;
129
130 rx_bufs[1].buf = buffer2_rx;
131 rx_bufs[1].len = BUF2_SIZE;
132
133 int ret;
134
135 LOG_INF("Start complete multiple");
136
137 ret = spi_transceive(dev, spi_conf, &tx, &rx);
138 if (ret) {
139 LOG_ERR("Code %d", ret);
140 zassert_false(ret, "SPI transceive failed");
141 return ret;
142 }
143
144 if (memcmp(buffer_tx, buffer_rx, BUF_SIZE)) {
145 to_display_format(buffer_tx, BUF_SIZE, buffer_print_tx);
146 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
147 LOG_ERR("Buffer contents are different: %s",
148 buffer_print_tx);
149 LOG_ERR(" vs: %s",
150 buffer_print_rx);
151 zassert_false(1, "Buffer contents are different");
152 return -1;
153 }
154
155 if (memcmp(buffer2_tx, buffer2_rx, BUF2_SIZE)) {
156 to_display_format(buffer2_tx, BUF2_SIZE, buffer_print_tx2);
157 to_display_format(buffer2_rx, BUF2_SIZE, buffer_print_rx2);
158 LOG_ERR("Buffer 2 contents are different: %s",
159 buffer_print_tx2);
160 LOG_ERR(" vs: %s",
161 buffer_print_rx2);
162 zassert_false(1, "Buffer contents are different");
163 return -1;
164 }
165
166 LOG_INF("Passed");
167
168 return 0;
169 }
170
spi_complete_loop(const struct device * dev,struct spi_config * spi_conf)171 static int spi_complete_loop(const struct device *dev,
172 struct spi_config *spi_conf)
173 {
174 const struct spi_buf tx_bufs[] = {
175 {
176 .buf = buffer_tx,
177 .len = BUF_SIZE,
178 },
179 };
180 const struct spi_buf rx_bufs[] = {
181 {
182 .buf = buffer_rx,
183 .len = BUF_SIZE,
184 },
185 };
186 const struct spi_buf_set tx = {
187 .buffers = tx_bufs,
188 .count = ARRAY_SIZE(tx_bufs)
189 };
190 const struct spi_buf_set rx = {
191 .buffers = rx_bufs,
192 .count = ARRAY_SIZE(rx_bufs)
193 };
194
195 int ret;
196
197 LOG_INF("Start complete loop");
198
199 ret = spi_transceive(dev, spi_conf, &tx, &rx);
200 if (ret) {
201 LOG_ERR("Code %d", ret);
202 zassert_false(ret, "SPI transceive failed");
203 return ret;
204 }
205
206 if (memcmp(buffer_tx, buffer_rx, BUF_SIZE)) {
207 to_display_format(buffer_tx, BUF_SIZE, buffer_print_tx);
208 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
209 LOG_ERR("Buffer contents are different: %s",
210 buffer_print_tx);
211 LOG_ERR(" vs: %s",
212 buffer_print_rx);
213 zassert_false(1, "Buffer contents are different");
214 return -1;
215 }
216
217 LOG_INF("Passed");
218
219 return 0;
220 }
221
spi_null_tx_buf(const struct device * dev,struct spi_config * spi_conf)222 static int spi_null_tx_buf(const struct device *dev,
223 struct spi_config *spi_conf)
224 {
225 static const uint8_t EXPECTED_NOP_RETURN_BUF[BUF_SIZE] = { 0 };
226 (void)memset(buffer_rx, 0x77, BUF_SIZE);
227
228 const struct spi_buf tx_bufs[] = {
229 {
230 /*
231 * According to documentation, when sending NULL tx buf -
232 * NOP frames should be sent on MOSI line
233 */
234 .buf = NULL,
235 .len = BUF_SIZE,
236 },
237 };
238 const struct spi_buf rx_bufs[] = {
239 {
240 .buf = buffer_rx,
241 .len = BUF_SIZE,
242 },
243 };
244 const struct spi_buf_set tx = {
245 .buffers = tx_bufs,
246 .count = ARRAY_SIZE(tx_bufs)
247 };
248 const struct spi_buf_set rx = {
249 .buffers = rx_bufs,
250 .count = ARRAY_SIZE(rx_bufs)
251 };
252
253 int ret;
254
255 LOG_INF("Start null tx");
256
257 ret = spi_transceive(dev, spi_conf, &tx, &rx);
258 if (ret) {
259 LOG_ERR("Code %d", ret);
260 zassert_false(ret, "SPI transceive failed");
261 return ret;
262 }
263
264
265 if (memcmp(buffer_rx, EXPECTED_NOP_RETURN_BUF, BUF_SIZE)) {
266 to_display_format(buffer_rx, BUF_SIZE, buffer_print_rx);
267 LOG_ERR("Rx Buffer should contain NOP frames but got: %s",
268 buffer_print_rx);
269 zassert_false(1, "Buffer not as expected");
270 return -1;
271 }
272
273 LOG_INF("Passed");
274
275 return 0;
276 }
277
spi_rx_half_start(const struct device * dev,struct spi_config * spi_conf)278 static int spi_rx_half_start(const struct device *dev,
279 struct spi_config *spi_conf)
280 {
281 const struct spi_buf tx_bufs[] = {
282 {
283 .buf = buffer_tx,
284 .len = BUF_SIZE,
285 },
286 };
287 const struct spi_buf rx_bufs[] = {
288 {
289 .buf = buffer_rx,
290 .len = 8,
291 },
292 };
293 const struct spi_buf_set tx = {
294 .buffers = tx_bufs,
295 .count = ARRAY_SIZE(tx_bufs)
296 };
297 const struct spi_buf_set rx = {
298 .buffers = rx_bufs,
299 .count = ARRAY_SIZE(rx_bufs)
300 };
301 int ret;
302
303 LOG_INF("Start half start");
304
305 (void)memset(buffer_rx, 0, BUF_SIZE);
306
307 ret = spi_transceive(dev, spi_conf, &tx, &rx);
308 if (ret) {
309 LOG_ERR("Code %d", ret);
310 zassert_false(ret, "SPI transceive failed");
311 return -1;
312 }
313
314 if (memcmp(buffer_tx, buffer_rx, 8)) {
315 to_display_format(buffer_tx, 8, buffer_print_tx);
316 to_display_format(buffer_rx, 8, buffer_print_rx);
317 LOG_ERR("Buffer contents are different: %s",
318 buffer_print_tx);
319 LOG_ERR(" vs: %s",
320 buffer_print_rx);
321 zassert_false(1, "Buffer contents are different");
322 return -1;
323 }
324
325 LOG_INF("Passed");
326
327 return 0;
328 }
329
spi_rx_half_end(const struct device * dev,struct spi_config * spi_conf)330 static int spi_rx_half_end(const struct device *dev,
331 struct spi_config *spi_conf)
332 {
333 const struct spi_buf tx_bufs[] = {
334 {
335 .buf = buffer_tx,
336 .len = BUF_SIZE,
337 },
338 };
339 const struct spi_buf rx_bufs[] = {
340 {
341 .buf = NULL,
342 .len = 8,
343 },
344 {
345 .buf = buffer_rx,
346 .len = 8,
347 },
348 };
349 const struct spi_buf_set tx = {
350 .buffers = tx_bufs,
351 .count = ARRAY_SIZE(tx_bufs)
352 };
353 const struct spi_buf_set rx = {
354 .buffers = rx_bufs,
355 .count = ARRAY_SIZE(rx_bufs)
356 };
357 int ret;
358
359 if (IS_ENABLED(CONFIG_SPI_STM32_DMA)) {
360 LOG_INF("Skip half end");
361 return 0;
362 }
363
364 LOG_INF("Start half end");
365
366 (void)memset(buffer_rx, 0, BUF_SIZE);
367
368 ret = spi_transceive(dev, spi_conf, &tx, &rx);
369 if (ret) {
370 LOG_ERR("Code %d", ret);
371 zassert_false(ret, "SPI transceive failed");
372 return -1;
373 }
374
375 if (memcmp(buffer_tx+8, buffer_rx, 8)) {
376 to_display_format(buffer_tx + 8, 8, buffer_print_tx);
377 to_display_format(buffer_rx, 8, buffer_print_rx);
378 LOG_ERR("Buffer contents are different: %s",
379 buffer_print_tx);
380 LOG_ERR(" vs: %s",
381 buffer_print_rx);
382 zassert_false(1, "Buffer contents are different");
383 return -1;
384 }
385
386 LOG_INF("Passed");
387
388 return 0;
389 }
390
spi_rx_every_4(const struct device * dev,struct spi_config * spi_conf)391 static int spi_rx_every_4(const struct device *dev,
392 struct spi_config *spi_conf)
393 {
394 const struct spi_buf tx_bufs[] = {
395 {
396 .buf = buffer_tx,
397 .len = BUF_SIZE,
398 },
399 };
400 const struct spi_buf rx_bufs[] = {
401 {
402 .buf = NULL,
403 .len = 4,
404 },
405 {
406 .buf = buffer_rx,
407 .len = 4,
408 },
409 {
410 .buf = NULL,
411 .len = 4,
412 },
413 {
414 .buf = buffer_rx + 4,
415 .len = 4,
416 },
417 };
418 const struct spi_buf_set tx = {
419 .buffers = tx_bufs,
420 .count = ARRAY_SIZE(tx_bufs)
421 };
422 const struct spi_buf_set rx = {
423 .buffers = rx_bufs,
424 .count = ARRAY_SIZE(rx_bufs)
425 };
426 int ret;
427
428 if (IS_ENABLED(CONFIG_SPI_STM32_DMA)) {
429 LOG_INF("Skip every 4");
430 return 0;
431 }
432
433 if (IS_ENABLED(CONFIG_DSPI_MCUX_EDMA)) {
434 LOG_INF("Skip every 4");
435 return 0;
436 }
437
438 LOG_INF("Start every 4");
439
440 (void)memset(buffer_rx, 0, BUF_SIZE);
441
442 ret = spi_transceive(dev, spi_conf, &tx, &rx);
443 if (ret) {
444 LOG_ERR("Code %d", ret);
445 zassert_false(ret, "SPI transceive failed");
446 return -1;
447 }
448
449 if (memcmp(buffer_tx + 4, buffer_rx, 4)) {
450 to_display_format(buffer_tx + 4, 4, buffer_print_tx);
451 to_display_format(buffer_rx, 4, buffer_print_rx);
452 LOG_ERR("Buffer contents are different: %s",
453 buffer_print_tx);
454 LOG_ERR(" vs: %s",
455 buffer_print_rx);
456 zassert_false(1, "Buffer contents are different");
457 return -1;
458 } else if (memcmp(buffer_tx + 12, buffer_rx + 4, 4)) {
459 to_display_format(buffer_tx + 12, 4, buffer_print_tx);
460 to_display_format(buffer_rx + 4, 4, buffer_print_rx);
461 LOG_ERR("Buffer contents are different: %s",
462 buffer_print_tx);
463 LOG_ERR(" vs: %s",
464 buffer_print_rx);
465 zassert_false(1, "Buffer contents are different");
466 return -1;
467 }
468
469 LOG_INF("Passed");
470
471 return 0;
472 }
473
474 #if (CONFIG_SPI_ASYNC)
475 static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
476 static struct k_poll_event async_evt =
477 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
478 K_POLL_MODE_NOTIFY_ONLY,
479 &async_sig);
480 static K_SEM_DEFINE(caller, 0, 1);
481 K_THREAD_STACK_DEFINE(spi_async_stack, STACK_SIZE);
482 static int result = 1;
483
spi_async_call_cb(struct k_poll_event * async_evt,struct k_sem * caller_sem,void * unused)484 static void spi_async_call_cb(struct k_poll_event *async_evt,
485 struct k_sem *caller_sem,
486 void *unused)
487 {
488 int ret;
489
490 LOG_DBG("Polling...");
491
492 while (1) {
493 ret = k_poll(async_evt, 1, K_MSEC(200));
494 zassert_false(ret, "one or more events are not ready");
495
496 result = async_evt->signal->result;
497 k_sem_give(caller_sem);
498
499 /* Reinitializing for next call */
500 async_evt->signal->signaled = 0U;
501 async_evt->state = K_POLL_STATE_NOT_READY;
502 }
503 }
504
spi_async_call(const struct device * dev,struct spi_config * spi_conf)505 static int spi_async_call(const struct device *dev,
506 struct spi_config *spi_conf)
507 {
508 const struct spi_buf tx_bufs[] = {
509 {
510 .buf = buffer_tx,
511 .len = BUF_SIZE,
512 },
513 };
514 const struct spi_buf rx_bufs[] = {
515 {
516 .buf = buffer_rx,
517 .len = BUF_SIZE,
518 },
519 };
520 const struct spi_buf_set tx = {
521 .buffers = tx_bufs,
522 .count = ARRAY_SIZE(tx_bufs)
523 };
524 const struct spi_buf_set rx = {
525 .buffers = rx_bufs,
526 .count = ARRAY_SIZE(rx_bufs)
527 };
528 int ret;
529
530 LOG_INF("Start async call");
531
532 ret = spi_transceive_async(dev, spi_conf, &tx, &rx, &async_sig);
533 if (ret == -ENOTSUP) {
534 LOG_DBG("Not supported");
535 return 0;
536 }
537
538 if (ret) {
539 LOG_ERR("Code %d", ret);
540 zassert_false(ret, "SPI transceive failed");
541 return -1;
542 }
543
544 k_sem_take(&caller, K_FOREVER);
545
546 if (result) {
547 LOG_ERR("Call code %d", ret);
548 zassert_false(result, "SPI transceive failed");
549 return -1;
550 }
551
552 LOG_INF("Passed");
553
554 return 0;
555 }
556 #endif
557
spi_resource_lock_test(const struct device * lock_dev,struct spi_config * spi_conf_lock,const struct device * try_dev,struct spi_config * spi_conf_try)558 static int spi_resource_lock_test(const struct device *lock_dev,
559 struct spi_config *spi_conf_lock,
560 const struct device *try_dev,
561 struct spi_config *spi_conf_try)
562 {
563 spi_conf_lock->operation |= SPI_LOCK_ON;
564
565 if (spi_complete_loop(lock_dev, spi_conf_lock)) {
566 return -1;
567 }
568
569 if (spi_release(lock_dev, spi_conf_lock)) {
570 LOG_ERR("Deadlock now?");
571 zassert_false(1, "SPI release failed");
572 return -1;
573 }
574
575 if (spi_complete_loop(try_dev, spi_conf_try)) {
576 return -1;
577 }
578
579 return 0;
580 }
581
test_spi_loopback(void)582 void test_spi_loopback(void)
583 {
584 #if (CONFIG_SPI_ASYNC)
585 struct k_thread async_thread;
586 k_tid_t async_thread_id;
587 #endif
588 const struct device *spi_slow;
589 const struct device *spi_fast;
590
591 LOG_INF("SPI test on buffers TX/RX %p/%p", buffer_tx, buffer_rx);
592
593 #if defined(CONFIG_SPI_LOOPBACK_CS_GPIO)
594 if (cs_ctrl_gpio_config()) {
595 return;
596 }
597 #endif /* CONFIG_SPI_LOOPBACK_CS_GPIO */
598
599 spi_slow = device_get_binding(SPI_DRV_NAME);
600 if (!spi_slow) {
601 LOG_ERR("Cannot find %s!\n", SPI_DRV_NAME);
602 zassert_not_null(spi_slow, "Invalid SPI device");
603 return;
604 }
605
606 spi_fast = spi_slow;
607
608 #if (CONFIG_SPI_ASYNC)
609 async_thread_id = k_thread_create(&async_thread,
610 spi_async_stack, STACK_SIZE,
611 (k_thread_entry_t)spi_async_call_cb,
612 &async_evt, &caller, NULL,
613 K_PRIO_COOP(7), 0, K_NO_WAIT);
614 #endif
615
616 LOG_INF("SPI test slow config");
617
618 if (spi_complete_multiple(spi_slow, &spi_cfg_slow) ||
619 spi_complete_loop(spi_slow, &spi_cfg_slow) ||
620 spi_null_tx_buf(spi_slow, &spi_cfg_slow) ||
621 spi_rx_half_start(spi_slow, &spi_cfg_slow) ||
622 spi_rx_half_end(spi_slow, &spi_cfg_slow) ||
623 spi_rx_every_4(spi_slow, &spi_cfg_slow)
624 #if (CONFIG_SPI_ASYNC)
625 || spi_async_call(spi_slow, &spi_cfg_slow)
626 #endif
627 ) {
628 goto end;
629 }
630
631 LOG_INF("SPI test fast config");
632
633 if (spi_complete_multiple(spi_fast, &spi_cfg_fast) ||
634 spi_complete_loop(spi_fast, &spi_cfg_fast) ||
635 spi_null_tx_buf(spi_fast, &spi_cfg_fast) ||
636 spi_rx_half_start(spi_fast, &spi_cfg_fast) ||
637 spi_rx_half_end(spi_fast, &spi_cfg_fast) ||
638 spi_rx_every_4(spi_fast, &spi_cfg_fast)
639 #if (CONFIG_SPI_ASYNC)
640 || spi_async_call(spi_fast, &spi_cfg_fast)
641 #endif
642 ) {
643 goto end;
644 }
645
646 if (spi_resource_lock_test(spi_slow, &spi_cfg_slow,
647 spi_fast, &spi_cfg_fast)) {
648 goto end;
649 }
650
651 LOG_INF("All tx/rx passed");
652 end:
653 #if (CONFIG_SPI_ASYNC)
654 k_thread_abort(async_thread_id);
655 #else
656 ;
657 #endif
658 }
659
660 /*test case main entry*/
test_main(void)661 void test_main(void)
662 {
663 ztest_test_suite(test_spi, ztest_unit_test(test_spi_loopback));
664 ztest_run_test_suite(test_spi);
665 }
666