1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-05-29 QT-one first version
9 */
10 #include <rtdbg.h>
11 #include "drv_soft_i2c.h"
12
13 #ifdef RT_USING_I2C
14 #if !defined(BSP_USING_I2C0_SW) && !defined(BSP_USING_I2C1_SW) && !defined(BSP_USING_I2C2_SW)
15 #error "Please define at least one BSP_USING_I2Cx_SW"
16 /* this driver can be disabled at menuconfig RT-Thread Components Device Drivers */
17 #endif
18
19 /* ht32 software i2c config class */
20 struct ht32_soft_i2c_config
21 {
22 rt_uint8_t scl;
23 rt_uint8_t sda;
24 const char *bus_name;
25 };
26 /* ht32 software i2c dirver class */
27 struct ht32_soft_i2c
28 {
29 struct rt_i2c_bit_ops ops;
30 struct rt_i2c_bus_device i2c_bus;
31 };
32
33 static rt_uint8_t scl_rw_flag = 0;
34 static rt_uint8_t sda_rw_flag = 0;
35
36 static const struct ht32_soft_i2c_config soft_i2c_config[] =
37 {
38 #ifdef BSP_USING_I2C0_SW
39 {
40 .scl = BSP_I2C0_SLC_PIN,
41 .sda = BSP_I2C0_SDA_PIN,
42 .bus_name = BSP_USING_I2C0_SW_NAME,
43 },
44 #endif
45 #ifdef BSP_USING_I2C1_SW
46 {
47 .scl = BSP_I2C1_SLC_PIN,
48 .sda = BSP_I2C1_SDA_PIN,
49 .bus_name = BSP_USING_I2C1_SW_NAME,
50 },
51 #endif
52 #ifdef BSP_USING_I2C2_SW
53 {
54 .scl = BSP_I2C2_SLC_PIN,
55 .sda = BSP_I2C2_SDA_PIN,
56 .bus_name = BSP_USING_I2C2_SW_NAME,
57 },
58 #endif
59 };
60
61 static struct ht32_soft_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
62
63 /* this function initializes the software i2c pin */
ht32_soft_i2c_gpio_init(struct ht32_soft_i2c * i2c)64 static void ht32_soft_i2c_gpio_init(struct ht32_soft_i2c *i2c)
65 {
66 struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)i2c->ops.data;
67
68 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
69 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
70
71 rt_pin_write(cfg->scl, PIN_HIGH);
72 rt_pin_write(cfg->sda, PIN_HIGH);
73 }
74 /* this function sets the sda pin */
ht32_set_sda(void * data,rt_int32_t state)75 void ht32_set_sda(void *data, rt_int32_t state)
76 {
77 struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
78 if(sda_rw_flag != 0)
79 {
80 sda_rw_flag = 0;
81 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
82 }
83 if (state)
84 {
85 rt_pin_write(cfg->sda, PIN_HIGH);
86 }
87 else
88 {
89 rt_pin_write(cfg->sda, PIN_LOW);
90 }
91 }
92 /* this function sets the scl pin */
ht32_set_scl(void * data,rt_int32_t state)93 void ht32_set_scl(void *data, rt_int32_t state)
94 {
95 struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
96 if(scl_rw_flag != 0)
97 {
98 scl_rw_flag = 0;
99 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
100 }
101 if (state)
102 {
103 rt_pin_write(cfg->scl, PIN_HIGH);
104 }
105 else
106 {
107 rt_pin_write(cfg->scl, PIN_LOW);
108 }
109 }
110 /* this function gets the sda pin state */
ht32_get_sda(void * data)111 rt_int32_t ht32_get_sda(void *data)
112 {
113 struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
114
115 if(sda_rw_flag == 0)
116 {
117 sda_rw_flag = 1;
118 rt_pin_mode(cfg->sda, PIN_MODE_INPUT);
119 }
120 return rt_pin_read(cfg->sda);
121 }
122 /* this function gets the scl pin state */
ht32_get_scl(void * data)123 rt_int32_t ht32_get_scl(void *data)
124 {
125 struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
126 if(scl_rw_flag == 0)
127 {
128 scl_rw_flag = 1;
129 rt_pin_mode(cfg->scl, PIN_MODE_INPUT);
130 }
131 return rt_pin_read(cfg->scl);
132 }
133
ht32_udelay(rt_uint32_t us)134 void ht32_udelay(rt_uint32_t us)
135 {
136 rt_uint32_t ticks;
137 rt_uint32_t told, tnow, tcnt = 0;
138 rt_uint32_t reload = SysTick->LOAD;
139
140 ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
141 told = SysTick->VAL;
142 while (1)
143 {
144 tnow = SysTick->VAL;
145 if (tnow != told)
146 {
147 if (tnow < told)
148 {
149 tcnt += told - tnow;
150 }
151 else
152 {
153 tcnt += reload - tnow + told;
154 }
155 told = tnow;
156 if (tcnt >= ticks)
157 {
158 break;
159 }
160 }
161 }
162 }
163
164 static const struct rt_i2c_bit_ops ht32_bit_ops_default =
165 {
166 .data = RT_NULL,
167 .set_sda = ht32_set_sda,
168 .set_scl = ht32_set_scl,
169 .get_sda = ht32_get_sda,
170 .get_scl = ht32_get_scl,
171 .udelay = ht32_udelay,
172 .delay_us = 1,
173 .timeout = 100
174 };
175
176 /* if i2c is locked, this function will unlock it */
ht32_soft_i2c_bus_unlock(const struct ht32_soft_i2c_config * cfg)177 static rt_err_t ht32_soft_i2c_bus_unlock(const struct ht32_soft_i2c_config *cfg)
178 {
179 rt_int32_t i = 0;
180 rt_pin_mode(cfg->sda, PIN_MODE_INPUT_PULLUP);
181 if (PIN_LOW == rt_pin_read(cfg->sda))
182 {
183 while (i++ < 9)
184 {
185 rt_pin_write(cfg->scl, PIN_HIGH);
186 ht32_udelay(100);
187 rt_pin_write(cfg->scl, PIN_LOW);
188 ht32_udelay(100);
189 }
190 }
191 if (PIN_LOW == rt_pin_read(cfg->sda))
192 {
193 return -RT_ERROR;
194 }
195 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
196 return RT_EOK;
197 }
198
199 /* i2c initialization function */
rt_sw_i2c_init(void)200 int rt_sw_i2c_init(void)
201 {
202 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct ht32_soft_i2c);
203 rt_err_t result;
204
205 for (int i = 0; i < obj_num; i++)
206 {
207 i2c_obj[i].ops = ht32_bit_ops_default;
208 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
209 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
210 ht32_soft_i2c_gpio_init(&i2c_obj[i]);
211
212 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
213
214 RT_ASSERT(result == RT_EOK);
215 ht32_soft_i2c_bus_unlock(&soft_i2c_config[i]);
216
217 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
218 soft_i2c_config[i].bus_name,
219 soft_i2c_config[i].scl,
220 soft_i2c_config[i].sda);
221 }
222 return result;
223 }
224
225 INIT_BOARD_EXPORT(rt_sw_i2c_init);
226
227
228 #endif /* RT_USING_I2C */
229