aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2023-07-13 15:24:58 +0200
committerRon Evans <[email protected]>2023-07-16 10:27:33 +0200
commit14ddba851903177b26fff97644b6979fea7ade3a (patch)
tree32e3eb79bc44248b87ce0b5134a978fbdf399f86
parenta7b205c26cab4f87d9b2e5e845482cd206ba1daf (diff)
downloadtinygo-14ddba851903177b26fff97644b6979fea7ade3a.tar.gz
tinygo-14ddba851903177b26fff97644b6979fea7ade3a.zip
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.
-rw-r--r--src/machine/machine_nrf.go10
-rw-r--r--src/machine/machine_nrf5x.go17
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