1 /*
2 * Copyright (c) 2021 Marc Reilly, Creative Product Design
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <zephyr/drivers/spi.h>
16
17 #define SPIBB_NODE DT_NODELABEL(spibb0)
18
19 /*
20 * writes 5 9bit words, you can check the output with a logic analyzer
21 */
test_basic_write_9bit_words(const struct device * dev,struct spi_cs_control * cs)22 void test_basic_write_9bit_words(const struct device *dev,
23 struct spi_cs_control *cs)
24 {
25 struct spi_config config;
26
27 config.frequency = 125000;
28 config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(9);
29 config.slave = 0;
30 config.cs = *cs;
31
32 uint16_t buff[5] = { 0x0101, 0x00ff, 0x00a5, 0x0000, 0x0102};
33 int len = 5 * sizeof(buff[0]);
34
35 struct spi_buf tx_buf = { .buf = buff, .len = len };
36 struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 };
37
38 int ret = spi_write(dev, &config, &tx_bufs);
39
40 printf("basic_write_9bit_words; ret: %d\n", ret);
41 printf(" wrote %04x %04x %04x %04x %04x\n",
42 buff[0], buff[1], buff[2], buff[3], buff[4]);
43 }
44
45 /*
46 * A more complicated xfer, sends two words, then sends and receives another
47 * 3 words. Connect MOSI to MISO to test read
48 */
test_9bit_loopback_partial(const struct device * dev,struct spi_cs_control * cs)49 void test_9bit_loopback_partial(const struct device *dev,
50 struct spi_cs_control *cs)
51 {
52 struct spi_config config;
53
54 config.frequency = 125000;
55 config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(9);
56 config.slave = 0;
57 config.cs = *cs;
58
59 enum { datacount = 5 };
60 uint16_t buff[datacount] = { 0x0101, 0x0102, 0x0003, 0x0004, 0x0105};
61 uint16_t rxdata[3];
62
63 const int stride = sizeof(buff[0]);
64
65 struct spi_buf tx_buf[2] = {
66 {.buf = buff, .len = (2) * stride},
67 {.buf = buff + (2), .len = (datacount - 2)*stride},
68 };
69 struct spi_buf rx_buf[2] = {
70 {.buf = 0, .len = (2) * stride},
71 {.buf = rxdata, .len = (datacount - 2) * stride},
72 };
73
74 struct spi_buf_set tx_set = { .buffers = tx_buf, .count = 2 };
75 struct spi_buf_set rx_set = { .buffers = rx_buf, .count = 2 };
76
77 int ret = spi_transceive(dev, &config, &tx_set, &rx_set);
78
79 printf("9bit_loopback_partial; ret: %d\n", ret);
80 printf(" tx (i) : %04x %04x\n", buff[0], buff[1]);
81 printf(" tx (ii) : %04x %04x %04x\n", buff[2], buff[3], buff[4]);
82 printf(" rx (ii) : %04x %04x %04x\n", rxdata[0], rxdata[1], rxdata[2]);
83 }
84
85 /*
86 * Tests 8 bit transfer at higher frequency, at this frequency there won't be
87 * any busy waits between clock edges, the rate is limited by gpio calls etc.
88 */
test_8bit_xfer(const struct device * dev,struct spi_cs_control * cs)89 void test_8bit_xfer(const struct device *dev, struct spi_cs_control *cs)
90 {
91 struct spi_config config;
92
93 config.frequency = 1000000;
94 config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8);
95 config.slave = 0;
96 config.cs = *cs;
97
98 enum { datacount = 5 };
99 uint8_t buff[datacount] = { 0x01, 0x02, 0x03, 0x04, 0x05};
100 uint8_t rxdata[datacount];
101
102 struct spi_buf tx_buf[1] = {
103 {.buf = buff, .len = datacount},
104 };
105 struct spi_buf rx_buf[1] = {
106 {.buf = rxdata, .len = datacount},
107 };
108
109 struct spi_buf_set tx_set = { .buffers = tx_buf, .count = 1 };
110 struct spi_buf_set rx_set = { .buffers = rx_buf, .count = 1 };
111
112 int ret = spi_transceive(dev, &config, &tx_set, &rx_set);
113
114 printf("8bit_loopback_partial; ret: %d\n", ret);
115 printf(" tx (i) : %02x %02x %02x %02x %02x\n",
116 buff[0], buff[1], buff[2], buff[3], buff[4]);
117 printf(" rx (i) : %02x %02x %02x %02x %02x\n",
118 rxdata[0], rxdata[1], rxdata[2], rxdata[3], rxdata[4]);
119 }
120
main(void)121 int main(void)
122 {
123 const struct device *const dev = DEVICE_DT_GET(SPIBB_NODE);
124
125 if (!device_is_ready(dev)) {
126 printk("%s: device not ready.\n", dev->name);
127 return 0;
128 }
129
130 struct spi_cs_control cs_ctrl = (struct spi_cs_control){
131 .gpio = GPIO_DT_SPEC_GET(SPIBB_NODE, cs_gpios),
132 .delay = 0u,
133 };
134
135 /*
136 * Loop through the various demo functions, the delays make it easier to
137 * locate on a scope/analyzer, the longer delay at the end helps discern
138 * where the pattern repeats.
139 */
140 while (1) {
141 test_basic_write_9bit_words(dev, &cs_ctrl);
142 k_sleep(K_MSEC(200));
143
144 test_9bit_loopback_partial(dev, &cs_ctrl);
145 k_sleep(K_MSEC(200));
146
147 test_8bit_xfer(dev, &cs_ctrl);
148 k_sleep(K_MSEC(1000));
149 }
150 return 0;
151 }
152