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