1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-05-16 shelton first version
9 */
10
11 #include "drv_common.h"
12 #include "drv_soft_i2c.h"
13
14 #ifdef RT_USING_I2C
15
16 #define LOG_TAG "drv.i2c"
17 #include <drv_log.h>
18
19 #if !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && \
20 !defined(BSP_USING_I2C3)
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 static const struct at32_soft_i2c_config soft_i2c_config[] =
26 {
27 #ifdef BSP_USING_I2C1
28 I2C1_BUS_CONFIG,
29 #endif
30 #ifdef BSP_USING_I2C2
31 I2C2_BUS_CONFIG,
32 #endif
33 #ifdef BSP_USING_I2C3
34 I2C3_BUS_CONFIG,
35 #endif
36 };
37
38 static struct at32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
39
40 /**
41 * this function initializes the i2c pin.
42 *
43 * @param at32 i2c dirver class.
44 */
at32_i2c_gpio_init(struct at32_i2c * i2c)45 static void at32_i2c_gpio_init(struct at32_i2c *i2c)
46 {
47 struct at32_soft_i2c_config* cfg = (struct at32_soft_i2c_config*)i2c->ops.data;
48
49 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
50 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
51
52 rt_pin_write(cfg->scl, PIN_HIGH);
53 rt_pin_write(cfg->sda, PIN_HIGH);
54 }
55
at32_i2c_pin_init(void)56 static void at32_i2c_pin_init(void)
57 {
58 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct at32_i2c);
59
60 for(rt_size_t i = 0; i < obj_num; i++)
61 {
62 at32_i2c_gpio_init(&i2c_obj[i]);
63 }
64 }
65
66 /**
67 * this function sets the sda pin.
68 *
69 * @param at32 config class.
70 * @param the sda pin state.
71 */
at32_set_sda(void * data,rt_int32_t state)72 static void at32_set_sda(void *data, rt_int32_t state)
73 {
74 struct at32_soft_i2c_config* cfg = (struct at32_soft_i2c_config*)data;
75 if (state)
76 {
77 rt_pin_write(cfg->sda, PIN_HIGH);
78 }
79 else
80 {
81 rt_pin_write(cfg->sda, PIN_LOW);
82 }
83 }
84
85 /**
86 * this function sets the scl pin.
87 *
88 * @param at32 config class.
89 * @param the scl pin state.
90 */
at32_set_scl(void * data,rt_int32_t state)91 static void at32_set_scl(void *data, rt_int32_t state)
92 {
93 struct at32_soft_i2c_config* cfg = (struct at32_soft_i2c_config*)data;
94 if (state)
95 {
96 rt_pin_write(cfg->scl, PIN_HIGH);
97 }
98 else
99 {
100 rt_pin_write(cfg->scl, PIN_LOW);
101 }
102 }
103
104 /**
105 * this function gets the sda pin state.
106 *
107 * @param the sda pin state.
108 */
at32_get_sda(void * data)109 static rt_int32_t at32_get_sda(void *data)
110 {
111 struct at32_soft_i2c_config* cfg = (struct at32_soft_i2c_config*)data;
112 return rt_pin_read(cfg->sda);
113 }
114
115 /**
116 * this function gets the scl pin state.
117 *
118 * @param the scl pin state.
119 */
at32_get_scl(void * data)120 static rt_int32_t at32_get_scl(void *data)
121 {
122 struct at32_soft_i2c_config* cfg = (struct at32_soft_i2c_config*)data;
123 return rt_pin_read(cfg->scl);
124 }
125
126 /**
127 * the time delay function.
128 *
129 * @param microseconds.
130 */
at32_udelay(rt_uint32_t us)131 static void at32_udelay(rt_uint32_t us)
132 {
133 rt_uint32_t ticks;
134 rt_uint32_t told, tnow, tcnt = 0;
135 rt_uint32_t reload = SysTick->LOAD;
136
137 ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
138 told = SysTick->VAL;
139 while (1)
140 {
141 tnow = SysTick->VAL;
142 if (tnow != told)
143 {
144 if (tnow < told)
145 {
146 tcnt += told - tnow;
147 }
148 else
149 {
150 tcnt += reload - tnow + told;
151 }
152 told = tnow;
153 if (tcnt >= ticks)
154 {
155 break;
156 }
157 }
158 }
159 }
160
161 static const struct rt_i2c_bit_ops at32_bit_ops_default =
162 {
163 .data = RT_NULL,
164 .pin_init = at32_i2c_pin_init,
165 .set_sda = at32_set_sda,
166 .set_scl = at32_set_scl,
167 .get_sda = at32_get_sda,
168 .get_scl = at32_get_scl,
169 .udelay = at32_udelay,
170 .delay_us = 1,
171 .timeout = 100,
172 .i2c_pin_init_flag = RT_FALSE
173 };
174
175 /**
176 * if i2c is locked, this function will unlock it
177 *
178 * @param at32 config class
179 *
180 * @return RT_EOK indicates successful unlock.
181 */
at32_i2c_bus_unlock(const struct at32_soft_i2c_config * cfg)182 static rt_err_t at32_i2c_bus_unlock(const struct at32_soft_i2c_config *cfg)
183 {
184 rt_int32_t i = 0;
185
186 if (PIN_LOW == rt_pin_read(cfg->sda))
187 {
188 while (i++ < 9)
189 {
190 rt_pin_write(cfg->scl, PIN_HIGH);
191 at32_udelay(100);
192 rt_pin_write(cfg->scl, PIN_LOW);
193 at32_udelay(100);
194 }
195 }
196 if (PIN_LOW == rt_pin_read(cfg->sda))
197 {
198 return -RT_ERROR;
199 }
200
201 return RT_EOK;
202 }
203
204 /* i2c initialization function */
rt_hw_i2c_init(void)205 int rt_hw_i2c_init(void)
206 {
207 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct at32_i2c);
208 rt_err_t result;
209
210 for (rt_size_t i = 0; i < obj_num; i++)
211 {
212 i2c_obj[i].ops = at32_bit_ops_default;
213 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
214 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
215
216 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
217 RT_ASSERT(result == RT_EOK);
218 at32_i2c_bus_unlock(&soft_i2c_config[i]);
219
220 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
221 soft_i2c_config[i].bus_name,
222 soft_i2c_config[i].scl,
223 soft_i2c_config[i].sda);
224 }
225
226 return RT_EOK;
227 }
228
229 INIT_BOARD_EXPORT(rt_hw_i2c_init);
230
231 #endif /* RT_USING_I2C */
232