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 6224690f92abf4bf46a9f9a15f7f9ca9149a8d1c Author: Max Kriegleder <[email protected]> AuthorDate: Sat Oct 24 12:53:47 2026 +0200 arch/arm/nrf52: Use a repeated START for an I2C register read. A register read is a write of the register address with I2C_M_NOSTOP followed by a read from the same address, and many devices require a repeated START between the two. The driver ignored I2C_M_NOSTOP: every write ended in STOP (LASTTX -> STOP), so the read went out as a separate transaction. Found with an LSM6DSL, whose datasheet (DocID028475, tables 16 and 17) requires the repeated START for reads, while debugging out-of-order words in FIFO burst reads through /dev/i2c0. When a write with I2C_M_NOSTOP is followed by a read from the same address and both carry data, run them as one TWIM transfer: LASTTX -> STARTRX makes the repeated START, LASTRX -> STOP ends it, and the pair completes on a single STOPPED event. Every other sequence is handled as before. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Max Kriegleder <[email protected]> --- arch/arm/src/nrf52/nrf52_i2c.c | 48 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/arch/arm/src/nrf52/nrf52_i2c.c b/arch/arm/src/nrf52/nrf52_i2c.c index 7ea13584088..0960c08a506 100644 --- a/arch/arm/src/nrf52/nrf52_i2c.c +++ b/arch/arm/src/nrf52/nrf52_i2c.c @@ -28,6 +28,7 @@ #include <assert.h> #include <errno.h> +#include <stdbool.h> #include <nuttx/debug.h> #include <nuttx/irq.h> @@ -212,6 +213,7 @@ static int nrf52_i2c_transfer(struct i2c_master_s *dev, struct nrf52_i2c_priv_s *priv = (struct nrf52_i2c_priv_s *)dev; uint32_t regval = 0; int ret = OK; + bool rx_after = false; #ifndef CONFIG_NRF52_I2C_MASTER_DISABLE_NOSTART uint8_t *pack_buf = NULL; #endif @@ -292,6 +294,8 @@ static int nrf52_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; @@ -371,10 +375,42 @@ static int nrf52_i2c_transfer(struct i2c_master_s *dev, regval = priv->dcnt; nrf52_i2c_putreg(priv, NRF52_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. + */ - nrf52_i2c_putreg(priv, NRF52_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(nrf52_easydma_valid(regval)); + nrf52_i2c_putreg(priv, NRF52_TWIM_RXDPTR_OFFSET, regval); + nrf52_i2c_putreg(priv, NRF52_TWIM_RXDMAXCNT_OFFSET, + priv->msgv[1].length); + + /* Shortcuts from LASTTX to STARTRX, LASTRX to STOP */ + + nrf52_i2c_putreg(priv, NRF52_TWIM_SHORTS_OFFSET, + TWIM_SHORTS_LASTTX_STARTRX | + TWIM_SHORTS_LASTRX_STOP); + } + else + { + /* Shortcut from LASTTX to STOP */ + + nrf52_i2c_putreg(priv, NRF52_TWIM_SHORTS_OFFSET, + TWIM_SHORTS_LASTTX_STOP); + } /* Start TX sequence */ @@ -441,10 +477,10 @@ static int nrf52_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);
