tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/i2csoft/i2csoft.go (about) 1 package i2csoft 2 3 import ( 4 "errors" 5 "machine" 6 "time" 7 8 "tinygo.org/x/drivers/delay" 9 ) 10 11 // I2C is an I2C implementation by Software. Since it is implemented by 12 // software, it can be used with microcontrollers that do not have I2C 13 // function. This is not efficient but works around broken or missing drivers. 14 type I2C struct { 15 scl machine.Pin 16 sda machine.Pin 17 nack bool 18 baudrate uint32 19 } 20 21 // I2CConfig is used to store config info for I2C. 22 type I2CConfig struct { 23 Frequency uint32 24 SCL machine.Pin 25 SDA machine.Pin 26 } 27 28 var ( 29 errSI2CAckExpected = errors.New("I2C error: expected ACK not NACK") 30 ) 31 32 // New returns the i2csoft driver. For the arguments, specify the pins to be 33 // used as SCL and SDA. As I2C is implemented in software, any GPIO pin can be 34 // specified. 35 func New(sclPin, sdaPin machine.Pin) *I2C { 36 return &I2C{ 37 scl: sclPin, 38 sda: sdaPin, 39 baudrate: 100e3, 40 } 41 } 42 43 // Configure is intended to setup the I2C interface. 44 func (i2c *I2C) Configure(config I2CConfig) error { 45 // Default I2C bus speed is 100 kHz. 46 if config.Frequency != 0 { 47 i2c.SetBaudRate(config.Frequency) 48 } 49 50 // This exists for compatibility with machine.I2CConfig. SCL and SDA must 51 // be set at the same time. Because Pin(0) is sometimes set, it is not 52 // checked for 0. 53 if config.SCL != config.SDA { 54 i2c.scl = config.SCL 55 i2c.sda = config.SDA 56 } 57 58 // enable pins 59 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput}) 60 i2c.sda.High() 61 i2c.scl.Configure(machine.PinConfig{Mode: machine.PinOutput}) 62 i2c.scl.High() 63 64 return nil 65 } 66 67 // SetBaudRate sets the communication speed for the I2C. 68 func (i2c *I2C) SetBaudRate(br uint32) { 69 // At this time, the value of i2c.baudrate is ignored because it is fixed 70 // at 100 kHz. SetBaudrate() is exist for compatibility with machine.I2C. 71 i2c.baudrate = br 72 } 73 74 // Tx does a single I2C transaction at the specified address. 75 // It clocks out the given address, writes the bytes in w, reads back len(r) 76 // bytes and stores them in r, and generates a stop condition on the bus. 77 func (i2c *I2C) Tx(addr uint16, w, r []byte) error { 78 i2c.nack = false 79 if len(w) != 0 { 80 // send start/address for write 81 i2c.sendAddress(addr, true) 82 83 // wait until transmission complete 84 85 // ACK received (0: ACK, 1: NACK) 86 if i2c.nack { 87 i2c.signalStop() 88 return errSI2CAckExpected 89 } 90 91 // write data 92 for _, b := range w { 93 i2c.writeByte(b) 94 } 95 96 i2c.signalStop() 97 } 98 if len(r) != 0 { 99 // send start/address for read 100 i2c.sendAddress(addr, false) 101 102 // wait transmission complete 103 104 // ACK received (0: ACK, 1: NACK) 105 if i2c.nack { 106 i2c.signalStop() 107 return errSI2CAckExpected 108 } 109 110 // read first byte 111 r[0] = i2c.readByte() 112 for i := 1; i < len(r); i++ { 113 // Send an ACK 114 115 i2c.signalRead() 116 117 // Read data and send the ACK 118 r[i] = i2c.readByte() 119 } 120 121 // Send NACK to end transmission 122 i2c.sendNack() 123 124 i2c.signalStop() 125 } 126 127 return nil 128 } 129 130 // writeByte writes a single byte to the I2C bus. 131 func (i2c *I2C) writeByte(data byte) { 132 // Send data byte 133 i2c.scl.Low() 134 i2c.sda.High() 135 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput}) 136 i2c.wait() 137 138 for i := 0; i < 8; i++ { 139 i2c.scl.Low() 140 if ((data >> (7 - i)) & 1) == 1 { 141 i2c.sda.High() 142 } else { 143 i2c.sda.Low() 144 } 145 i2c.wait() 146 i2c.wait() 147 i2c.scl.High() 148 i2c.wait() 149 i2c.wait() 150 } 151 152 i2c.scl.Low() 153 i2c.wait() 154 i2c.wait() 155 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput}) 156 i2c.scl.High() 157 i2c.wait() 158 159 i2c.nack = i2c.sda.Get() 160 161 i2c.wait() 162 163 // wait until transmission successful 164 } 165 166 // sendAddress sends the address and start signal 167 func (i2c *I2C) sendAddress(address uint16, write bool) { 168 data := (address << 1) 169 if !write { 170 data |= 1 // set read flag 171 } 172 173 i2c.scl.High() 174 i2c.sda.Low() 175 i2c.wait() 176 i2c.wait() 177 for i := 0; i < 8; i++ { 178 i2c.scl.Low() 179 if ((data >> (7 - i)) & 1) == 1 { 180 i2c.sda.High() 181 } else { 182 i2c.sda.Low() 183 } 184 i2c.wait() 185 i2c.wait() 186 i2c.scl.High() 187 i2c.wait() 188 i2c.wait() 189 } 190 191 i2c.scl.Low() 192 i2c.wait() 193 i2c.wait() 194 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput}) 195 i2c.scl.High() 196 i2c.wait() 197 198 i2c.nack = i2c.sda.Get() 199 200 i2c.wait() 201 202 // wait until bus ready 203 } 204 205 func (i2c *I2C) signalStop() { 206 i2c.scl.Low() 207 i2c.sda.Low() 208 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput}) 209 i2c.wait() 210 i2c.wait() 211 i2c.scl.High() 212 i2c.wait() 213 i2c.wait() 214 i2c.sda.High() 215 i2c.wait() 216 i2c.wait() 217 } 218 219 func (i2c *I2C) signalRead() { 220 i2c.wait() 221 i2c.wait() 222 i2c.scl.Low() 223 i2c.sda.Low() 224 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput}) 225 i2c.wait() 226 i2c.wait() 227 i2c.scl.High() 228 i2c.wait() 229 i2c.wait() 230 } 231 232 func (i2c *I2C) readByte() byte { 233 var data byte 234 for i := 0; i < 8; i++ { 235 i2c.scl.Low() 236 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput}) 237 i2c.wait() 238 i2c.wait() 239 i2c.scl.High() 240 if i2c.sda.Get() { 241 data |= 1 << (7 - i) 242 } 243 i2c.wait() 244 i2c.wait() 245 } 246 return data 247 } 248 249 func (i2c *I2C) sendNack() { 250 i2c.wait() 251 i2c.wait() 252 i2c.scl.Low() 253 i2c.sda.High() 254 i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput}) 255 i2c.wait() 256 i2c.wait() 257 i2c.scl.High() 258 i2c.wait() 259 i2c.wait() 260 } 261 262 // WriteRegister transmits first the register and then the data to the 263 // peripheral device. 264 // 265 // Many I2C-compatible devices are organized in terms of registers. This method 266 // is a shortcut to easily write to such registers. Also, it only works for 267 // devices with 7-bit addresses, which is the vast majority. 268 func (i2c *I2C) WriteRegister(address uint8, register uint8, data []byte) error { 269 buf := make([]uint8, len(data)+1) 270 buf[0] = register 271 copy(buf[1:], data) 272 return i2c.Tx(uint16(address), buf, nil) 273 } 274 275 // ReadRegister transmits the register, restarts the connection as a read 276 // operation, and reads the response. 277 // 278 // Many I2C-compatible devices are organized in terms of registers. This method 279 // is a shortcut to easily read such registers. Also, it only works for devices 280 // with 7-bit addresses, which is the vast majority. 281 func (i2c *I2C) ReadRegister(address uint8, register uint8, data []byte) error { 282 return i2c.Tx(uint16(address), []byte{register}, data) 283 } 284 285 // wait waits for half the time of the SCL operation interval. 286 func (i2c *I2C) wait() { 287 delay.Sleep(50 * time.Microsecond) // half of a 100kHz cycle (50µs) 288 }