1 /*
2 * Copyright (c) 2006-2022, Synwit Technology Co.,Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-05-31 ZYH first version
9 * 2018-12-10 Zohar_Lee format file
10 * 2020-07-10 lik rewrite
11 */
12
13 #include "drv_soft_i2c.h"
14
15 #ifdef RT_USING_I2C
16 #ifdef BSP_USING_I2C
17
18 /***************************************************************
19 *!!!!!!!!!!!!!!!!!!!!!!!!!!!!NOTICE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
20 *In order to use swm drv_soft_i2c,you need to commented out
21 line 114 (SDA_H(ops);) and line 167 (SDA_H(ops);) in i2c-bit-ops.c
22 At the same time, add one line (SDA_L(ops);)after line 154 (SCL_L(ops);)
23 in i2c-bit-ops.c
24 ***************************************************************/
25
26 //#define DRV_DEBUG
27 #define LOG_TAG "drv.i2c"
28 #include <drv_log.h>
29
30 #if !defined(BSP_USING_I2C0) && !defined(BSP_USING_I2C1)
31 #error "Please define at least one BSP_USING_I2Cx"
32 /* this driver can be disabled at menuconfig ? RT-Thread Components ? Device Drivers */
33 #endif
34
35 #ifdef BSP_USING_I2C0
36 #define I2C0_BUS_CFG \
37 { \
38 .scl = BSP_I2C0_SCL_PIN, \
39 .sda = BSP_I2C0_SDA_PIN, \
40 .name = "i2c0", \
41 }
42 #endif
43
44 #ifdef BSP_USING_I2C1
45 #define I2C1_BUS_CFG \
46 { \
47 .scl = BSP_I2C1_SCL_PIN, \
48 .sda = BSP_I2C1_SDA_PIN, \
49 .name = "i2c1", \
50 }
51 #endif
52
53 /* swm config class */
54 struct swm_soft_i2c_cfg
55 {
56 rt_uint8_t scl;
57 rt_uint8_t sda;
58 const char *name;
59 };
60 /* swm i2c dirver class */
61 struct swm_soft_i2c_device
62 {
63 struct rt_i2c_bit_ops ops;
64 struct rt_i2c_bus_device i2c_bus;
65 };
66 static const struct swm_soft_i2c_cfg swm_soft_i2c_cfg[] =
67 {
68 #ifdef BSP_USING_I2C0
69 I2C0_BUS_CFG,
70 #endif
71 #ifdef BSP_USING_I2C1
72 I2C1_BUS_CFG,
73 #endif
74 };
75
76 static struct swm_soft_i2c_device i2c_obj[sizeof(swm_soft_i2c_cfg) / sizeof(swm_soft_i2c_cfg[0])];
77
78 /**
79 * This function initializes the i2c pin.
80 *
81 * @param swm i2c dirver class.
82 */
swm_i2c_gpio_init(struct swm_soft_i2c_device * i2c)83 static void swm_i2c_gpio_init(struct swm_soft_i2c_device *i2c)
84 {
85 struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)i2c->ops.data;
86
87 rt_pin_mode(soft_i2c_cfg->scl, PIN_MODE_OUTPUT_OD);
88 rt_pin_mode(soft_i2c_cfg->sda, PIN_MODE_OUTPUT_OD);
89
90 rt_pin_write(soft_i2c_cfg->scl, PIN_HIGH);
91 rt_pin_write(soft_i2c_cfg->sda, PIN_HIGH);
92 }
93
swm_i2c_pin_init(void)94 static void swm_i2c_pin_init(void)
95 {
96 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct swm_soft_i2c_device);
97
98 for(rt_size_t i = 0; i < obj_num; i++)
99 {
100 swm_i2c_gpio_init(&i2c_obj[i]);
101 }
102 }
103
104 /**
105 * This function sets the sda pin.
106 *
107 * @param swm config class.
108 * @param The sda pin state.
109 */
swm_i2c_set_sda(void * data,rt_int32_t state)110 static void swm_i2c_set_sda(void *data, rt_int32_t state)
111 {
112 struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
113 rt_pin_mode(soft_i2c_cfg->sda, PIN_MODE_OUTPUT_OD);
114 if (state)
115 {
116 rt_pin_write(soft_i2c_cfg->sda, PIN_HIGH);
117 }
118 else
119 {
120 rt_pin_write(soft_i2c_cfg->sda, PIN_LOW);
121 }
122 }
123
124 /**
125 * This function sets the scl pin.
126 *
127 * @param swm config class.
128 * @param The scl pin state.
129 */
swm_i2c_set_scl(void * data,rt_int32_t state)130 static void swm_i2c_set_scl(void *data, rt_int32_t state)
131 {
132 struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
133 rt_pin_mode(soft_i2c_cfg->scl, PIN_MODE_OUTPUT_OD);
134 if (state)
135 {
136 rt_pin_write(soft_i2c_cfg->scl, PIN_HIGH);
137 }
138 else
139 {
140 rt_pin_write(soft_i2c_cfg->scl, PIN_LOW);
141 }
142 }
143
144 /**
145 * This function gets the sda pin state.
146 *
147 * @param The sda pin state.
148 */
swm_i2c_get_sda(void * data)149 static rt_int32_t swm_i2c_get_sda(void *data)
150 {
151 struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
152 rt_pin_mode(soft_i2c_cfg->sda, PIN_MODE_INPUT_PULLUP);
153 return rt_pin_read(soft_i2c_cfg->sda);
154 }
155
156 /**
157 * This function gets the scl pin state.
158 *
159 * @param The scl pin state.
160 */
swm_i2c_get_scl(void * data)161 static rt_int32_t swm_i2c_get_scl(void *data)
162 {
163 struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
164 rt_pin_mode(soft_i2c_cfg->scl, PIN_MODE_INPUT_PULLUP);
165 return rt_pin_read(soft_i2c_cfg->scl);
166 }
167
168 /**
169 * The time delay function.
170 *
171 * @param microseconds.
172 */
swm_i2c_udelay(rt_uint32_t us)173 static void swm_i2c_udelay(rt_uint32_t us)
174 {
175 rt_uint32_t ticks;
176 rt_uint32_t told, tnow, tcnt = 0;
177 rt_uint32_t reload = SysTick->LOAD;
178
179 ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
180 told = SysTick->VAL;
181 while (1)
182 {
183 tnow = SysTick->VAL;
184 if (tnow != told)
185 {
186 if (tnow < told)
187 {
188 tcnt += told - tnow;
189 }
190 else
191 {
192 tcnt += reload - tnow + told;
193 }
194 told = tnow;
195 if (tcnt >= ticks)
196 {
197 break;
198 }
199 }
200 }
201 }
202
203 static const struct rt_i2c_bit_ops swm_i2c_bit_ops =
204 {
205 .data = RT_NULL,
206 .pin_init = swm_i2c_pin_init,
207 .set_sda = swm_i2c_set_sda,
208 .set_scl = swm_i2c_set_scl,
209 .get_sda = swm_i2c_get_sda,
210 .get_scl = swm_i2c_get_scl,
211 .udelay = swm_i2c_udelay,
212 .delay_us = 1,
213 .timeout = 100,
214 .i2c_pin_init_flag = RT_FALSE
215 };
216
217 /* I2C initialization function */
swm_i2c_init(void)218 int swm_i2c_init(void)
219 {
220 rt_err_t result;
221
222 for (rt_size_t i = 0; i < sizeof(i2c_obj) / sizeof(struct swm_soft_i2c_device); i++)
223 {
224 i2c_obj[i].ops = swm_i2c_bit_ops;
225 i2c_obj[i].ops.data = (void *)&swm_soft_i2c_cfg[i];
226 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
227
228 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, swm_soft_i2c_cfg[i].name);
229 RT_ASSERT(result == RT_EOK);
230
231 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
232 swm_soft_i2c_cfg[i].name,
233 swm_soft_i2c_cfg[i].scl,
234 swm_soft_i2c_cfg[i].sda);
235 }
236
237 return RT_EOK;
238 }
239 INIT_DEVICE_EXPORT(swm_i2c_init);
240 #endif /* BSP_USING_I2C */
241 #endif /* RT_USING_I2C */
242