diff --git a/src/machine/machine_esp32_i2c.go b/src/machine/machine_esp32_i2c.go index abcc2b4c94..8542bf4608 100644 --- a/src/machine/machine_esp32_i2c.go +++ b/src/machine/machine_esp32_i2c.go @@ -242,6 +242,7 @@ func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { timeoutNS := int64(timeoutMS) * 1000000 needAddress := true needRestart := false + isRead := false var readTo []byte for cmdIdx, reg := 0, &i2c.Bus.COMD0; cmdIdx < len(cmd); { c := &cmd[cmdIdx] @@ -253,6 +254,7 @@ func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { cmdIdx++ case i2cCMD_WRITE: + isRead = false count := 32 if needAddress { needAddress = false @@ -266,15 +268,17 @@ func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { reg.Set(i2cCMD_WRITE | uint32(32-count)) reg = nextAddress(reg) - if c.head < len(c.data) { - reg.Set(i2cCMD_END) - reg = nil - } else { + // Always end a write segment with END, so STOP goes out alone + // in its own segment (ref: ESP32 TRM v5.8, section 21.3.5). + reg.Set(i2cCMD_END) + reg = nil + if c.head >= len(c.data) { cmdIdx++ } needRestart = true case i2cCMD_READ: + isRead = true if needAddress { needAddress = false i2c.Bus.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) @@ -308,10 +312,16 @@ func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { reg = nextAddress(reg) } - if split { + if split && bytes > 0 { + reg.Set(i2cCMD_END) + readTo = c.data[c.head : c.head+bytes] + reg = nil + } else if split { reg.Set(i2cCMD_READLAST | 1) reg = nextAddress(reg) - readTo = c.data[c.head : c.head+bytes+1] // read bytes + 1 last byte + reg.Set(i2cCMD_END) + readTo = c.data[c.head : c.head+1] + reg = nil cmdIdx++ } else { reg.Set(i2cCMD_END) @@ -333,7 +343,7 @@ func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { if nanotime() > end { // timeout leaves the bus in an undefined state, reset i2c.resetBus() - if readTo != nil { + if isRead { return errI2CReadTimeout } return errI2CWriteTimeout @@ -345,7 +355,7 @@ func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { case mask&esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk != 0: // timeout leaves the bus in an undefined state, reset i2c.resetBus() - if readTo != nil { + if isRead { return errI2CReadTimeout } return errI2CWriteTimeout