From 14ddba851903177b26fff97644b6979fea7ade3a Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 13 Jul 2023 15:24:58 +0200 Subject: nrf: add I2C timeout This commit adds I2C timeouts for nrf51 and nrf52 (but not yet for others like nrf52840). Tested on the PineTime, where I now got a timeout instead of hanging and resetting due to a watchdog reset. --- src/machine/machine_nrf.go | 10 +++++++++- src/machine/machine_nrf5x.go | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_nrf.go b/src/machine/machine_nrf.go index 346a0bb2e..d7b87d9ae 100644 --- a/src/machine/machine_nrf.go +++ b/src/machine/machine_nrf.go @@ -203,6 +203,8 @@ func (uart *UART) handleInterrupt(interrupt.Interrupt) { } } +const i2cTimeout = 0xffff // this is around 29ms on a nrf52 + // I2CConfig is used to store config info for I2C. type I2CConfig struct { Frequency uint32 @@ -261,11 +263,17 @@ func (i2c *I2C) Configure(config I2CConfig) error { } // signalStop sends a stop signal to the I2C peripheral and waits for confirmation. -func (i2c *I2C) signalStop() { +func (i2c *I2C) signalStop() error { + tries := 0 i2c.Bus.TASKS_STOP.Set(1) for i2c.Bus.EVENTS_STOPPED.Get() == 0 { + tries++ + if tries >= i2cTimeout { + return errI2CSignalStopTimeout + } } i2c.Bus.EVENTS_STOPPED.Set(0) + return nil } var rngStarted = false diff --git a/src/machine/machine_nrf5x.go b/src/machine/machine_nrf5x.go index 8c012b49e..4c731036b 100644 --- a/src/machine/machine_nrf5x.go +++ b/src/machine/machine_nrf5x.go @@ -72,12 +72,17 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) { if len(r) == 0 { // Stop the I2C transaction after the write. - i2c.signalStop() + err = i2c.signalStop() } else { // The last byte read has already stopped the transaction, via // TWI_SHORTS_BB_STOP. But we still need to wait until we receive the // STOPPED event. + tries := 0 for i2c.Bus.EVENTS_STOPPED.Get() == 0 { + tries++ + if tries >= i2cTimeout { + return errI2CSignalStopTimeout + } } i2c.Bus.EVENTS_STOPPED.Set(0) } @@ -87,12 +92,17 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) { // writeByte writes a single byte to the I2C bus and waits for confirmation. func (i2c *I2C) writeByte(data byte) error { + tries := 0 i2c.Bus.TXD.Set(uint32(data)) for i2c.Bus.EVENTS_TXDSENT.Get() == 0 { if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 { i2c.Bus.EVENTS_ERROR.Set(0) return errI2CBusError } + tries++ + if tries >= i2cTimeout { + return errI2CWriteTimeout + } } i2c.Bus.EVENTS_TXDSENT.Set(0) return nil @@ -100,11 +110,16 @@ func (i2c *I2C) writeByte(data byte) error { // readByte reads a single byte from the I2C bus when it is ready. func (i2c *I2C) readByte() (byte, error) { + tries := 0 for i2c.Bus.EVENTS_RXDREADY.Get() == 0 { if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 { i2c.Bus.EVENTS_ERROR.Set(0) return 0, errI2CBusError } + tries++ + if tries >= i2cTimeout { + return 0, errI2CReadTimeout + } } i2c.Bus.EVENTS_RXDREADY.Set(0) return byte(i2c.Bus.RXD.Get()), nil -- cgit v1.2.3