github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_nrf5x.go (about) 1 //go:build nrf51 || nrf52 2 3 package machine 4 5 import "device/nrf" 6 7 // I2C on the NRF51 and NRF52. 8 type I2C struct { 9 Bus *nrf.TWI_Type 10 mode I2CMode 11 } 12 13 // There are 2 I2C interfaces on the NRF. 14 var ( 15 I2C0 = &I2C{Bus: nrf.TWI0} 16 I2C1 = &I2C{Bus: nrf.TWI1} 17 ) 18 19 func (i2c *I2C) enableAsController() { 20 i2c.Bus.ENABLE.Set(nrf.TWI_ENABLE_ENABLE_Enabled) 21 } 22 23 func (i2c *I2C) enableAsTarget() { 24 // Not supported on this hardware 25 } 26 27 func (i2c *I2C) disable() { 28 i2c.Bus.ENABLE.Set(0) 29 } 30 31 // Tx does a single I2C transaction at the specified address. 32 // It clocks out the given address, writes the bytes in w, reads back len(r) 33 // bytes and stores them in r, and generates a stop condition on the bus. 34 func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) { 35 36 // Tricky stop condition. 37 // After reads, the stop condition is generated implicitly with a shortcut. 38 // After writes not followed by reads and in the case of errors, stop must be generated explicitly. 39 40 i2c.Bus.ADDRESS.Set(uint32(addr)) 41 42 if len(w) != 0 { 43 i2c.Bus.TASKS_STARTTX.Set(1) // start transmission for writing 44 for _, b := range w { 45 if err = i2c.writeByte(b); err != nil { 46 i2c.signalStop() 47 return 48 } 49 } 50 } 51 52 if len(r) != 0 { 53 // To trigger suspend task when a byte is received 54 i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND) 55 i2c.Bus.TASKS_STARTRX.Set(1) // re-start transmission for reading 56 for i := range r { // read each char 57 if i+1 == len(r) { 58 // To trigger stop task when last byte is received, set before resume task. 59 i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_STOP) 60 } 61 if i > 0 { 62 i2c.Bus.TASKS_RESUME.Set(1) // re-start transmission for reading 63 } 64 if r[i], err = i2c.readByte(); err != nil { 65 i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled) 66 i2c.signalStop() 67 return 68 } 69 } 70 i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled) 71 } 72 73 if len(r) == 0 { 74 // Stop the I2C transaction after the write. 75 err = i2c.signalStop() 76 } else { 77 // The last byte read has already stopped the transaction, via 78 // TWI_SHORTS_BB_STOP. But we still need to wait until we receive the 79 // STOPPED event. 80 tries := 0 81 for i2c.Bus.EVENTS_STOPPED.Get() == 0 { 82 tries++ 83 if tries >= i2cTimeout { 84 return errI2CSignalStopTimeout 85 } 86 } 87 i2c.Bus.EVENTS_STOPPED.Set(0) 88 } 89 90 return 91 } 92 93 // writeByte writes a single byte to the I2C bus and waits for confirmation. 94 func (i2c *I2C) writeByte(data byte) error { 95 tries := 0 96 i2c.Bus.TXD.Set(uint32(data)) 97 for i2c.Bus.EVENTS_TXDSENT.Get() == 0 { 98 if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 { 99 i2c.Bus.EVENTS_ERROR.Set(0) 100 return errI2CBusError 101 } 102 tries++ 103 if tries >= i2cTimeout { 104 return errI2CWriteTimeout 105 } 106 } 107 i2c.Bus.EVENTS_TXDSENT.Set(0) 108 return nil 109 } 110 111 // readByte reads a single byte from the I2C bus when it is ready. 112 func (i2c *I2C) readByte() (byte, error) { 113 tries := 0 114 for i2c.Bus.EVENTS_RXDREADY.Get() == 0 { 115 if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 { 116 i2c.Bus.EVENTS_ERROR.Set(0) 117 return 0, errI2CBusError 118 } 119 tries++ 120 if tries >= i2cTimeout { 121 return 0, errI2CReadTimeout 122 } 123 } 124 i2c.Bus.EVENTS_RXDREADY.Set(0) 125 return byte(i2c.Bus.RXD.Get()), nil 126 }