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