Skip to content

Commit d748c84

Browse files
committed
init main
1 parent a81f8cf commit d748c84

File tree

1 file changed

+194
-16
lines changed

1 file changed

+194
-16
lines changed

bsp/gd32/arm/libraries/gd32_drivers/drv_hw_i2c.c

Lines changed: 194 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,7 @@ struct gd32_i2c
4545
struct rt_i2c_bus_device parent;
4646
const struct gd32_i2c_config *config;
4747

48-
/* Interrupt-driven transfer context */
49-
struct rt_i2c_msg *msg;
50-
volatile rt_size_t count;
51-
volatile rt_err_t result;
52-
struct rt_completion completion;
53-
54-
struct rt_completion bus_mutex;
48+
struct rt_mutex bus_mutex;
5549
struct rt_completion sync_sem;
5650
uint32_t dev_config;
5751
uint16_t addr1;
@@ -96,6 +90,10 @@ static const struct gd32_i2c_config i2c_configs[] =
9690

9791
static struct gd32_i2c i2c_objs[sizeof(i2c_configs) / sizeof(i2c_configs[0])];
9892

93+
#define I2C_GD32_ERR_BERR (1U << 0) /* Bus error */
94+
#define I2C_GD32_ERR_LARB (1U << 1) /* Arbitration lost */
95+
#define I2C_GD32_ERR_AERR (1U << 2) /* No ACK received */
96+
#define I2C_GD32_ERR_BUSY (1U << 4) /* I2C bus busy */
9997
static inline void i2c_enable_interrupts(uint32_t i2c_periph)
10098
{
10199
i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
@@ -110,17 +108,18 @@ static inline void i2c_disable_interrupts(uint32_t i2c_periph)
110108
i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
111109
}
112110

111+
static inline void i2c_log_error(struct gd32_i2c *i2c_dev)
112+
{
113+
if (i2c_dev->errs & I2C_GD32_ERR_BERR) LOG_E("Bus error");
114+
if (i2c_dev->errs & I2C_GD32_ERR_LARB) LOG_E("Arbitration lost");
115+
if (i2c_dev->errs & I2C_GD32_ERR_AERR) LOG_E("No ACK received");
116+
if (i2c_dev->errs & I2C_GD32_ERR_BUSY) LOG_E("I2C bus is busy");
117+
}
118+
113119

114120
static inline void i2c_xfer_read(struct gd32_i2c *i2c_obj)
115121
{
116-
i2c_obj->current->len--;
117-
*i2c_obj->current->buf = I2C_DATA(i2c_obj->config->i2c_periph);
118-
i2c_obj->current->buf++;
119-
120-
if ((i2c_obj->xfer_len > 0U) &&
121-
(i2c_obj->current->len == 0U)) {
122-
i2c_obj->current++;
123-
}
122+
124123
}
125124

126125
static inline void i2c_xfer_write(struct gd32_i2c *i2c_obj)
@@ -146,7 +145,179 @@ static rt_err_t i2c_xfer_begin(struct gd32_i2c *i2c_obj)
146145

147146
static rt_ssize_t gd32_i2c_master_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
148147
{
149-
return num;
148+
struct gd32_i2c *i2c_dev;
149+
const struct gd32_i2c_config *cfg;
150+
rt_ssize_t i, itr;
151+
rt_err_t result = RT_EOK;
152+
153+
RT_ASSERT(bus != RT_NULL);
154+
RT_ASSERT(msgs != RT_NULL);
155+
RT_ASSERT(num > 0);
156+
157+
i2c_dev = rt_container_of(bus, struct gd32_i2c, parent);
158+
cfg = i2c_dev->config;
159+
160+
/* 1. 消息序列验证 (参考 Zephyr i2c_gd32_transfer 中的验证逻辑) */
161+
for (i = 0; i < num; i++)
162+
{
163+
/* 中间的消息不能带有 STOP 标志 */
164+
if ((i < num - 1) && !(msgs[i].flags & RT_I2C_NO_STOP))
165+
{
166+
LOG_E("Only the last message can have a STOP signal");
167+
return -RT_EINVAL;
168+
}
169+
if (msgs[i].len == 0 || msgs[i].buf == RT_NULL)
170+
{
171+
LOG_E("Invalid message buffer or length at index %d", i);
172+
return -RT_EINVAL;
173+
}
174+
}
175+
176+
/* 2. 获取互斥锁 */
177+
rt_mutex_take(&i2c_dev->bus_mutex, RT_WAITING_FOREVER);
178+
179+
/* 3. 使能 I2C 外设 */
180+
I2C_CTL0(cfg->i2c_periph) |= I2C_CTL0_I2CEN;
181+
182+
/* 4. 核心传输循环 (严格参考 Zephyr 的消息合并逻辑) */
183+
for (i = 0; i < num; i = itr)
184+
{
185+
i2c_dev->current = &msgs[i];
186+
i2c_dev->xfer_len = msgs[i].len;
187+
rt_uint16_t current_addr = i2c_dev->current->addr;
188+
189+
/*
190+
* Zephyr 驱动的一个关键特性:合并连续的、相同方向的传输。
191+
* 这可以减少 START/STOP 开销,形成一个更长的读或写事务。
192+
*/
193+
for (itr = i + 1; itr < num; itr++)
194+
{
195+
/* 如果读写方向改变,则停止合并 */
196+
if ((msgs[itr].flags & RT_I2C_RD) != (i2c_dev->current->flags & RT_I2C_RD))
197+
{
198+
break;
199+
}
200+
/* 如果地址改变,也停止合并 */
201+
if (msgs[itr].addr != current_addr)
202+
{
203+
break;
204+
}
205+
i2c_dev->xfer_len += msgs[itr].len;
206+
}
207+
208+
/* 检查总线是否繁忙 (只在事务开始时检查) */
209+
if (I2C_STAT1(cfg->i2c_periph) & I2C_STAT1_I2CBSY)
210+
{
211+
i2c_dev->errs = I2C_GD32_ERR_BUSY;
212+
result = -RT_EBUSY;
213+
break; /* 退出 for 循环 */
214+
}
215+
216+
/* 准备地址 */
217+
if (i2c_dev->current->flags & RT_I2C_ADDR_10BIT)
218+
{
219+
i2c_dev->addr1 = 0xF0 | ((current_addr >> 8) & 0x03);
220+
i2c_dev->addr2 = current_addr & 0xFF;
221+
}
222+
else
223+
{
224+
i2c_dev->addr1 = current_addr & 0x7F;
225+
}
226+
227+
/* 重置状态 */
228+
i2c_dev->errs = 0;
229+
i2c_dev->is_restart = RT_FALSE;
230+
rt_completion_init(&i2c_dev->sync_sem);
231+
232+
/*
233+
* 启动传输事务 (逻辑等同于 Zephyr 的 i2c_gd32_xfer_begin)
234+
*/
235+
I2C_CTL0(cfg->i2c_periph) |= I2C_CTL0_ACKEN; // 默认使能ACK
236+
237+
/* 10位读操作的特殊处理 */
238+
if ((i2c_dev->current->flags & RT_I2C_RD) && (i2c_dev->current->flags & RT_I2C_ADDR_10BIT))
239+
{
240+
i2c_dev->is_restart = RT_TRUE;
241+
i2c_dev->current->flags &= ~RT_I2C_RD; // 临时改为写,发送地址头
242+
}
243+
244+
/* 读2字节的特殊处理 */
245+
if ((i2c_dev->current->flags & RT_I2C_RD) && (i2c_dev->xfer_len == 2))
246+
{
247+
I2C_CTL0(cfg->i2c_periph) |= I2C_CTL0_POAP;
248+
}
249+
250+
i2c_enable_interrupts(cfg->i2c_periph);
251+
I2C_CTL0(cfg->i2c_periph) |= I2C_CTL0_START;
252+
253+
/* 等待中断完成 */
254+
result = rt_completion_wait(&i2c_dev->sync_sem, bus->timeout);
255+
256+
/* 恢复临时修改的标志 */
257+
if (i2c_dev->is_restart == RT_TRUE)
258+
{
259+
i2c_dev->current->flags |= RT_I2C_RD;
260+
}
261+
262+
/* 清理 */
263+
I2C_CTL0(cfg->i2c_periph) &= ~I2C_CTL0_POAP;
264+
i2c_disable_interrupts(cfg->i2c_periph);
265+
266+
/*
267+
* 检查结果 (逻辑等同于 Zephyr 的 i2c_gd32_xfer_end)
268+
*/
269+
if (result != RT_EOK) /* 超时 */
270+
{
271+
LOG_E("I2C transaction timeout!");
272+
result = -RT_ETIMEOUT;
273+
I2C_CTL0(cfg->i2c_periph) |= I2C_CTL0_STOP; /* 尝试恢复总线 */
274+
break; /* 退出 for 循环 */
275+
}
276+
if (i2c_dev->errs != 0) /* ISR 报告的硬件错误 */
277+
{
278+
i2c_log_error(i2c_dev);
279+
result = -RT_EIO;
280+
/* ISR中已产生STOP,此处无需再发 */
281+
break; /* 退出 for 循环 */
282+
}
283+
}
284+
285+
/* 如果循环正常结束 (没有break),则表示所有事务都成功了 */
286+
if (result == RT_EOK)
287+
{
288+
/*
289+
* 处理 STOP 条件:仅在最后一个消息且没有NO_STOP标志时发送。
290+
* 此时 i 应该等于 num。
291+
*/
292+
if (!(msgs[num - 1].flags & RT_I2C_NO_STOP))
293+
{
294+
I2C_CTL0(cfg->i2c_periph) |= I2C_CTL0_STOP;
295+
/* 短暂等待总线释放 */
296+
rt_uint32_t timeout = 1000;
297+
while(I2C_STAT1(cfg->i2c_periph) & I2C_STAT1_I2CBSY && timeout--)
298+
{
299+
rt_hw_us_delay(1);
300+
}
301+
}
302+
}
303+
304+
/* 5. 关闭 I2C 外设 */
305+
I2C_CTL0(cfg->i2c_periph) &= ~I2C_CTL0_I2CEN;
306+
307+
/* 6. 释放互斥锁 */
308+
rt_mutex_release(&i2c_dev->bus_mutex);
309+
310+
/* 7. 返回结果 */
311+
if (result == RT_EOK)
312+
{
313+
/* 成功,返回处理的消息数 */
314+
return i;
315+
}
316+
else
317+
{
318+
/* 失败,返回错误码 */
319+
return result;
320+
}
150321
}
151322

152323
#if defined(BSP_USING_HW_I2C0)
@@ -250,6 +421,13 @@ int rt_hw_i2c_init(void)
250421
LOG_E("Failed to register i2c bus %s", config->device_name);
251422
return result;
252423
}
424+
425+
rt_mutex_init(&i2c_obj->bus_mutex,
426+
config->device_name,
427+
RT_IPC_FLAG_FIFO);
428+
429+
rt_completion_init(&i2c_obj->sync_sem);
430+
253431
LOG_I("I2C bus %s registered successfully.", config->device_name);
254432
}
255433
return RT_EOK;

0 commit comments

Comments
 (0)