tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/at24cx/at24cx.go (about)

     1  // Package at24cx provides a driver for the AT24C32/64/128/256/512 2-wire serial EEPROM
     2  //
     3  // Datasheet:
     4  // https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf
     5  package at24cx // import "tinygo.org/x/drivers/at24cx"
     6  
     7  import (
     8  	"errors"
     9  	"time"
    10  
    11  	"tinygo.org/x/drivers"
    12  )
    13  
    14  // Device wraps an I2C connection to an AT24CX device.
    15  type Device struct {
    16  	bus               drivers.I2C
    17  	Address           uint16
    18  	pageSize          uint16
    19  	currentRAMAddress uint16
    20  	startRAMAddress   uint16
    21  	endRAMAddress     uint16
    22  }
    23  
    24  type Config struct {
    25  	PageSize        uint16
    26  	StartRAMAddress uint16
    27  	EndRAMAddress   uint16
    28  }
    29  
    30  // New creates a new AT24C32/64 connection. The I2C bus must already be
    31  // configured.
    32  //
    33  // This function only creates the Device object, it does not touch the device.
    34  func New(bus drivers.I2C) Device {
    35  	return Device{
    36  		bus:     bus,
    37  		Address: Address,
    38  	}
    39  }
    40  
    41  // Configure sets up the device for communication
    42  func (d *Device) Configure(cfg Config) {
    43  	if cfg.PageSize == 0 {
    44  		d.pageSize = 32
    45  	} else {
    46  		d.pageSize = cfg.PageSize
    47  	}
    48  	if cfg.EndRAMAddress == 0 {
    49  		d.endRAMAddress = 4096
    50  	} else {
    51  		d.endRAMAddress = cfg.EndRAMAddress
    52  	}
    53  	d.startRAMAddress = cfg.StartRAMAddress
    54  }
    55  
    56  // WriteByte writes a byte at the specified address
    57  func (d *Device) WriteByte(eepromAddress uint16, value uint8) error {
    58  	address := []uint8{
    59  		uint8((eepromAddress >> 8) & 0xFF),
    60  		uint8(eepromAddress & 0xFF),
    61  		value,
    62  	}
    63  	return d.bus.Tx(d.Address, address, nil)
    64  }
    65  
    66  // ReadByte reads the byte at the specified address
    67  func (d *Device) ReadByte(eepromAddress uint16) (uint8, error) {
    68  	address := []uint8{
    69  		uint8(eepromAddress >> 8),
    70  		uint8(eepromAddress & 0xFF),
    71  	}
    72  	data := make([]uint8, 1)
    73  	err := d.bus.Tx(d.Address, address, data)
    74  	return data[0], err
    75  }
    76  
    77  // WriteAt writes a byte array at the specified address
    78  func (d *Device) WriteAt(data []byte, offset int64) (n int, err error) {
    79  	return d.writeAt(data, uint16(offset))
    80  }
    81  
    82  // writeAt writes a byte array at the specified address
    83  func (d *Device) writeAt(data []byte, offset uint16) (n int, err error) {
    84  	values := make([]uint8, 32)
    85  	dataLeft := uint16(len(data))
    86  	d.currentRAMAddress = offset
    87  	offset = 0
    88  	var offsetPage uint16
    89  	var chunkLength uint16
    90  	for dataLeft > 0 {
    91  		offsetPage = d.currentRAMAddress % d.pageSize
    92  		if dataLeft < 30 { // The 32K/64K EEPROM is capable of 32-byte page writes and we're using 2 for the address
    93  			chunkLength = dataLeft
    94  		} else {
    95  			chunkLength = 30
    96  		}
    97  		if (d.pageSize - offsetPage) < chunkLength {
    98  			chunkLength = d.pageSize - offsetPage
    99  		}
   100  		for i := uint16(0); i < chunkLength; i++ {
   101  			values[2+i] = data[offset+i]
   102  		}
   103  		values[0] = uint8(d.currentRAMAddress >> 8)
   104  		values[1] = uint8(d.currentRAMAddress & 0xFF)
   105  		err := d.bus.Tx(d.Address, values[:chunkLength+2], nil)
   106  		if err != nil {
   107  			return 0, err
   108  		}
   109  		dataLeft -= chunkLength
   110  		offset += chunkLength
   111  		if d.endRAMAddress-chunkLength < d.currentRAMAddress {
   112  			d.currentRAMAddress = d.startRAMAddress + (d.currentRAMAddress+uint16(len(data)))%d.endRAMAddress
   113  		} else {
   114  			d.currentRAMAddress += chunkLength
   115  		}
   116  		time.Sleep(2 * time.Millisecond) // writing again too soon will block the device
   117  	}
   118  	return len(data), nil
   119  }
   120  
   121  // ReadAt reads the bytes at the specified address
   122  func (d *Device) ReadAt(data []byte, offset int64) (n int, err error) {
   123  	return d.readAt(data, uint16(offset))
   124  }
   125  
   126  // readAt reads the bytes at the specified address
   127  func (d *Device) readAt(data []byte, offset uint16) (n int, err error) {
   128  	address := []uint8{
   129  		uint8((offset >> 8) & 0xFF),
   130  		uint8(offset & 0xFF),
   131  	}
   132  	err = d.bus.Tx(d.Address, address, data)
   133  
   134  	if d.endRAMAddress-uint16(len(data)) < offset {
   135  		d.currentRAMAddress = d.startRAMAddress + (offset+uint16(len(data)))%d.endRAMAddress
   136  	} else {
   137  		d.currentRAMAddress = offset + uint16(len(data))
   138  	}
   139  	return len(data), err
   140  }
   141  
   142  // Seek sets the offset for the next Read or Write on SRAM to offset, interpreted
   143  // according to whence: 0 means relative to the origin of the SRAM, 1 means
   144  // relative to the current offset, and 2 means relative to the end.
   145  // returns new offset and error, if any
   146  func (d *Device) Seek(offset int64, whence int) (int64, error) {
   147  	w := uint16(0)
   148  	switch whence {
   149  	case 0:
   150  		w = d.startRAMAddress
   151  	case 1:
   152  		w = d.currentRAMAddress
   153  	case 2:
   154  		w = d.endRAMAddress
   155  	default:
   156  		return 0, errors.New("invalid whence")
   157  	}
   158  	d.currentRAMAddress = w + uint16(offset)
   159  	return int64(d.currentRAMAddress), nil
   160  }
   161  
   162  // Write writes len(data) bytes to SRAM
   163  // returns number of bytes written and error, if any
   164  func (d *Device) Write(data []byte) (n int, err error) {
   165  	return d.writeAt(data, d.currentRAMAddress)
   166  }
   167  
   168  // Read reads len(data) from SRAM
   169  // returns number of bytes written and error, if any
   170  func (d *Device) Read(data []uint8) (n int, err error) {
   171  	return d.readAt(data, d.currentRAMAddress)
   172  }