@@ -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
9791static 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 */
9997static 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
114120static 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
126125static 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
147146static 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