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-30 sp-cai first version
9 */
10
11 #include <rtdevice.h>
12
13 #ifdef RT_USING_SOFT_I2C
14 #if !defined(RT_USING_SOFT_I2C0) &&\
15 !defined(RT_USING_SOFT_I2C1) && !defined(RT_USING_SOFT_I2C2) &&\
16 !defined(RT_USING_SOFT_I2C3) && !defined(RT_USING_SOFT_I2C4) &&\
17 !defined(RT_USING_SOFT_I2C5) && !defined(RT_USING_SOFT_I2C6) &&\
18 !defined(RT_USING_SOFT_I2C7) && !defined(RT_USING_SOFT_I2C8)
19 #error "Please define at least one RT_USING_SOFT_I2Cx"
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 "I2C_S"
28 #ifdef RT_I2C_BITOPS_DEBUG
29 #define DBG_LEVEL DBG_LOG
30 #endif
31 #include <rtdbg.h>
32
33 /* i2c config class */
34 struct soft_i2c_config
35 {
36 rt_base_t scl_pin;
37 rt_base_t sda_pin;
38 const char *bus_name;
39 rt_uint16_t timing_delay; /* scl and sda line delay */
40 rt_uint16_t timing_timeout; /* in tick */
41 };
42
43 /* i2c dirver class */
44 struct rt_soft_i2c
45 {
46 struct rt_i2c_bus_device i2c_bus;
47 struct rt_i2c_bit_ops ops;
48 };
49
50 struct soft_i2c_config i2c_cfg[] =
51 {
52 #ifdef RT_USING_SOFT_I2C0
53 {
54 .scl_pin = RT_SOFT_I2C0_SCL_PIN,
55 .sda_pin = RT_SOFT_I2C0_SDA_PIN,
56 .bus_name = RT_SOFT_I2C0_BUS_NAME,
57 .timing_delay = RT_SOFT_I2C0_TIMING_DELAY,
58 .timing_timeout = RT_SOFT_I2C0_TIMING_TIMEOUT,
59 },
60 #endif //RT_USING_SOFT_I2C0
61 #ifdef RT_USING_SOFT_I2C1
62 {
63 .scl_pin = RT_SOFT_I2C1_SCL_PIN,
64 .sda_pin = RT_SOFT_I2C1_SDA_PIN,
65 .bus_name = RT_SOFT_I2C1_BUS_NAME,
66 .timing_delay = RT_SOFT_I2C1_TIMING_DELAY,
67 .timing_timeout = RT_SOFT_I2C1_TIMING_TIMEOUT,
68 },
69 #endif //RT_USING_SOFT_I2C1
70 #ifdef RT_USING_SOFT_I2C2
71 {
72 .scl_pin = RT_SOFT_I2C2_SCL_PIN,
73 .sda_pin = RT_SOFT_I2C2_SDA_PIN,
74 .bus_name = RT_SOFT_I2C2_BUS_NAME,
75 .timing_delay = RT_SOFT_I2C2_TIMING_DELAY,
76 .timing_timeout = RT_SOFT_I2C2_TIMING_TIMEOUT,
77 },
78 #endif //RT_USING_SOFT_I2C2
79 #ifdef RT_USING_SOFT_I2C3
80 {
81 .scl_pin = RT_SOFT_I2C3_SCL_PIN,
82 .sda_pin = RT_SOFT_I2C3_SDA_PIN,
83 .bus_name = RT_SOFT_I2C3_BUS_NAME,
84 .timing_delay = RT_SOFT_I2C3_TIMING_DELAY,
85 .timing_timeout = RT_SOFT_I2C3_TIMING_TIMEOUT,
86 },
87 #endif //RT_USING_SOFT_I2C3
88 #ifdef RT_USING_SOFT_I2C4
89 {
90 .scl_pin = RT_SOFT_I2C4_SCL_PIN,
91 .sda_pin = RT_SOFT_I2C4_SDA_PIN,
92 .bus_name = RT_SOFT_I2C4_BUS_NAME,
93 .timing_delay = RT_SOFT_I2C4_TIMING_DELAY,
94 .timing_timeout = RT_SOFT_I2C4_TIMING_TIMEOUT,
95 },
96 #endif //RT_USING_SOFT_I2C4
97 #ifdef RT_USING_SOFT_I2C5
98 {
99 .scl_pin = RT_SOFT_I2C5_SCL_PIN,
100 .sda_pin = RT_SOFT_I2C5_SDA_PIN,
101 .bus_name = RT_SOFT_I2C5_BUS_NAME,
102 .timing_delay = RT_SOFT_I2C5_TIMING_DELAY,
103 .timing_timeout = RT_SOFT_I2C5_TIMING_TIMEOUT,
104 },
105 #endif //RT_USING_SOFT_I2C5
106 #ifdef RT_USING_SOFT_I2C6
107 {
108 .scl_pin = RT_SOFT_I2C6_SCL_PIN,
109 .sda_pin = RT_SOFT_I2C6_SDA_PIN,
110 .bus_name = RT_SOFT_I2C6_BUS_NAME,
111 .timing_delay = RT_SOFT_I2C6_TIMING_DELAY,
112 .timing_timeout = RT_SOFT_I2C6_TIMING_TIMEOUT,
113 },
114 #endif //RT_USING_SOFT_I2C6
115 #ifdef RT_USING_SOFT_I2C7
116 {
117 .scl_pin = RT_SOFT_I2C7_SCL_PIN,
118 .sda_pin = RT_SOFT_I2C7_SDA_PIN,
119 .bus_name = RT_SOFT_I2C7_BUS_NAME,
120 .timing_delay = RT_SOFT_I2C7_TIMING_DELAY,
121 .timing_timeout = RT_SOFT_I2C7_TIMING_TIMEOUT,
122 },
123 #endif //RT_USING_SOFT_I2C7
124 #ifdef RT_USING_SOFT_I2C8
125 {
126 .scl_pin = RT_SOFT_I2C8_SCL_PIN,
127 .sda_pin = RT_SOFT_I2C8_SDA_PIN,
128 .bus_name = RT_SOFT_I2C8_BUS_NAME,
129 .timing_delay = RT_SOFT_I2C8_TIMING_DELAY,
130 .timing_timeout = RT_SOFT_I2C8_TIMING_TIMEOUT,
131 },
132 #endif //RT_USING_SOFT_I2C8
133 };
134
135
136 static struct rt_soft_i2c i2c_bus_obj[sizeof(i2c_cfg) / sizeof(i2c_cfg[0])] =
137 { 0 };
138
139 /**
140 * This function initializes the i2c pin.
141 * @param i2c config class.
142 */
pin_init(const struct soft_i2c_config * cfg)143 static void pin_init(const struct soft_i2c_config *cfg)
144 {
145 rt_pin_mode(cfg->scl_pin, PIN_MODE_OUTPUT_OD);
146 rt_pin_mode(cfg->sda_pin, PIN_MODE_OUTPUT_OD);
147 rt_pin_write(cfg->scl_pin, PIN_HIGH);
148 rt_pin_write(cfg->sda_pin, PIN_HIGH);
149 }
150
151
152 /**
153 * This function sets the sda pin.
154 * @param i2c config class.
155 * @param The sda pin state.
156 */
set_sda(void * cfg,rt_int32_t value)157 static void set_sda(void *cfg, rt_int32_t value)
158 {
159 rt_pin_write(((const struct soft_i2c_config*)cfg)->sda_pin, value);
160 }
161
162 /**
163 * This function sets the scl pin.
164 * @param i2c config class.
165 * @param The sda pin state.
166 */
set_scl(void * cfg,rt_int32_t value)167 static void set_scl(void *cfg, rt_int32_t value)
168 {
169 rt_pin_write(((const struct soft_i2c_config*)cfg)->scl_pin, value);
170 }
171
172 /**
173 * This function gets the sda pin state.
174 * @param i2c config class.
175 */
get_sda(void * cfg)176 static rt_int32_t get_sda(void *cfg)
177 {
178 return rt_pin_read(((const struct soft_i2c_config*)cfg)->sda_pin);
179 }
180
181 /**
182 * This function gets the scl pin state.
183 * @param i2c config class.
184 */
get_scl(void * cfg)185 static rt_int32_t get_scl(void *cfg)
186 {
187 return rt_pin_read(((const struct soft_i2c_config*)cfg)->scl_pin);
188 }
189
190
191 static const struct rt_i2c_bit_ops soft_i2c_ops =
192 {
193 .set_sda = set_sda,
194 .set_scl = set_scl,
195 .get_sda = get_sda,
196 .get_scl = get_scl,
197 .udelay = rt_hw_us_delay,
198 };
199
200 /**
201 * if i2c is locked, this function will unlock it
202 *
203 * @param i2c config class.
204 *
205 * @return RT_EOK indicates successful unlock.
206 */
i2c_bus_unlock(const struct soft_i2c_config * cfg)207 static rt_err_t i2c_bus_unlock(const struct soft_i2c_config *cfg)
208 {
209 rt_ubase_t i = 0;
210
211 if(PIN_LOW == rt_pin_read(cfg->sda_pin))
212 {
213 while(i++ < 9)
214 {
215 rt_pin_write(cfg->scl_pin, PIN_HIGH);
216 rt_hw_us_delay(cfg->timing_delay);
217 rt_pin_write(cfg->scl_pin, PIN_LOW);
218 rt_hw_us_delay(cfg->timing_delay);
219 }
220 }
221 if(PIN_LOW == rt_pin_read(cfg->sda_pin))
222 {
223 return -RT_ERROR;
224 }
225
226 return RT_EOK;
227 }
228
229 /* I2C initialization function */
rt_soft_i2c_init(void)230 int rt_soft_i2c_init(void)
231 {
232 int err = RT_EOK;
233 struct rt_soft_i2c *obj;
234 int i;
235
236 for(i = 0; i < sizeof(i2c_bus_obj) / sizeof(i2c_bus_obj[0]); i++)
237 {
238 struct soft_i2c_config *cfg = &i2c_cfg[i];
239
240 pin_init(cfg);
241
242 obj = &i2c_bus_obj[i];
243 obj->ops = soft_i2c_ops;
244 obj->ops.data = cfg;
245 obj->i2c_bus.priv = &obj->ops;
246 obj->ops.delay_us = cfg->timing_delay;
247 obj->ops.timeout = cfg->timing_timeout;
248 if(rt_i2c_bit_add_bus(&obj->i2c_bus, cfg->bus_name) == RT_EOK)
249 {
250 i2c_bus_unlock(cfg);
251 LOG_D("Software simulation %s init done"
252 ", SCL pin: 0x%02X, SDA pin: 0x%02X"
253 , cfg->bus_name
254 , cfg->scl_pin
255 , cfg->sda_pin
256 );
257 }
258 else
259 {
260 err++;
261 LOG_E("Software simulation %s init fail"
262 ", SCL pin: 0x%02X, SDA pin: 0x%02X"
263 , cfg->bus_name
264 , cfg->scl_pin
265 , cfg->sda_pin
266 );
267 }
268 }
269
270 return err;
271 }
272 INIT_PREV_EXPORT(rt_soft_i2c_init);
273
274 #endif // RT_USING_SOFT_I2C
275