Skip to content

Commit d8a7adc

Browse files
authored
Update drv_hw_i2c.c
1 parent 21790fd commit d8a7adc

File tree

1 file changed

+72
-38
lines changed

1 file changed

+72
-38
lines changed

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

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -95,36 +95,49 @@ static void gd32_i2c_irq_handler(struct gd32_i2c *i2c_obj)
9595
}
9696
}
9797
/* Master receiver logic */
98-
else if(i2c_flag_get(i2c_periph, I2C_FLAG_MASTER) && !i2c_flag_get(i2c_periph, I2C_FLAG_TR))
98+
else if(i2c_flag_get(i2c_periph, I2C_FLAG_MASTER) && !i2c_flag_get(i2c_periph, I2C_FLAG_TR))
99+
{
100+
/* Check if receive buffer is not empty */
101+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_RBNE))
99102
{
100-
/* Check if receive buffer is not empty */
101-
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_RBNE))
102-
{
103-
/* Special timing logic for N > 2 bytes, based on official GD32 example */
104-
if (i2c_obj->msg->len > 2 && (i2c_obj->msg->len - i2c_obj->count) == 3)
105-
{
106-
/* Wait for BTC to be set for byte N-2. This ensures N-2 is fully shifted
107-
out before we disable ACK for byte N-1. */
108-
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
109-
/* Disable ACK to send NACK after the next byte (N-1) is received */
110-
i2c_ack_config(i2c_periph, I2C_ACK_DISABLE);
103+
rt_uint32_t remaining = i2c_obj->msg->len - i2c_obj->count;
104+
105+
/* Handle ACK control for multi-byte reads */
106+
if (remaining > 3) {
107+
// For N > 3, ACK is enabled by default (set in xfer). Do nothing special here.
108+
} else if (remaining == 3) {
109+
rt_tick_t btc_timeout_ticks = (rt_tick_from_millisecond(10) > 1) ? rt_tick_from_millisecond(10) : 1;
110+
111+
/* Wait for BTC to be set for byte N-2. Timeout added for robustness. */
112+
rt_tick_t start_tick = rt_tick_get();
113+
while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC)) {
114+
if (rt_tick_get() - start_tick > btc_timeout_ticks) { // Arbitrary short timeout
115+
LOG_W("I2C BTC wait timeout (N-2).");
116+
i2c_obj->result = -RT_ETIMEOUT;
117+
i2c_stop_on_bus(i2c_periph); // Try to recover
118+
rt_completion_done(&i2c_obj->completion);
119+
return; // Exit ISR
120+
}
111121
}
122+
/* Disable ACK to send NACK after the next byte (N-1) is received */
123+
i2c_ack_config(i2c_periph, I2C_ACK_DISABLE);
124+
}
125+
/* Read the received data byte */
126+
i2c_obj->msg->buf[i2c_obj->count++] = i2c_data_receive(i2c_periph);
112127

113-
i2c_obj->msg->buf[i2c_obj->count++] = i2c_data_receive(i2c_periph);
128+
/* Check if this was the last byte */
129+
if (i2c_obj->count == i2c_obj->msg->len) {
130+
i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);
114131

115-
/* Check if this was the last byte */
116-
if (i2c_obj->count == i2c_obj->msg->len)
117-
{
118-
if (!(i2c_obj->msg->flags & RT_I2C_NO_STOP))
119-
{
120-
i2c_stop_on_bus(i2c_periph);
121-
}
122-
i2c_obj->result = RT_EOK;
123-
rt_completion_done(&i2c_obj->completion);
132+
if (!(i2c_obj->msg->flags & RT_I2C_NO_STOP)) {
133+
i2c_stop_on_bus(i2c_periph);
124134
}
135+
i2c_obj->result = RT_EOK;
136+
rt_completion_done(&i2c_obj->completion);
125137
}
126138
}
127139
}
140+
}
128141

129142
/**
130143
* @brief I2C error interrupt handler.
@@ -133,32 +146,53 @@ static void gd32_i2c_irq_handler(struct gd32_i2c *i2c_obj)
133146
static void gd32_i2c_err_irq_handler(struct gd32_i2c *i2c_obj)
134147
{
135148
uint32_t i2c_periph = i2c_obj->config->i2c_periph;
149+
i2c_obj->result = -RT_ERROR; // Default error
136150

137151
/* Acknowledge failure */
138-
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_AERR))
139-
{
152+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_AERR)) {
140153
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_AERR);
141-
i2c_obj->result = -RT_EIO;
142-
LOG_D("I2C NACK error.");
154+
i2c_obj->result = -RT_EIO; // More specific error
155+
LOG_D("I2C NACK/Acknowledge error (AERR).");
143156
}
144157
/* Bus error */
145-
else if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_BERR))
146-
{
158+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_BERR)) {
147159
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_BERR);
148160
i2c_obj->result = -RT_ERROR;
149-
LOG_E("I2C bus error.");
161+
LOG_E("I2C Bus error (BERR).");
150162
}
151-
/* Other errors should be handled as needed */
152-
else
153-
{
154-
if(i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_LOSTARB)) i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_LOSTARB);
155-
if(i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_OUERR)) i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_OUERR);
156-
i2c_obj->result = -RT_ERROR;
157-
LOG_E("I2C other error.");
163+
/* Arbitration lost */
164+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_LOSTARB)) {
165+
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_LOSTARB);
166+
i2c_obj->result = -RT_EBUSY; // Appropriate error?
167+
LOG_W("I2C Arbitration lost (LOSTARB).");
168+
}
169+
/* Overrun/Underrun */
170+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_OUERR)) {
171+
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_OUERR);
172+
i2c_obj->result = -RT_EIO; // Input/Output error?
173+
LOG_E("I2C Overrun/Underrun error (OUERR).");
174+
}
175+
/* SMBus related errors (if applicable) */
176+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_SMBALT)) {
177+
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_SMBALT);
178+
LOG_W("I2C SMBus Alert (SMBALT).");
179+
}
180+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_SMBTO)) {
181+
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_SMBTO);
182+
LOG_W("I2C SMBus Timeout (SMBTO).");
183+
}
184+
if (i2c_interrupt_flag_get(i2c_periph, I2C_INT_FLAG_PECERR)) {
185+
i2c_interrupt_flag_clear(i2c_periph, I2C_INT_FLAG_PECERR);
186+
LOG_W("I2C PEC Error (PECERR).");
158187
}
159188

160189
/* In case of error, always try to send a stop condition to release the bus */
161190
i2c_stop_on_bus(i2c_periph);
191+
/* Disable all I2C interrupts to prevent further interrupts from this error */
192+
i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
193+
i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
194+
i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
195+
162196
/* Wake up the waiting thread */
163197
rt_completion_done(&i2c_obj->completion);
164198
}
@@ -208,19 +242,19 @@ static rt_ssize_t gd32_i2c_master_xfer(struct rt_i2c_bus_device *bus, struct rt_
208242
}
209243

210244
/* Enable interrupts */
245+
i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
211246
i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
212247
i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
213-
i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
214248
/* Generate start condition */
215249
i2c_start_on_bus(i2c_periph);
216250

217251
/* Wait for transfer completion or timeout */
218252
ret = rt_completion_wait(&i2c_obj->completion, bus->timeout);
219253

220254
/* Disable interrupts after transfer is done or timed out */
255+
i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
221256
i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
222257
i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
223-
i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
224258

225259
/* Restore ACK and ACKPOS to default state for next transfer */
226260
i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);

0 commit comments

Comments
 (0)