diff --git a/internal/regmap/devices.go b/internal/regmap/device8.go similarity index 66% rename from internal/regmap/devices.go rename to internal/regmap/device8.go index 348dc6af8..b62aec1bf 100644 --- a/internal/regmap/devices.go +++ b/internal/regmap/device8.go @@ -8,6 +8,10 @@ import ( ) // Device8 implements common logic to most 8-bit peripherals with an I2C or SPI bus. +// All methods expect the target to support conventional register read and write operations +// where the first byte sent is the register address being accessed. +// +// All methods use an internal buffer and perform no dynamic memory allocation. type Device8 struct { buf [10]byte } @@ -19,41 +23,53 @@ func (d *Device8) clear() { // I2C methods. +// Read8I2C reads a single byte from register addr of the device at i2cAddr using the provided I2C bus. func (d *Device8) Read8I2C(bus drivers.I2C, i2cAddr uint16, addr uint8) (byte, error) { d.buf[0] = addr err := bus.Tx(i2cAddr, d.buf[0:1], d.buf[1:2]) return d.buf[1], err } +// Read16I2C reads a 16-bit value from register addr of the device at i2cAddr using the provided I2C bus. +// The byte order is specified by order. func (d *Device8) Read16I2C(bus drivers.I2C, i2cAddr uint16, addr uint8, order binary.ByteOrder) (uint16, error) { d.buf[0] = addr err := bus.Tx(i2cAddr, d.buf[0:1], d.buf[1:3]) return order.Uint16(d.buf[1:3]), err } +// Read32I2C reads a 32-bit value from register addr of the device at i2cAddr using the provided I2C bus. +// The byte order is specified by order. func (d *Device8) Read32I2C(bus drivers.I2C, i2cAddr uint16, addr uint8, order binary.ByteOrder) (uint32, error) { d.buf[0] = addr err := bus.Tx(i2cAddr, d.buf[0:1], d.buf[1:5]) return order.Uint32(d.buf[1:5]), err } +// ReadDataI2C reads dataLength bytes from register addr of the device at i2cAddr using the provided I2C bus. +// The data is stored in dataDestination. func (d *Device8) ReadDataI2C(bus drivers.I2C, i2cAddr uint16, addr uint8, dataDestination []byte) error { d.buf[0] = addr return bus.Tx(i2cAddr, d.buf[:1], dataDestination) } +// Write8I2C writes a single byte value to register addr of the device at i2cAddr using the provided I2C bus. func (d *Device8) Write8I2C(bus drivers.I2C, i2cAddr uint16, addr, value uint8) error { d.buf[0] = addr d.buf[1] = value return bus.Tx(i2cAddr, d.buf[:2], nil) } +// Write16I2C writes a 16-bit value to register addr of the device at i2cAddr using the provided I2C bus. +// The byte order is specified by order. func (d *Device8) Write16I2C(bus drivers.I2C, i2cAddr uint16, addr uint8, value uint16, order binary.ByteOrder) error { d.buf[0] = addr order.PutUint16(d.buf[1:3], value) return bus.Tx(i2cAddr, d.buf[0:3], nil) } +// Write32I2C writes a 32-bit value to register addr of the device at i2cAddr using the provided I2C bus. +// The byte order is specified by order. func (d *Device8) Write32I2C(bus drivers.I2C, i2cAddr uint16, addr uint8, value uint32, order binary.ByteOrder) error { d.buf[0] = addr order.PutUint32(d.buf[1:5], value) @@ -62,6 +78,7 @@ func (d *Device8) Write32I2C(bus drivers.I2C, i2cAddr uint16, addr uint8, value // SPI methods. +// Read8SPI reads a single byte from register addr using the provided SPI bus. func (d *Device8) Read8SPI(bus drivers.SPI, addr uint8) (byte, error) { d.clear() d.buf[0] = addr @@ -69,6 +86,7 @@ func (d *Device8) Read8SPI(bus drivers.SPI, addr uint8) (byte, error) { return d.buf[1], err } +// Read16SPI reads a 16-bit value from register addr using the provided SPI bus. The byte order is specified by order. func (d *Device8) Read16SPI(bus drivers.SPI, addr uint8, order binary.ByteOrder) (uint16, error) { d.clear() d.buf[0] = addr @@ -76,6 +94,7 @@ func (d *Device8) Read16SPI(bus drivers.SPI, addr uint8, order binary.ByteOrder) return order.Uint16(d.buf[4:6]), err } +// Read32SPI reads a 32-bit value from register addr using the provided SPI bus. The byte order is specified by order. func (d *Device8) Read32SPI(bus drivers.SPI, addr uint8, order binary.ByteOrder) (uint32, error) { d.clear() d.buf[0] = addr @@ -99,6 +118,7 @@ func (d *Device8) ReadDataSPI(bus drivers.SPI, addr uint8, dataLength int, auxil return rbuf[1:], err } +// Write8SPI writes a single byte value to register addr using the provided SPI bus. func (d *Device8) Write8SPI(bus drivers.SPI, addr, value uint8) error { d.clear() d.buf[0] = addr @@ -106,6 +126,7 @@ func (d *Device8) Write8SPI(bus drivers.SPI, addr, value uint8) error { return bus.Tx(d.buf[:2], nil) } +// Write16SPI writes a 16-bit value to register addr using the provided SPI bus. The byte order is specified by order. func (d *Device8) Write16SPI(bus drivers.SPI, addr uint8, value uint16, order binary.ByteOrder) error { d.clear() d.buf[0] = addr @@ -113,6 +134,7 @@ func (d *Device8) Write16SPI(bus drivers.SPI, addr uint8, value uint16, order bi return bus.Tx(d.buf[:3], nil) } +// Write32SPI writes a 32-bit value to register addr using the provided SPI bus. The byte order is specified by order. func (d *Device8) Write32SPI(bus drivers.SPI, addr uint8, value uint32, order binary.ByteOrder) error { d.clear() d.buf[0] = addr diff --git a/internal/regmap/i2c-spi.go b/internal/regmap/i2c-spi.go new file mode 100644 index 000000000..0e0abe748 --- /dev/null +++ b/internal/regmap/i2c-spi.go @@ -0,0 +1,123 @@ +package regmap + +import ( + "encoding/binary" + + "tinygo.org/x/drivers" +) + +// Device8SPI implements common logic to most 8-bit peripherals with an SPI bus. +// All methods expect the target to support conventional register read and write operations +// where the first byte sent is the register address being accessed. +// +// All methods use an internal buffer and perform no dynamic memory allocation. +type Device8SPI struct { + bus drivers.SPI + order binary.ByteOrder + d Device8 +} + +// SetBus sets the SPI bus and byte order for the Device8SPI. +// +// As a hint, most SPI devices use big-endian (MSB) byte order. +// - Big endian: A value of 0x1234 is transmitted as 0x12 followed by 0x34. +// - Little endian: A value of 0x1234 is transmitted as 0x34 followed by 0x12. +func (d *Device8SPI) SetBus(bus drivers.SPI, order binary.ByteOrder) { + d.bus = bus + d.order = order +} + +// Read8 reads a single byte from register addr. +func (d *Device8SPI) Read8(addr uint8) (byte, error) { + return d.d.Read8SPI(d.bus, addr) +} + +// Read16 reads a 16-bit value from register addr. +func (d *Device8SPI) Read16(addr uint8) (uint16, error) { + return d.d.Read16SPI(d.bus, addr, d.order) +} + +// Read32 reads a 32-bit value from register addr. +func (d *Device8SPI) Read32(addr uint8) (uint32, error) { + return d.d.Read32SPI(d.bus, addr, d.order) +} + +// ReadData reads dataLength bytes from register addr. Due to the internal functioning of +// SPI, an auxiliary buffer must be provided to perform the operation and avoid memory allocation. +// The returned slice is a subslice of auxBuffer containing the read data. +func (d *Device8SPI) ReadData(addr uint8, datalength int, auxBuffer []byte) ([]byte, error) { + return d.d.ReadDataSPI(d.bus, addr, datalength, auxBuffer) +} + +// Write8 writes a single byte value to register addr. +func (d *Device8SPI) Write8(addr, value uint8) error { + return d.d.Write8SPI(d.bus, addr, value) +} + +// Write16 writes a 16-bit value to register addr. +func (d *Device8SPI) Write16(addr uint8, value uint16) error { + return d.d.Write16SPI(d.bus, addr, value, d.order) +} + +// Write32 writes a 32-bit value to register addr. +func (d *Device8SPI) Write32(addr uint8, value uint32) error { + return d.d.Write32SPI(d.bus, addr, value, d.order) +} + +// Device8I2C implements common logic to most 8-bit peripherals with an I2C bus. +// All methods expect the target to support conventional register read and write operations +// where the first byte sent is the register address being accessed. +// +// All methods use an internal buffer and perform no dynamic memory allocation. +type Device8I2C struct { + bus drivers.I2C + i2cAddr uint16 + order binary.ByteOrder + d Device8 +} + +// SetBus sets the I2C bus, device address, and byte order for the Device8I2C. +// +// As a hint, most I2C devices use big-endian (MSB) byte order. +// - Big endian: A value of 0x1234 is transmitted as 0x12 followed by 0x34. +// - Little endian: A value of 0x1234 is transmitted as 0x34 followed by 0x12. +func (d *Device8I2C) SetBus(bus drivers.I2C, i2cAddr uint16, order binary.ByteOrder) { + d.bus = bus + d.i2cAddr = i2cAddr + d.order = order +} + +// Read8 reads a single byte from register addr. +func (d *Device8I2C) Read8(addr uint8) (byte, error) { + return d.d.Read8I2C(d.bus, d.i2cAddr, addr) +} + +// Read16 reads a 16-bit value from register addr. +func (d *Device8I2C) Read16(addr uint8) (uint16, error) { + return d.d.Read16I2C(d.bus, d.i2cAddr, addr, d.order) +} + +// Read32 reads a 32-bit value from register addr. +func (d *Device8I2C) Read32(addr uint8) (uint32, error) { + return d.d.Read32I2C(d.bus, d.i2cAddr, addr, d.order) +} + +// ReadData reads dataLength bytes from register addr. +func (d *Device8I2C) ReadData(addr uint8, dataDestination []byte) error { + return d.d.ReadDataI2C(d.bus, d.i2cAddr, addr, dataDestination) +} + +// Write8 writes a single byte value to register addr. +func (d *Device8I2C) Write8(addr, value uint8) error { + return d.d.Write8I2C(d.bus, d.i2cAddr, addr, value) +} + +// Write16 writes a 16-bit value to register addr. +func (d *Device8I2C) Write16(addr uint8, value uint16) error { + return d.d.Write16I2C(d.bus, d.i2cAddr, addr, value, d.order) +} + +// Write32 writes a 32-bit value to register addr. +func (d *Device8I2C) Write32(addr uint8, value uint32) error { + return d.d.Write32I2C(d.bus, d.i2cAddr, addr, value, d.order) +}