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

commit 9729bfe3082c4b9414e47173f5b0775068ee57c8
Author: Max Kriegleder <[email protected]>
AuthorDate: Mon Oct 26 20:58:50 2026 +0100

    arch/arm/nrf91: Use a repeated START for an I2C register read.
    
    nrf91_i2c.c is the nRF52 TWIM driver with more instances and ignores
    I2C_M_NOSTOP the same way: a register read (a write with I2C_M_NOSTOP
    followed by a read from the same address) went out as two transactions,
    STOP and START, where many devices require a repeated START. Apply the
    nRF52 change: such a pair runs as one TWIM transfer (LASTTX -> STARTRX,
    LASTRX -> STOP) completing on a single STOPPED event. Also indent the
    frequency switch's case labels as on the nRF52 (whitespace only).
    
    Tested on an nRF9160-DK: TWIM2 reading 4 bytes from a TWIS on the same
    chip (SDA P0.30-P0.13, SCL P0.31-P0.14), the slave's STOPPED events
    counted in hardware: 2 per register read before (STOP + START), 1 after
    (repeated START), with the register address and data right in both.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: Max Kriegleder <[email protected]>
---
 arch/arm/src/nrf91/nrf91_i2c.c | 56 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 46 insertions(+), 10 deletions(-)

diff --git a/arch/arm/src/nrf91/nrf91_i2c.c b/arch/arm/src/nrf91/nrf91_i2c.c
index 05c4996eb31..2b2851de58e 100644
--- a/arch/arm/src/nrf91/nrf91_i2c.c
+++ b/arch/arm/src/nrf91/nrf91_i2c.c
@@ -28,6 +28,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <stdbool.h>
 
 #include <nuttx/debug.h>
 #include <nuttx/irq.h>
@@ -262,6 +263,7 @@ static int nrf91_i2c_transfer(struct i2c_master_s *dev,
   struct nrf91_i2c_priv_s *priv = (struct nrf91_i2c_priv_s *)dev;
   uint32_t regval = 0;
   int      ret = OK;
+  bool     rx_after = false;
 #ifndef CONFIG_NRF91_I2C_MASTER_DISABLE_NOSTART
   uint8_t *pack_buf = NULL;
 #endif
@@ -294,25 +296,25 @@ static int nrf91_i2c_transfer(struct i2c_master_s *dev,
 
       switch (priv->msgv->frequency)
         {
-            case 100000:
+          case 100000:
             {
               regval = TWIM_FREQUENCY_100KBPS;
               break;
             }
 
-            case 250000:
+          case 250000:
             {
               regval = TWIM_FREQUENCY_250KBPS;
               break;
             }
 
-            case 400000:
+          case 400000:
             {
               regval = TWIM_FREQUENCY_400KBPS;
               break;
             }
 
-            default:
+          default:
             {
               ret = -EINVAL;
               goto errout;
@@ -342,6 +344,8 @@ static int nrf91_i2c_transfer(struct i2c_master_s *dev,
       i2cinfo("ptr=%p dcnt=%d flags=%d addr=%d\n",
               priv->ptr, priv->dcnt, priv->flags, priv->addr);
 
+      rx_after = false;
+
       /* Write TWI address */
 
       regval = priv->addr;
@@ -421,10 +425,42 @@ static int nrf91_i2c_transfer(struct i2c_master_s *dev,
           regval = priv->dcnt;
           nrf91_i2c_putreg(priv, NRF91_TWIM_TXDMAXCNT_OFFSET, regval);
 
-          /* Shortcut from LASTTX to STOP */
+          /* A write without STOP followed by a read from the same address
+           * (a register read): repeated START into the read, then STOP.
+           * Both run as one transfer ending in one STOPPED event.  Only
+           * for data in both directions, as the shortcuts need the LASTTX
+           * and LASTRX events.
+           */
 
-          nrf91_i2c_putreg(priv, NRF91_TWIM_SHORTS_OFFSET,
-                           TWIM_SHORTS_LASTTX_STOP);
+          rx_after = (priv->flags & I2C_M_NOSTOP) != 0 &&
+                     priv->dcnt > 0 &&
+                     priv->msgc > 1 &&
+                     priv->msgv[1].length > 0 &&
+                     (priv->msgv[1].flags & I2C_M_READ) != 0 &&
+                     (priv->msgv[1].flags & I2C_M_NOSTART) == 0 &&
+                     priv->msgv[1].addr == priv->addr;
+
+          if (rx_after)
+            {
+              regval = (uint32_t)priv->msgv[1].buffer;
+              DEBUGASSERT(nrf91_easydma_valid(regval));
+              nrf91_i2c_putreg(priv, NRF91_TWIM_RXDPTR_OFFSET, regval);
+              nrf91_i2c_putreg(priv, NRF91_TWIM_RXDMAXCNT_OFFSET,
+                               priv->msgv[1].length);
+
+              /* Shortcuts from LASTTX to STARTRX, LASTRX to STOP */
+
+              nrf91_i2c_putreg(priv, NRF91_TWIM_SHORTS_OFFSET,
+                               TWIM_SHORTS_LASTTX_STARTRX |
+                               TWIM_SHORTS_LASTRX_STOP);
+            }
+          else
+            {
+              /* Shortcut from LASTTX to STOP */
+
+              nrf91_i2c_putreg(priv, NRF91_TWIM_SHORTS_OFFSET,
+                               TWIM_SHORTS_LASTTX_STOP);
+            }
 
           /* Start TX sequence */
 
@@ -491,10 +527,10 @@ static int nrf91_i2c_transfer(struct i2c_master_s *dev,
         }
 #endif
 
-      /* Next message */
+      /* Next message (two after a write with its read) */
 
-      priv->msgc -= 1;
-      priv->msgv += 1;
+      priv->msgc -= rx_after ? 2 : 1;
+      priv->msgv += rx_after ? 2 : 1;
     }
   while (priv->msgc > 0);
 

Reply via email to