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 * 2022-01-21 charlown first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "drivers/dev_spi.h"
14 #include "board.h"
15 #include "drv_spi.h"
16 #include "ch32f20x_spi.h"
17 #include "ch32f20x_rcc.h"
18
19 #ifdef BSP_USING_SPI
20
21 #define LOG_TAG "drv.spi"
22 #include "drv_log.h"
23
24 #ifndef ITEM_NUM
25 #define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
26 #endif
27
28 struct spi_bus_device
29 {
30 struct rt_spi_bus parent;
31 char *name;
32 SPI_TypeDef *periph;
33 rt_base_t cs_pin;
34 struct rt_spi_device spi_device;
35 };
36
37 static struct spi_bus_device spi_bus_device_list[] = {
38 #ifdef BSP_USING_SPI1
39 {.periph = SPI1,
40 .name = "spi1"},
41 #endif
42
43 #ifdef BSP_USING_SPI2
44 {.periph = SPI2,
45 .name = "spi2"},
46 #endif
47
48 #ifdef BSP_USING_SPI3
49 {.periph = SPI3,
50 .name = "spi3"},
51 #endif
52 };
53
54 /**
55 * Attach the spi device to SPI bus, this function must be used after initialization.
56 */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,rt_uint32_t pin)57 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_uint32_t pin)
58 {
59 rt_err_t result;
60 struct rt_spi_bus *spi_bus;
61 struct spi_bus_device *spi_bus_dev;
62
63 RT_ASSERT(bus_name != RT_NULL);
64 RT_ASSERT(device_name != RT_NULL);
65
66 spi_bus = (struct rt_spi_bus *)rt_device_find(bus_name);
67
68 RT_ASSERT(spi_bus != RT_NULL);
69
70 spi_bus_dev = (struct spi_bus_device *)spi_bus;
71
72 spi_bus_dev->cs_pin = pin;
73
74 //often active low, output from master
75 rt_pin_mode(spi_bus_dev->cs_pin, PIN_MODE_OUTPUT);
76 rt_pin_write(spi_bus_dev->cs_pin, PIN_HIGH);
77
78 result = rt_spi_bus_attach_device(&spi_bus_dev->spi_device, device_name, bus_name, RT_NULL);
79
80 if (result != RT_EOK)
81 {
82 LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
83 }
84
85 LOG_D("%s attach to %s done", device_name, bus_name);
86
87 return result;
88 }
89
ch32f2_spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)90 static rt_err_t ch32f2_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
91 {
92 struct rt_spi_bus *spi_bus;
93 struct spi_bus_device *spi_bus_dev;
94 rt_uint32_t spi_clock;
95
96 SPI_InitTypeDef SPI_InitStruct;
97
98 RT_ASSERT(device != RT_NULL);
99 RT_ASSERT(configuration != RT_NULL);
100
101 //device is not RT_NULL, so spi_bus not need check
102 spi_bus = (struct rt_spi_bus *)device->bus;
103 spi_bus_dev = (struct spi_bus_device *)spi_bus;
104
105 ch32f2_spi_clock_and_io_init(spi_bus_dev->periph);
106
107 spi_clock = ch32f2_spi_clock_get(spi_bus_dev->periph);
108
109 if (configuration->data_width <= 8)
110 {
111 SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
112 }
113 else if (configuration->data_width <= 16)
114 {
115 SPI_InitStruct.SPI_DataSize = SPI_DataSize_16b;
116 }
117 else
118 {
119 return -RT_EIO;
120 }
121
122 if (configuration->max_hz >= spi_clock / 2)
123 {
124 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
125 }
126 else if (configuration->max_hz >= spi_clock / 4)
127 {
128 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
129 }
130 else if (configuration->max_hz >= spi_clock / 8)
131 {
132 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
133 }
134 else if (configuration->max_hz >= spi_clock / 16)
135 {
136 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
137 }
138 else if (configuration->max_hz >= spi_clock / 32)
139 {
140 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
141 }
142 else if (configuration->max_hz >= spi_clock / 64)
143 {
144 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
145 }
146 else if (configuration->max_hz >= spi_clock / 128)
147 {
148 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
149 }
150 else
151 {
152 /* min prescaler 256 */
153 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
154 }
155
156 switch (configuration->mode & RT_SPI_MODE_3)
157 {
158 case RT_SPI_MODE_0:
159 SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
160 SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
161 break;
162 case RT_SPI_MODE_1:
163 SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
164 SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
165 break;
166 case RT_SPI_MODE_2:
167 SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
168 SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
169 break;
170 case RT_SPI_MODE_3:
171 SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
172 SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
173 break;
174 }
175
176 /* MSB or LSB */
177 if (configuration->mode & RT_SPI_MSB)
178 {
179 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
180 }
181 else
182 {
183 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_LSB;
184 }
185
186 SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
187 SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
188 SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
189
190 SPI_Init(spi_bus_dev->periph, &SPI_InitStruct);
191 /* Enable SPI_MASTER */
192 SPI_Cmd(spi_bus_dev->periph, ENABLE);
193
194 return RT_EOK;
195 };
196
ch32f2_spi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)197 static rt_ssize_t ch32f2_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
198 {
199 struct rt_spi_bus *spi_bus;
200 struct spi_bus_device *spi_bus_dev;
201 struct rt_spi_configuration *config;
202
203 RT_ASSERT(device != NULL);
204 RT_ASSERT(message != NULL);
205
206 //device is not RT_NULL, so spi_bus not need check
207 spi_bus = (struct rt_spi_bus *)device->bus;
208 spi_bus_dev = (struct spi_bus_device *)spi_bus;
209 config = &device->config;
210
211 /* take CS */
212 if (message->cs_take)
213 {
214 rt_pin_write(spi_bus_dev->cs_pin, PIN_LOW);
215 LOG_D("spi take cs\n");
216 }
217
218 if (config->data_width <= 8)
219 {
220 const rt_uint8_t *send_ptr = message->send_buf;
221 rt_uint8_t *recv_ptr = message->recv_buf;
222 rt_uint32_t size = message->length;
223 rt_uint8_t data;
224
225 LOG_D("spi poll transfer start: %d\n", size);
226
227 while (size--)
228 {
229 data = 0xFF;
230
231 if (send_ptr != RT_NULL)
232 {
233 data = *send_ptr++;
234 }
235
236 //Wait until the transmit buffer is empty
237 while (RESET == SPI_I2S_GetFlagStatus(spi_bus_dev->periph, SPI_I2S_FLAG_TXE))
238 ;
239 // Send the byte
240 SPI_I2S_SendData(spi_bus_dev->periph, data);
241
242 //Wait until a data is received
243 while (RESET == SPI_I2S_GetFlagStatus(spi_bus_dev->periph, SPI_I2S_FLAG_RXNE))
244 ;
245 // Get the received data
246 data = SPI_I2S_ReceiveData(spi_bus_dev->periph);
247
248 if (recv_ptr != RT_NULL)
249 {
250 *recv_ptr++ = data;
251 }
252 }
253 LOG_D("spi poll transfer finsh\n");
254 }
255 else if (config->data_width <= 16)
256 {
257 const rt_uint16_t *send_ptr = message->send_buf;
258 rt_uint16_t *recv_ptr = message->recv_buf;
259 rt_uint32_t size = message->length;
260 rt_uint16_t data;
261
262 while (size--)
263 {
264 data = 0xFF;
265
266 if (send_ptr != RT_NULL)
267 {
268 data = *send_ptr++;
269 }
270
271 //Wait until the transmit buffer is empty
272 while (RESET == SPI_I2S_GetFlagStatus(spi_bus_dev->periph, SPI_I2S_FLAG_TXE))
273 ;
274 // Send the byte
275 SPI_I2S_SendData(spi_bus_dev->periph, data);
276
277 //Wait until a data is received
278 while (RESET == SPI_I2S_GetFlagStatus(spi_bus_dev->periph, SPI_I2S_FLAG_RXNE))
279 ;
280 // Get the received data
281 data = SPI_I2S_ReceiveData(spi_bus_dev->periph);
282
283 if (recv_ptr != RT_NULL)
284 {
285 *recv_ptr++ = data;
286 }
287 }
288 }
289
290 /* release CS */
291 if (message->cs_release)
292 {
293 rt_pin_write(spi_bus_dev->cs_pin, PIN_HIGH);
294 LOG_D("spi release cs\n");
295 }
296
297 return message->length;
298 };
299
300 static struct rt_spi_ops spi_ops = {
301 .configure = ch32f2_spi_configure,
302 .xfer = ch32f2_spi_xfer};
303
rt_hw_spi_init(void)304 int rt_hw_spi_init(void)
305 {
306 int index;
307
308 for (index = 0; index < ITEM_NUM(spi_bus_device_list); index++)
309 {
310 rt_spi_bus_register(&spi_bus_device_list[index].parent, spi_bus_device_list[index].name, &spi_ops);
311 }
312
313 return RT_EOK;
314 }
315
316 INIT_BOARD_EXPORT(rt_hw_spi_init);
317
318 #endif /* BSP_USING_SPI */
319