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  }