1 /*
2 * Copyright (c) 2006-2025 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2025-01-23 CYFS first version
9 */
10 #include <rthw.h>
11 #include <rtdevice.h>
12 #include <dev_spi_bit_ops.h>
13
14 #ifdef RT_USING_SOFT_SPI
15 #if !defined(RT_USING_SOFT_SPI0) &&\
16 !defined(RT_USING_SOFT_SPI1) && !defined(RT_USING_SOFT_SPI2) &&\
17 !defined(RT_USING_SOFT_SPI3) && !defined(RT_USING_SOFT_SPI4) &&\
18 !defined(RT_USING_SOFT_SPI5) && !defined(RT_USING_SOFT_SPI6)
19 #error "Please define at least one RT_USING_SOFT_SPIx"
20 /*
21 This driver can be disabled at:
22 menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers
23 */
24 #endif
25
26 #define DBG_ENABLE
27 #define DBG_TAG "SPI_S"
28 #ifdef RT_SPI_BITOPS_DEBUG
29 #define DBG_LEVEL DBG_LOG
30 #endif
31 #include <rtdbg.h>
32
33 /* spi config class */
34 struct rt_soft_spi_config
35 {
36 rt_base_t sck;
37 rt_base_t miso;
38 rt_base_t mosi;
39 rt_uint32_t timing_delay;
40 const char *bus_name;
41 };
42
43 /* spi dirver class */
44 struct rt_soft_spi
45 {
46 struct rt_spi_bit_obj spi;
47 struct rt_spi_bit_ops ops;
48 struct rt_soft_spi_config *cfg;
49 };
50
51 static struct rt_soft_spi_config soft_spi_config[] =
52 {
53 #ifdef RT_USING_SOFT_SPI0
54 {
55 .sck = RT_SOFT_SPI0_SCK_PIN,
56 .miso = RT_SOFT_SPI0_MISO_PIN,
57 .mosi = RT_SOFT_SPI0_MOSI_PIN,
58 .timing_delay = RT_SOFT_SPI0_TIMING_DELAY,
59 .bus_name = RT_SOFT_SPI0_BUS_NAME,
60 },
61 #endif /*RT_USING_SOFT_SPI0*/
62 #ifdef RT_USING_SOFT_SPI1
63 {
64 .sck = RT_SOFT_SPI1_SCK_PIN,
65 .miso = RT_SOFT_SPI1_MISO_PIN,
66 .mosi = RT_SOFT_SPI1_MOSI_PIN,
67 .timing_delay = RT_SOFT_SPI1_TIMING_DELAY,
68 .bus_name = RT_SOFT_SPI1_BUS_NAME,
69 },
70 #endif /*RT_USING_SOFT_SPI1*/
71 #ifdef RT_USING_SOFT_SPI2
72 {
73 .sck = RT_SOFT_SPI2_SCK_PIN,
74 .miso = RT_SOFT_SPI2_MISO_PIN,
75 .mosi = RT_SOFT_SPI2_MOSI_PIN,
76 .timing_delay = RT_SOFT_SPI2_TIMING_DELAY,
77 .bus_name = RT_SOFT_SPI2_BUS_NAME,
78 },
79 #endif /*RT_USING_SOFT_SPI2*/
80 #ifdef RT_USING_SOFT_SPI3
81 {
82 .sck = RT_SOFT_SPI3_SCK_PIN,
83 .miso = RT_SOFT_SPI3_MISO_PIN,
84 .mosi = RT_SOFT_SPI3_MOSI_PIN,
85 .timing_delay = RT_SOFT_SPI3_TIMING_DELAY,
86 .bus_name = RT_SOFT_SPI3_BUS_NAME,
87 },
88 #endif /*RT_USING_SOFT_SPI3*/
89 #ifdef RT_USING_SOFT_SPI4
90 {
91 .sck = RT_SOFT_SPI4_SCK_PIN,
92 .miso = RT_SOFT_SPI4_MISO_PIN,
93 .mosi = RT_SOFT_SPI4_MOSI_PIN,
94 .timing_delay = RT_SOFT_SPI4_TIMING_DELAY,
95 .bus_name = RT_SOFT_SPI4_BUS_NAME,
96 },
97 #endif /*RT_USING_SOFT_SPI4*/
98 #ifdef RT_USING_SOFT_SPI5
99 {
100 .sck = RT_SOFT_SPI5_SCK_PIN,
101 .miso = RT_SOFT_SPI5_MISO_PIN,
102 .mosi = RT_SOFT_SPI5_MOSI_PIN,
103 .timing_delay = RT_SOFT_SPI5_TIMING_DELAY,
104 .bus_name = RT_SOFT_SPI5_BUS_NAME,
105 },
106 #endif /*RT_USING_SOFT_SPI5*/
107 #ifdef RT_USING_SOFT_SPI6
108 {
109 .sck = RT_SOFT_SPI6_SCK_PIN,
110 .miso = RT_SOFT_SPI6_MISO_PIN,
111 .mosi = RT_SOFT_SPI6_MOSI_PIN,
112 .timing_delay = RT_SOFT_SPI6_TIMING_DELAY,
113 .bus_name = RT_SOFT_SPI6_BUS_NAME,
114 },
115 #endif /*RT_USING_SOFT_SPI6*/
116
117 };
118
119 static struct rt_soft_spi spi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];
120
spi_soft_pin_init(struct rt_soft_spi * soft_spi)121 static void spi_soft_pin_init(struct rt_soft_spi * soft_spi)
122 {
123 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)soft_spi->cfg;
124 rt_pin_mode(cfg->sck, PIN_MODE_OUTPUT);
125 rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
126 rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
127
128 rt_pin_write(cfg->miso, PIN_HIGH);
129 rt_pin_write(cfg->sck, PIN_HIGH);
130 rt_pin_write(cfg->mosi, PIN_HIGH);
131 }
132
133
spi_soft_tog_sclk(void * data)134 static void spi_soft_tog_sclk(void *data)
135 {
136 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
137 if(rt_pin_read(cfg->sck) == PIN_HIGH)
138 {
139 rt_pin_write(cfg->sck, PIN_LOW);
140 }
141 else
142 {
143 rt_pin_write(cfg->sck, PIN_HIGH);
144 }
145 }
146
spi_soft_set_sclk(void * data,rt_int32_t state)147 static void spi_soft_set_sclk(void *data, rt_int32_t state)
148 {
149 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
150 if (state)
151 {
152 rt_pin_write(cfg->sck, PIN_HIGH);
153 }
154 else
155 {
156 rt_pin_write(cfg->sck, PIN_LOW);
157 }
158 }
159
spi_soft_set_mosi(void * data,rt_int32_t state)160 static void spi_soft_set_mosi(void *data, rt_int32_t state)
161 {
162 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
163 if (state)
164 {
165 rt_pin_write(cfg->mosi, PIN_HIGH);
166 }
167 else
168 {
169 rt_pin_write(cfg->mosi, PIN_LOW);
170 }
171 }
172
spi_soft_set_miso(void * data,rt_int32_t state)173 static void spi_soft_set_miso(void *data, rt_int32_t state)
174 {
175 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
176 if (state)
177 {
178 rt_pin_write(cfg->miso, PIN_HIGH);
179 }
180 else
181 {
182 rt_pin_write(cfg->miso, PIN_LOW);
183 }
184 }
185
spi_soft_get_sclk(void * data)186 static rt_int32_t spi_soft_get_sclk(void *data)
187 {
188 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
189 return rt_pin_read(cfg->sck);
190 }
191
spi_soft_get_mosi(void * data)192 static rt_int32_t spi_soft_get_mosi(void *data)
193 {
194 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
195 return rt_pin_read(cfg->mosi);
196 }
197
spi_soft_get_miso(void * data)198 static rt_int32_t spi_soft_get_miso(void *data)
199 {
200 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
201 return rt_pin_read(cfg->miso);
202 }
203
spi_soft_dir_mosi(void * data,rt_int32_t state)204 static void spi_soft_dir_mosi(void *data, rt_int32_t state)
205 {
206 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
207 if (state)
208 {
209 rt_pin_mode(cfg->mosi, PIN_MODE_INPUT);
210 }
211 else
212 {
213 rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
214 }
215 }
216
spi_soft_dir_miso(void * data,rt_int32_t state)217 static void spi_soft_dir_miso(void *data, rt_int32_t state)
218 {
219 struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
220 if (state)
221 {
222 rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
223 }
224 else
225 {
226 rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT);
227 }
228 }
229
230 static struct rt_spi_bit_ops soft_spi_ops=
231 {
232 .data = RT_NULL,
233 .pin_init = RT_NULL,
234 .tog_sclk = spi_soft_tog_sclk,
235 .set_sclk = spi_soft_set_sclk,
236 .set_mosi = spi_soft_set_mosi,
237 .set_miso = spi_soft_set_miso,
238 .get_sclk = spi_soft_get_sclk,
239 .get_mosi = spi_soft_get_mosi,
240 .get_miso = spi_soft_get_miso,
241 .dir_mosi = spi_soft_dir_mosi,
242 .dir_miso = spi_soft_dir_miso,
243 .udelay = rt_hw_us_delay,
244 };
245
246 /* Soft SPI initialization function */
rt_soft_spi_init(void)247 int rt_soft_spi_init(void)
248 {
249 rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct rt_soft_spi);
250 rt_err_t result;
251
252 for (rt_size_t i = 0; i < obj_num; i++)
253 {
254 rt_memcpy(&spi_obj[i].ops, &soft_spi_ops, sizeof(struct rt_spi_bit_ops));
255 spi_obj[i].ops.data = (void *)&soft_spi_config[i];
256 spi_obj[i].spi.ops = &soft_spi_ops;
257 spi_obj[i].cfg = (void *)&soft_spi_config[i];
258 spi_soft_pin_init(&spi_obj[i]);
259 spi_obj[i].spi.ops->delay_us = soft_spi_config[i].timing_delay;
260 result = rt_spi_bit_add_bus(&spi_obj[i].spi, soft_spi_config[i].bus_name, &spi_obj[i].ops);
261 RT_ASSERT(result == RT_EOK);
262 }
263
264 return RT_EOK;
265 }
266 INIT_PREV_EXPORT(rt_soft_spi_init);
267
268 #endif /* RT_USING_SOFT_SPI */
269
270