@@ -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)
133146static 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