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 * 2020-01-09 shelton first version
9 */
10
11 #include <board.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) && !defined(BSP_USING_I2C3) && !defined(BSP_USING_I2C4)
20 #error "Please define at least one BSP_USING_I2Cx"
21 /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
22 #endif
23
24 static const struct n32_soft_i2c_config soft_i2c_config[] =
25 {
26 #ifdef BSP_USING_I2C1
27 I2C1_BUS_CONFIG,
28 #endif
29 #ifdef BSP_USING_I2C2
30 I2C2_BUS_CONFIG,
31 #endif
32 #ifdef BSP_USING_I2C3
33 I2C3_BUS_CONFIG,
34 #endif
35 #ifdef BSP_USING_I2C4
36 I2C4_BUS_CONFIG,
37 #endif
38 };
39
40 static struct n32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
41
42 /**
43 * This function initializes the i2c pin.
44 *
45 * @param n32 i2c dirver class.
46 */
n32_i2c_gpio_init(struct n32_i2c * i2c)47 static void n32_i2c_gpio_init(struct n32_i2c *i2c)
48 {
49 struct n32_soft_i2c_config *cfg = (struct n32_soft_i2c_config *)i2c->ops.data;
50
51 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
52 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
53
54 rt_pin_write(cfg->scl, PIN_HIGH);
55 rt_pin_write(cfg->sda, PIN_HIGH);
56 }
57
n32_i2c_pin_init(void)58 static void n32_i2c_pin_init(void)
59 {
60 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct n32_i2c);
61
62 for(rt_size_t i = 0; i < obj_num; i++)
63 {
64 n32_i2c_gpio_init(&i2c_obj[i]);
65 }
66 }
67
68 /**
69 * This function sets the sda pin.
70 *
71 * @param n32 config class.
72 * @param The sda pin state.
73 */
n32_set_sda(void * data,rt_int32_t state)74 static void n32_set_sda(void *data, rt_int32_t state)
75 {
76 struct n32_soft_i2c_config *cfg = (struct n32_soft_i2c_config *)data;
77 if (state)
78 {
79 rt_pin_write(cfg->sda, PIN_HIGH);
80 }
81 else
82 {
83 rt_pin_write(cfg->sda, PIN_LOW);
84 }
85 }
86
87 /**
88 * This function sets the scl pin.
89 *
90 * @param n32 config class.
91 * @param The scl pin state.
92 */
n32_set_scl(void * data,rt_int32_t state)93 static void n32_set_scl(void *data, rt_int32_t state)
94 {
95 struct n32_soft_i2c_config *cfg = (struct n32_soft_i2c_config *)data;
96 if (state)
97 {
98 rt_pin_write(cfg->scl, PIN_HIGH);
99 }
100 else
101 {
102 rt_pin_write(cfg->scl, PIN_LOW);
103 }
104 }
105
106 /**
107 * This function gets the sda pin state.
108 *
109 * @param The sda pin state.
110 */
n32_get_sda(void * data)111 static rt_int32_t n32_get_sda(void *data)
112 {
113 struct n32_soft_i2c_config *cfg = (struct n32_soft_i2c_config *)data;
114 return rt_pin_read(cfg->sda);
115 }
116
117 /**
118 * This function gets the scl pin state.
119 *
120 * @param The scl pin state.
121 */
n32_get_scl(void * data)122 static rt_int32_t n32_get_scl(void *data)
123 {
124 struct n32_soft_i2c_config *cfg = (struct n32_soft_i2c_config *)data;
125 return rt_pin_read(cfg->scl);
126 }
127 /**
128 * The time delay function.
129 *
130 * @param microseconds.
131 */
n32_udelay(rt_uint32_t us)132 static void n32_udelay(rt_uint32_t us)
133 {
134 rt_uint32_t ticks;
135 rt_uint32_t told, tnow, tcnt = 0;
136 rt_uint32_t reload = SysTick->LOAD;
137
138 ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
139 told = SysTick->VAL;
140 while (1)
141 {
142 tnow = SysTick->VAL;
143 if (tnow != told)
144 {
145 if (tnow < told)
146 {
147 tcnt += told - tnow;
148 }
149 else
150 {
151 tcnt += reload - tnow + told;
152 }
153 told = tnow;
154 if (tcnt >= ticks)
155 {
156 break;
157 }
158 }
159 }
160 }
161
162 static const struct rt_i2c_bit_ops n32_bit_ops_default =
163 {
164 .data = RT_NULL,
165 .pin_init = n32_i2c_pin_init,
166 .set_sda = n32_set_sda,
167 .set_scl = n32_set_scl,
168 .get_sda = n32_get_sda,
169 .get_scl = n32_get_scl,
170 .udelay = n32_udelay,
171 .delay_us = 1,
172 .timeout = 100,
173 .i2c_pin_init_flag = RT_FALSE
174 };
175
176 /**
177 * if i2c is locked, this function will unlock it
178 *
179 * @param n32 config class
180 *
181 * @return RT_EOK indicates successful unlock.
182 */
n32_i2c_bus_unlock(const struct n32_soft_i2c_config * cfg)183 static rt_err_t n32_i2c_bus_unlock(const struct n32_soft_i2c_config *cfg)
184 {
185 rt_int32_t i = 0;
186
187 if (PIN_LOW == rt_pin_read(cfg->sda))
188 {
189 while (i++ < 9)
190 {
191 rt_pin_write(cfg->scl, PIN_HIGH);
192 n32_udelay(100);
193 rt_pin_write(cfg->scl, PIN_LOW);
194 n32_udelay(100);
195 }
196 }
197 if (PIN_LOW == rt_pin_read(cfg->sda))
198 {
199 return -RT_ERROR;
200 }
201
202 return RT_EOK;
203 }
204
205 /* I2C initialization function */
rt_hw_i2c_init(void)206 int rt_hw_i2c_init(void)
207 {
208 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct n32_i2c);
209 rt_err_t result;
210
211 for (rt_size_t i = 0; i < obj_num; i++)
212 {
213 i2c_obj[i].ops = n32_bit_ops_default;
214 i2c_obj[i].ops.data = (void *)&soft_i2c_config[i];
215 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
216
217 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
218 RT_ASSERT(result == RT_EOK);
219 n32_i2c_bus_unlock(&soft_i2c_config[i]);
220
221 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
222 soft_i2c_config[i].bus_name,
223 soft_i2c_config[i].scl,
224 soft_i2c_config[i].sda);
225 }
226
227 return RT_EOK;
228 }
229 INIT_BOARD_EXPORT(rt_hw_i2c_init);
230
231 #endif /* RT_USING_I2C */
232