1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020-06-27 AHTYDHD the first version
9 */
10
11 #include "drv_spi.h"
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include "inc/hw_memmap.h"
15 #include "driverlib/ssi.h"
16 #include "driverlib/gpio.h"
17 #include "driverlib/sysctl.h"
18
19 #ifdef RT_USING_SPI
20
21 #if defined(BSP_USING_SPI0) || defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3)
22 /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
23 #include "tm4c123_config.h"
24 #include "spi_config.h"
25 #include <string.h>
26
27 //#define DRV_DEBUG
28 #define LOG_TAG "drv.spi"
29 #include <drv_log.h>
30
31 enum
32 {
33 #ifdef BSP_USING_SPI0
34 SPI0_INDEX,
35 #endif
36 #ifdef BSP_USING_SPI1
37 SPI1_INDEX,
38 #endif
39 #ifdef BSP_USING_SPI2
40 SPI2_INDEX,
41 #endif
42 #ifdef BSP_USING_SPI3
43 SPI3_INDEX,
44 #endif
45 };
46
47 static struct tm4c123_spi_config spi_config[] =
48 {
49 #ifdef BSP_USING_SPI0
50 SPI0_BUS_CONFIG,
51 #endif
52
53 #ifdef BSP_USING_SPI1
54 SPI1_BUS_CONFIG,
55 #endif
56
57 #ifdef BSP_USING_SPI2
58 SPI2_BUS_CONFIG,
59 #endif
60
61 #ifdef BSP_USING_SPI3
62 SPI3_BUS_CONFIG,
63 #endif
64
65 };
66
67 static struct tm4c123_spi spi_bus_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0};
68
tm4c123_spi_configure(struct tm4c123_spi * spi_drv,struct rt_spi_configuration * cfg)69 static rt_err_t tm4c123_spi_configure(struct tm4c123_spi *spi_drv, struct rt_spi_configuration *cfg)
70 {
71 RT_ASSERT(spi_drv != RT_NULL);
72 RT_ASSERT(cfg != RT_NULL);
73
74 uint32_t ui32Protocol, ui32Mode;
75 uint32_t ui32BitRate = (uint32_t)cfg->max_hz;
76 uint32_t ui32DataWidth = (uint32_t)cfg->data_width;
77 uint32_t pui32DataRx[1];
78 rt_uint8_t ui8Protocol = 0;
79
80 if (cfg->mode & RT_SPI_SLAVE)
81 {
82 ui32Mode = SSI_MODE_SLAVE;
83 }
84 else
85 {
86 ui32Mode = SSI_MODE_MASTER;
87 }
88
89 if (cfg->mode & RT_SPI_CPHA)
90 {
91 ui8Protocol += 1;
92 }
93 else
94 {
95 ui8Protocol += 0;
96 }
97
98 if (cfg->mode & RT_SPI_CPOL)
99 {
100 ui8Protocol += 2;
101 }
102 else
103 {
104 ui8Protocol += 0;
105 }
106
107 switch (ui8Protocol)
108 {
109 case 0:
110 ui32Protocol = SSI_FRF_MOTO_MODE_0;
111 break;
112 case 1:
113 ui32Protocol = SSI_FRF_MOTO_MODE_1;
114 break;
115 case 2:
116 ui32Protocol = SSI_FRF_MOTO_MODE_2;
117 break;
118 case 3:
119 ui32Protocol = SSI_FRF_MOTO_MODE_3;
120 break;
121 default:
122 ui32Protocol = SSI_FRF_MOTO_MODE_0;
123 break;
124 }
125
126 SSIConfigSetExpClk(spi_drv->config->base, SysCtlClockGet(), ui32Protocol,
127 ui32Mode, ui32BitRate, ui32DataWidth);
128
129 LOG_D("ssiclk freq: %d, SPI limiting freq: %d", SysCtlClockGet(), cfg->max_hz);
130
131 SSIEnable(spi_drv->config->base);
132
133 while (SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
134 {
135 }
136
137 LOG_D("%s init done", spi_drv->config->bus_name);
138
139 return RT_EOK;
140 }
141
spixfer(struct rt_spi_device * device,struct rt_spi_message * message)142 static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
143 {
144
145 rt_size_t message_length;
146 rt_uint8_t *recv_buf;
147 const rt_uint8_t *send_buf;
148 uint32_t ReadData = 0;
149 int i = 0;
150
151 RT_ASSERT(device != RT_NULL);
152 RT_ASSERT(device->bus != RT_NULL);
153 RT_ASSERT(device->bus->parent.user_data != RT_NULL);
154 RT_ASSERT(message != RT_NULL);
155
156 struct tm4c123_spi *spi_drv = rt_container_of(device->bus, struct tm4c123_spi, spi_bus);
157 struct tm4c123_hw_spi_cs *cs = device->parent.user_data;
158
159 if (message->cs_take)
160 {
161 GPIOPinWrite(cs->portbase, cs->GPIO_Pin, 0);
162 }
163
164 LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
165 LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
166 spi_drv->config->bus_name,
167 (uint32_t)message->send_buf,
168 (uint32_t)message->recv_buf, message->length);
169
170 message_length = message->length;
171 recv_buf = message->recv_buf;
172 send_buf = message->send_buf;
173
174 if (message->send_buf && message->recv_buf)
175 {
176 for (i = 0; i < message_length; i++)
177 {
178 SSIDataPut(spi_drv->config->base, (uint32_t)send_buf[i]);
179 while (SSIBusy(spi_drv->config->base))
180 {
181 }
182 SSIDataGet(spi_drv->config->base, &ReadData);
183 recv_buf[i] = (unsigned char)ReadData;
184 }
185
186 }
187 else if (message->send_buf)
188 {
189 for (i = 0; i < message_length; i++)
190 {
191 SSIDataPut(spi_drv->config->base, (uint32_t)send_buf[i]);
192 while (SSIBusy(spi_drv->config->base))
193 {
194 }
195 SSIDataGet(spi_drv->config->base, &ReadData);
196 }
197 }
198 else
199 {
200 for (i = 0; i < message_length; i++)
201 {
202 SSIDataPut(spi_drv->config->base, (uint32_t)0xff);
203 while (SSIBusy(spi_drv->config->base))
204 {
205 }
206 SSIDataGet(spi_drv->config->base, &ReadData);
207 recv_buf[i] = (unsigned char)ReadData;
208 }
209 }
210
211 LOG_D("%s transfer done", spi_drv->config->bus_name);
212
213 if (message->cs_release)
214 {
215 GPIOPinWrite(cs->portbase, cs->GPIO_Pin, cs->GPIO_Pin);
216 }
217
218 return message->length;
219 }
220
221
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)222 static rt_err_t spi_configure(struct rt_spi_device *device,
223 struct rt_spi_configuration *configuration)
224 {
225 RT_ASSERT(device != RT_NULL);
226 RT_ASSERT(configuration != RT_NULL);
227
228 struct tm4c123_spi *spi_drv = rt_container_of(device->bus, struct tm4c123_spi, spi_bus);
229 spi_drv->cfg = configuration;
230
231 return tm4c123_spi_configure(spi_drv, configuration);
232 }
233
234 static const struct rt_spi_ops tm4c123_spi_ops =
235 {
236 .configure = spi_configure,
237 .xfer = spixfer,
238 };
239
240
rt_hw_spi_bus_init(void)241 static int rt_hw_spi_bus_init(void)
242 {
243 rt_err_t result;
244 for (int i = 0; i < sizeof(spi_config) / sizeof(spi_config[0]); i++)
245 {
246 spi_bus_obj[i].config = &spi_config[i];
247 spi_bus_obj[i].spi_bus.parent.user_data = &spi_config[i];
248
249
250 result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, spi_config[i].bus_name, &tm4c123_spi_ops);
251 RT_ASSERT(result == RT_EOK);
252
253 LOG_D("%s bus init done", spi_config[i].bus_name);
254 }
255
256 return result;
257 }
258
259 /**
260 * Attach the spi device to SPI bus, this function must be used after initialization.
261 */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,uint32_t portindex,uint32_t cs_gpiobase,uint32_t cs_gpio_pin)262 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, uint32_t portindex, uint32_t cs_gpiobase, uint32_t cs_gpio_pin)
263 {
264 RT_ASSERT(bus_name != RT_NULL);
265 RT_ASSERT(device_name != RT_NULL);
266
267 rt_err_t result;
268 struct rt_spi_device *spi_device;
269 struct tm4c123_hw_spi_cs *cs_pin;
270
271 /* initialize the cs pin && select the slave*/
272 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA + portindex);
273 GPIOPinTypeGPIOOutput(cs_gpiobase, cs_gpio_pin);
274 GPIOPinWrite(cs_gpiobase, cs_gpio_pin, cs_gpio_pin);
275
276 /* attach the device to spi bus*/
277 spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
278 RT_ASSERT(spi_device != RT_NULL);
279 cs_pin = (struct tm4c123_hw_spi_cs *)rt_malloc(sizeof(struct tm4c123_hw_spi_cs));
280 RT_ASSERT(cs_pin != RT_NULL);
281 cs_pin->portbase = cs_gpiobase;
282 cs_pin->GPIO_Pin = cs_gpio_pin;
283 result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
284
285 if (result != RT_EOK)
286 {
287 LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
288 }
289
290 RT_ASSERT(result == RT_EOK);
291
292 LOG_D("%s attach to %s done", device_name, bus_name);
293
294 return result;
295 }
296
297
rt_hw_spi_init(void)298 int rt_hw_spi_init(void)
299 {
300 spi_hw_config();
301
302 return rt_hw_spi_bus_init();
303 }
304 INIT_BOARD_EXPORT(rt_hw_spi_init);
305
306 #endif /* defined(BSP_USING_SPI0) || defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3) */
307 #endif /*RT_USING_SPI*/
308
309 /************************** end of file ******************/
310