This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 5994c940bc7 arch/risc-v/gd32vw55x: fix the I2C recovery after a NACK
5994c940bc7 is described below

commit 5994c940bc7fbb0410962cf613ac3741cf65ce53
Author: Jorge Guzman <[email protected]>
AuthorDate: Fri Oct 23 21:40:22 2026 -0300

    arch/risc-v/gd32vw55x: fix the I2C recovery after a NACK
    
    On a NACK the driver requested the STOP condition and completed the
    transfer at once, leaving in TDATA the byte that was already loaded for
    the slave.  That byte was then sent at the start of the next transfer,
    which corrupted it, and the next transfer could also start while the
    STOP was still pending.
    
    Flush TDATA (write TBE) and complete the transfer only when the STOP
    is detected (STPDET), as the GigaDevice firmware library does.  The
    GD32W51x driver already does the same.  A NACK is a normal event while
    probing the bus, so it is now logged with i2cinfo.
    
    Also fix the indentation of the switch in gd32_i2cbus_initialize()
    reported by nxstyle.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Jorge Guzman <[email protected]>
---
 arch/risc-v/src/gd32vw55x/gd32vw55x_i2c.c | 61 +++++++++++++++++++++++--------
 1 file changed, 45 insertions(+), 16 deletions(-)

diff --git a/arch/risc-v/src/gd32vw55x/gd32vw55x_i2c.c 
b/arch/risc-v/src/gd32vw55x/gd32vw55x_i2c.c
index 20cb186f636..b3862290356 100644
--- a/arch/risc-v/src/gd32vw55x/gd32vw55x_i2c.c
+++ b/arch/risc-v/src/gd32vw55x/gd32vw55x_i2c.c
@@ -736,17 +736,46 @@ static int gd32_i2c_isr_process(struct gd32_i2c_priv_s 
*priv)
     {
       gd32_i2c_putreg(priv, GD32VW55X_I2C_STATC_OFFSET, I2C_STATC_NACKC);
 
-      i2cerr("ERROR: NACK, addr=0x%02x\n", priv->msgv[priv->msgid].addr);
+      i2cinfo("NACK, addr=0x%02x\n", priv->msgv[priv->msgid].addr);
 
-      /* Request the STOP condition.  If the automatic end mode is active
-       * the hardware has already sent it, in which case this bit is
-       * ignored.
+      /* Flush the byte that may be left in TDATA, otherwise it would be
+       * sent at the start of the next transfer.
        */
 
-      gd32_i2c_modifyreg(priv, GD32VW55X_I2C_CTL1_OFFSET,
-                         I2C_CTL1_STOP, 0);
+      gd32_i2c_modifyreg(priv, GD32VW55X_I2C_STAT_OFFSET, 0, I2C_STAT_TBE);
+
+      /* Request the STOP condition and complete the transfer only once it
+       * is on the bus: starting the next transfer before that leaves the
+       * bus busy.  If the automatic end mode is active the hardware has
+       * already sent it, in which case this bit is ignored.
+       */
+
+      priv->result = -ENXIO;
+      priv->dcnt   = 0;
+
+      if ((status & I2C_STAT_STPDET) == 0)
+        {
+          gd32_i2c_modifyreg(priv, GD32VW55X_I2C_CTL1_OFFSET,
+                             I2C_CTL1_STOP, 0);
+          return OK;
+        }
+
+      gd32_i2c_putreg(priv, GD32VW55X_I2C_STATC_OFFSET, I2C_STATC_STPDETC);
+      gd32_i2c_finish(priv, priv->result);
+      return OK;
+    }
+
+  /* A NACK has been handled: only wait for the STOP condition */
+
+  if (priv->result == -ENXIO)
+    {
+      if ((status & I2C_STAT_STPDET) != 0)
+        {
+          gd32_i2c_putreg(priv, GD32VW55X_I2C_STATC_OFFSET,
+                          I2C_STATC_STPDETC);
+          gd32_i2c_finish(priv, priv->result);
+        }
 
-      gd32_i2c_finish(priv, -ENXIO);
       return OK;
     }
 
@@ -1241,18 +1270,18 @@ struct i2c_master_s *gd32_i2cbus_initialize(int port)
   switch (port)
     {
 #ifdef CONFIG_GD32VW55X_I2C0
-    case 0:
-      priv = &g_i2c0_priv;
-      break;
+      case 0:
+        priv = &g_i2c0_priv;
+        break;
 #endif
 #ifdef CONFIG_GD32VW55X_I2C1
-    case 1:
-      priv = &g_i2c1_priv;
-      break;
+      case 1:
+        priv = &g_i2c1_priv;
+        break;
 #endif
-    default:
-      i2cerr("ERROR: Unsupported I2C port: %d\n", port);
-      return NULL;
+      default:
+        i2cerr("ERROR: Unsupported I2C port: %d\n", port);
+        return NULL;
     }
 
   /* Initialize the private data of the device, if it has not been done */

Reply via email to