1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-07-27 Chushicheng the first version
9 */
10
11 #include "drv_spi.h"
12 #include "pico/binary_info.h"
13 #include "hardware/gpio.h"
14 #include "hardware/spi.h"
15 #include "hardware/dma.h"
16
17 #ifdef BSP_USING_SPI
18 #define DBG_TAG "drv.spi"
19 #define DBG_LVL DBG_INFO
20 #include <rtdbg.h>
21
22 struct pico_spi
23 {
24 struct rt_spi_bus parent;
25 spi_inst_t *handle;
26 rt_uint8_t spi_rx_pin;
27 rt_uint8_t spi_tx_pin;
28 rt_uint8_t spi_sck_pin;
29 rt_uint8_t spi_cs_pin;
30 rt_uint8_t dma_tx;
31 rt_uint8_t dma_rx;
32 char *device_name;
33
34 };
35
36 static struct pico_spi pico_spi_obj[] =
37 {
38 #ifdef BSP_USING_SPI0
39 {
40 .handle = spi0,
41 .spi_rx_pin = BSP_SPI0_MISO_PIN,
42 .spi_tx_pin = BSP_SPI0_MOSI_PIN,
43 .spi_sck_pin = BSP_SPI0_SCK_PIN,
44 .spi_cs_pin = BSP_SPI0_CS_PIN,
45 .device_name = "spi0",
46 },
47 #endif
48 #ifdef BSP_USING_SPI1
49 {
50 .handle = spi1,
51 .spi_rx_pin = BSP_SPI1_MISO_PIN,
52 .spi_tx_pin = BSP_SPI1_MOSI_PIN,
53 .spi_sck_pin = BSP_SPI1_SCK_PIN,
54 .spi_cs_pin = BSP_SPI1_CS_PIN,
55 .device_name = "spi1",
56 },
57 #endif
58 };
59
pico_spi_init(struct pico_spi * spi_drv,struct rt_spi_configuration * cfg)60 static rt_err_t pico_spi_init(struct pico_spi *spi_drv, struct rt_spi_configuration *cfg)
61 {
62 RT_ASSERT(spi_drv != RT_NULL);
63 RT_ASSERT(cfg != RT_NULL);
64
65 spi_inst_t *spi_handle = spi_drv->handle;
66 spi_cpol_t cpol;
67 spi_cpha_t cpha;
68 rt_uint8_t dma_transfer_size;
69
70 if (cfg->mode & RT_SPI_SLAVE)
71 {
72 spi_set_slave(spi_handle, true);
73 }
74 else
75 {
76 spi_set_slave(spi_handle, false);
77 }
78
79 if (cfg->mode & RT_SPI_CPHA)
80 {
81 cpha = SPI_CPHA_1;
82 }
83 else
84 {
85 cpha = SPI_CPHA_0;
86 }
87
88 if (cfg->mode & RT_SPI_CPOL)
89 {
90 cpol = SPI_CPOL_1;
91 }
92 else
93 {
94 cpol = SPI_CPOL_0;
95 }
96
97 if (cfg->data_width >= 4
98 && cfg->data_width <= 16)
99 {
100 spi_set_format(spi_handle, cfg->data_width, cpol, cpha, SPI_MSB_FIRST);
101 }
102 else
103 {
104 return -RT_EIO;
105 }
106
107 LOG_D("spi baudrate:%d", cfg->max_hz);
108 spi_init(spi_handle, cfg->max_hz);
109 gpio_set_function(spi_drv->spi_rx_pin, GPIO_FUNC_SPI);
110 gpio_init(spi_drv->spi_cs_pin);
111 gpio_set_function(spi_drv->spi_sck_pin, GPIO_FUNC_SPI);
112 gpio_set_function(spi_drv->spi_tx_pin, GPIO_FUNC_SPI);
113 // Make the SPI pins available to picotool
114 bi_decl(bi_3pins_with_func(spi_drv->spi_rx_pin, spi_drv->spi_tx_pin, spi_drv->spi_sck_pin, GPIO_FUNC_SPI));
115 // Make the CS pin available to picotool
116 bi_decl(bi_1pin_with_name(spi_drv->spi_cs_pin, "SPI CS"));
117
118 // Grab some unused dma channels
119 spi_drv->dma_tx = dma_claim_unused_channel(true);
120 spi_drv->dma_rx = dma_claim_unused_channel(true);
121 /* DMA configuration */
122 if(cfg->data_width == 8)
123 {
124 dma_transfer_size = DMA_SIZE_8;
125 }
126 else if(cfg->data_width == 16)
127 {
128 dma_transfer_size = DMA_SIZE_16;
129 }
130 else if(cfg->data_width == 32)
131 {
132 dma_transfer_size = DMA_SIZE_32;
133 }
134 dma_channel_config c = dma_channel_get_default_config(spi_drv->dma_tx);
135 channel_config_set_transfer_data_size(&c, dma_transfer_size);
136 channel_config_set_dreq(&c, spi_get_index(spi_handle) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
137 dma_channel_set_config(spi_drv->dma_tx, &c, false);
138
139 c = dma_channel_get_default_config(spi_drv->dma_rx);
140 channel_config_set_transfer_data_size(&c, dma_transfer_size);
141 channel_config_set_dreq(&c, spi_get_index(spi_handle) ? DREQ_SPI1_RX : DREQ_SPI0_RX);
142 channel_config_set_read_increment(&c, false);
143 channel_config_set_write_increment(&c, true);
144 dma_channel_set_config(spi_drv->dma_rx, &c, false);
145 return RT_EOK;
146 }
147
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,rt_base_t cs_pin)148 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
149 {
150 rt_err_t ret = RT_EOK;
151
152 struct rt_spi_device *spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
153
154 ret = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
155
156 return ret;
157 }
158
spixfer(struct rt_spi_device * device,struct rt_spi_message * message)159 static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
160 {
161 int i;
162
163 RT_ASSERT(device != RT_NULL);
164 RT_ASSERT(device->bus != RT_NULL);
165
166 struct pico_spi *spi = rt_container_of(device->bus, struct pico_spi, parent);
167
168 if(message->cs_take && (device->cs_pin != PIN_NONE))
169 {
170 rt_pin_write(device->cs_pin, PIN_LOW);
171 }
172
173 dma_channel_config c = dma_get_channel_config(spi->dma_tx);
174 dma_channel_configure(spi->dma_tx, &c,
175 &spi_get_hw(spi->handle)->dr, // write address
176 (uint8_t *)(message->send_buf), // read address
177 message->length, // element count (each element is of size transfer_data_size)
178 false); // don't start yet
179
180 c = dma_get_channel_config(spi->dma_rx);
181 dma_channel_configure(spi->dma_rx, &c,
182 (uint8_t *)(message->recv_buf), // write address
183 &spi_get_hw(spi->handle)->dr, // read address
184 message->length, // element count (each element is of size transfer_data_size)
185 false); // don't start yet
186
187 dma_start_channel_mask((1u << spi->dma_tx) | (1u << spi->dma_rx));
188 dma_channel_wait_for_finish_blocking(spi->dma_tx);
189 dma_channel_wait_for_finish_blocking(spi->dma_rx);
190
191 if(message->cs_release && (device->cs_pin != PIN_NONE))
192 {
193 rt_pin_write(device->cs_pin, PIN_HIGH);
194 }
195
196 return message->length;
197 }
198
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)199 static rt_err_t spi_configure(struct rt_spi_device *device,
200 struct rt_spi_configuration *configuration)
201 {
202 rt_err_t ret = RT_EOK;
203 struct pico_spi *spi = rt_container_of(device->bus, struct pico_spi, parent);
204 ret = pico_spi_init(spi, configuration);
205
206 return ret;
207 }
208
209 static const struct rt_spi_ops pico_spi_ops =
210 {
211 .configure = spi_configure,
212 .xfer = spixfer,
213 };
214
rt_hw_spi_init(void)215 int rt_hw_spi_init(void)
216 {
217 int result = RT_EOK;
218
219 for (rt_size_t i = 0; i < sizeof(pico_spi_obj) / sizeof(struct pico_spi); i++)
220 {
221 LOG_D("%s initing", pico_spi_obj[i].device_name);
222 /* register spi device */
223 if (rt_spi_bus_register(&pico_spi_obj[i].parent, pico_spi_obj[i].device_name, &pico_spi_ops) == RT_EOK)
224 {
225 LOG_D("%s init success", pico_spi_obj[i].device_name);
226 }
227 else
228 {
229 LOG_E("%s register failed", pico_spi_obj[i].device_name);
230 result = -RT_ERROR;
231 }
232 }
233
234 return result;
235 }
236 INIT_BOARD_EXPORT(rt_hw_spi_init);
237
238 #endif /* BSP_USING_SPI */
239