Compare commits

..

10 Commits

Author SHA1 Message Date
Patricio Whittingslow ec6385c15a add example usage 2025-11-09 12:35:11 -03:00
Patricio Whittingslow 7267dc1014 change method name 2025-11-09 12:26:53 -03:00
Patricio Whittingslow 84bfe4a928 add regmap.Device8Txer 2025-11-09 12:21:59 -03:00
Pat Whittingslow bd88b70511 regmap: Add Device8I2C/SPI types and their logic (#801)
* add regmap Device8I2C/SPI types and their methods
* add endianess hint
2025-11-09 14:05:30 +01:00
Yurii Soldak 34da2d208a lsm9ds1: avoid unnecessary heap allocations 2025-11-08 10:53:22 +01:00
Pat Whittingslow 5cb360a4bf Add Honeywell HSC TruStability SPI+I2C pressure sensor driver (#799)
* add honeywell pressure sensor
* apply @aykevl suggestions
2025-11-08 10:45:18 +01:00
Ayke van Laethem 51b604ce97 lis3dh: add Update and Acceleration calls
This adjusts the API to the one proposed in
https://github.com/tinygo-org/drivers/pull/345, which I think is much
better than direct ReadAcceleration etc calls.

I have also updated the code that converts raw acceleration values to
normalized values. The new code should be faster (didn't measure) and
avoids floating point math.
2025-11-08 10:34:37 +01:00
Ayke van Laethem ec680be784 lis3dh: use correct error handling and make configurable
Instead of printing an error, this driver really should be returning
errors instead. Also, `Configure` didn't have a way to actually
configure the driver. This is now added, and can be expanded in the
future.

This is a breaking change.
2025-11-08 10:34:37 +01:00
Pat Whittingslow 5fb935001e PinInput+PinOutput HAL (#753, reloaded) (#795)
* first commit: add HAL and uc8151 driver demo
* unexport drivers.PinOutput/Input HAL
* fix non-tinygo pin config build
* change of heart
* docs: corrected some comments that were not changed at the same time as recent renaming
2025-11-08 10:21:01 +01:00
Martin Heck 297ad416d3 fix: add RP2350 to quadrature_interrupt.go 2025-09-23 14:03:35 +02:00
49 changed files with 1295 additions and 657 deletions
+3 -6
View File
@@ -5,9 +5,9 @@ package apa102 // import "tinygo.org/x/drivers/apa102"
import (
"image/color"
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
const (
@@ -37,11 +37,8 @@ func New(b drivers.SPI) *Device {
// NewSoftwareSPI returns a new APA102 driver that will use a software based
// implementation of the SPI protocol.
func NewSoftwareSPI(sckPin, sdoPin drivers.PinOutput, delay uint32) *Device {
return New(&bbSPI{SCK: sckPin.Set, SDO: sdoPin.Set, Delay: delay, configurePins: func() {
legacy.ConfigurePinOut(sckPin)
legacy.ConfigurePinOut(sdoPin)
}})
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
}
// WriteColors writes the given RGBA color slice out using the APA102 protocol.
+6 -12
View File
@@ -1,9 +1,6 @@
package apa102
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
import "machine"
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
@@ -11,18 +8,15 @@ import (
// most purposes other than the APA102 package. It might be desirable to make
// this more generic and include it in the TinyGo "machine" package instead.
type bbSPI struct {
SCK drivers.PinOutputFunc
SDO drivers.PinOutputFunc
Delay uint32
configurePins func()
SCK machine.Pin
SDO machine.Pin
Delay uint32
}
// Configure sets up the SCK and SDO pins as outputs and sets them low
func (s *bbSPI) Configure() {
if s.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
s.configurePins()
s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
s.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
s.SCK.Low()
s.SDO.Low()
if s.Delay == 0 {
+23 -30
View File
@@ -1,35 +1,31 @@
package bmi160
import (
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// DeviceSPI is the SPI interface to a BMI160 accelerometer/gyroscope. There is
// also an I2C interface, but it is not yet supported.
type DeviceSPI struct {
// Chip select pin
csb drivers.PinOutputFunc
CSB machine.Pin
buf [7]byte
// SPI bus (requires chip select to be usable).
bus drivers.SPI
configurePins func()
Bus drivers.SPI
}
// NewSPI returns a new device driver. The pin and SPI interface are not
// touched, provide a fully configured SPI object and call Configure to start
// using this device.
func NewSPI(csb drivers.PinOutput, spi drivers.SPI) *DeviceSPI {
func NewSPI(csb machine.Pin, spi drivers.SPI) *DeviceSPI {
return &DeviceSPI{
csb: csb.Set, // chip select
bus: spi,
configurePins: func() {
legacy.ConfigurePinOut(csb)
},
CSB: csb, // chip select
Bus: spi,
}
}
@@ -37,11 +33,8 @@ func NewSPI(csb drivers.PinOutput, spi drivers.SPI) *DeviceSPI {
// configures the BMI160, but it does not configure the SPI interface (it is
// assumed to be up and running).
func (d *DeviceSPI) Configure() error {
if d.configurePins == nil {
return legacy.ErrConfigBeforeInstantiated
}
d.configurePins()
d.csb.High()
d.CSB.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.CSB.High()
// The datasheet recommends doing a register read from address 0x7F to get
// SPI communication going:
@@ -93,9 +86,9 @@ func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
data[0] = 0x80 | reg_TEMPERATURE_0
data[1] = 0
data[2] = 0
d.csb.Low()
err = d.bus.Tx(data, data)
d.csb.High()
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
if err != nil {
return
}
@@ -130,9 +123,9 @@ func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
for i := 1; i < len(data); i++ {
data[i] = 0
}
d.csb.Low()
err = d.bus.Tx(data, data)
d.csb.High()
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
if err != nil {
return
}
@@ -160,9 +153,9 @@ func (d *DeviceSPI) ReadRotation() (x int32, y int32, z int32, err error) {
for i := 1; i < len(data); i++ {
data[i] = 0
}
d.csb.Low()
err = d.bus.Tx(data, data)
d.csb.High()
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
if err != nil {
return
}
@@ -208,9 +201,9 @@ func (d *DeviceSPI) readRegister(address uint8) uint8 {
data := d.buf[:2]
data[0] = 0x80 | address
data[1] = 0
d.csb.Low()
d.bus.Tx(data, data)
d.csb.High()
d.CSB.Low()
d.Bus.Tx(data, data)
d.CSB.High()
return data[1]
}
@@ -224,7 +217,7 @@ func (d *DeviceSPI) writeRegister(address, data uint8) {
buf[0] = address
buf[1] = data
d.csb.Low()
d.bus.Tx(buf, buf)
d.csb.High()
d.CSB.Low()
d.Bus.Tx(buf, buf)
d.CSB.High()
}
+7 -7
View File
@@ -2,22 +2,22 @@
package buzzer // import "tinygo.org/x/drivers/buzzer"
import (
"time"
"machine"
"tinygo.org/x/drivers"
"time"
)
// Device wraps a GPIO connection to a buzzer.
type Device struct {
pin drivers.PinOutputFunc
pin machine.Pin
High bool
BPM float64
}
// New returns a new buzzer driver given which pin to use
func New(pin drivers.PinOutput) Device {
func New(pin machine.Pin) Device {
return Device{
pin: pin.Set,
pin: pin,
High: false,
BPM: 96.0,
}
@@ -25,14 +25,14 @@ func New(pin drivers.PinOutput) Device {
// On sets the buzzer to a high state.
func (l *Device) On() (err error) {
l.pin.High()
l.pin.Set(true)
l.High = true
return
}
// Off sets the buzzer to a low state.
func (l *Device) Off() (err error) {
l.pin.Low()
l.pin.Set(false)
l.High = false
return
}
+67 -4
View File
@@ -2,9 +2,9 @@
package easystepper // import "tinygo.org/x/drivers/easystepper"
import (
"errors"
"machine"
"time"
"tinygo.org/x/drivers"
)
// StepMode determines the coil sequence used to perform a single step
@@ -30,10 +30,28 @@ func (sm StepMode) stepCount() uint {
}
}
// DeviceConfig contains the configuration data for a single easystepper driver
type DeviceConfig struct {
// Pin1 ... Pin4 determines the pins to configure and use for the device
Pin1, Pin2, Pin3, Pin4 machine.Pin
// StepCount is the number of steps required to perform a full revolution of the stepper motor
StepCount uint
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
RPM uint
// Mode determines the coil sequence used to perform a single step
Mode StepMode
}
// DualDeviceConfig contains the configuration data for a dual easystepper driver
type DualDeviceConfig struct {
DeviceConfig
// Pin5 ... Pin8 determines the pins to configure and use for the second device
Pin5, Pin6, Pin7, Pin8 machine.Pin
}
// Device holds the pins and the delay between steps
type Device struct {
pins [4]drivers.PinOutputFunc
config func()
pins [4]machine.Pin
stepDelay time.Duration
stepNumber uint8
stepMode StepMode
@@ -44,6 +62,51 @@ type DualDevice struct {
devices [2]*Device
}
// New returns a new single easystepper driver given a DeviceConfig
func New(config DeviceConfig) (*Device, error) {
if config.StepCount == 0 || config.RPM == 0 {
return nil, errors.New("config.StepCount and config.RPM must be > 0")
}
return &Device{
pins: [4]machine.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
stepMode: config.Mode,
}, nil
}
// Configure configures the pins of the Device
func (d *Device) Configure() {
for _, pin := range d.pins {
pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
}
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
func NewDual(config DualDeviceConfig) (*DualDevice, error) {
// Create the first device
dev1, err := New(config.DeviceConfig)
if err != nil {
return nil, err
}
// Create the second device
config.DeviceConfig.Pin1 = config.Pin5
config.DeviceConfig.Pin2 = config.Pin6
config.DeviceConfig.Pin3 = config.Pin7
config.DeviceConfig.Pin4 = config.Pin8
dev2, err := New(config.DeviceConfig)
if err != nil {
return nil, err
}
// Return composite dual device
return &DualDevice{devices: [2]*Device{dev1, dev2}}, nil
}
// Configure configures the pins of the DualDevice
func (d *DualDevice) Configure() {
d.devices[0].Configure()
d.devices[1].Configure()
}
// Move rotates the motor the number of given steps
// (negative steps will rotate it the opposite direction)
func (d *Device) Move(steps int32) {
-26
View File
@@ -1,26 +0,0 @@
package easystepper
import (
"errors"
"time"
"tinygo.org/x/drivers"
)
func NewCrossPlatform(stepcount, rpm uint, mode StepMode, pins [4]drivers.PinOutputFunc) (*Device, error) {
if stepcount == 0 || rpm == 0 {
return nil, errors.New("zero rpm and/or stepcount")
}
for i := range pins {
if pins[i] == nil {
return nil, errors.New("nil pin")
}
}
d := &Device{
pins: pins,
stepDelay: time.Second * 60 / time.Duration((stepcount * rpm)),
stepMode: mode,
config: func() {},
}
return d, nil
}
-83
View File
@@ -1,83 +0,0 @@
//go:build baremetal
package easystepper
import (
"errors"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// New returns a new single easystepper driver given a DeviceConfig
func New(config DeviceConfig) (*Device, error) {
if config.StepCount == 0 || config.RPM == 0 {
return nil, errors.New("config.StepCount and config.RPM must be > 0")
}
return &Device{
pins: [4]drivers.PinOutputFunc{config.Pin1.Set, config.Pin2.Set, config.Pin3.Set, config.Pin4.Set},
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
stepMode: config.Mode,
config: func() {
legacy.ConfigurePinOut(config.Pin1)
legacy.ConfigurePinOut(config.Pin2)
legacy.ConfigurePinOut(config.Pin3)
legacy.ConfigurePinOut(config.Pin4)
},
}, nil
}
// Configure configures the pins of the Device
func (d *Device) Configure() {
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.config()
}
// Configure configures the pins of the DualDevice
func (d *DualDevice) Configure() {
d.devices[0].Configure()
d.devices[1].Configure()
}
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
func NewDual(config DualDeviceConfig) (*DualDevice, error) {
// Create the first device
dev1, err := New(config.DeviceConfig)
if err != nil {
return nil, err
}
// Create the second device
config.DeviceConfig.Pin1 = config.Pin5
config.DeviceConfig.Pin2 = config.Pin6
config.DeviceConfig.Pin3 = config.Pin7
config.DeviceConfig.Pin4 = config.Pin8
dev2, err := New(config.DeviceConfig)
if err != nil {
return nil, err
}
// Return composite dual device
return &DualDevice{devices: [2]*Device{dev1, dev2}}, nil
}
// DeviceConfig contains the configuration data for a single easystepper driver
type DeviceConfig struct {
// Pin1 ... Pin4 determines the pins to configure and use for the device
Pin1, Pin2, Pin3, Pin4 machine.Pin
// StepCount is the number of steps required to perform a full revolution of the stepper motor
StepCount uint
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
RPM uint
// Mode determines the coil sequence used to perform a single step
Mode StepMode
}
// DualDeviceConfig contains the configuration data for a dual easystepper driver
type DualDeviceConfig struct {
DeviceConfig
// Pin5 ... Pin8 determines the pins to configure and use for the second device
Pin5, Pin6, Pin7, Pin8 machine.Pin
}
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build tinygo && (rp2040 || stm32 || k210 || esp32c3 || nrf || sam || (avr && (atmega328p || atmega328pb)))
//go:build tinygo && (rp2040 || rp2350 || stm32 || k210 || esp32c3 || nrf || sam || (avr && (atmega328p || atmega328pb)))
// Implementation based on:
// https://gist.github.com/aykevl/3fc1683ed77bb0a9c07559dfe857304a
+49
View File
@@ -0,0 +1,49 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/honeyhsc"
)
// Data taken from https://github.com/rodan/honeywell_hsc_ssc_i2c/blob/master/hsc_ssc_i2c.cpp
// these defaults are valid for the HSCMRNN030PA2A3 chip
const (
i2cAddress = 0x28
// 10%
outputMinimum = 0x666
// 90% of 2^14 - 1
outputMax = 0x399A
// min is 0 for sensors that give absolute values
pressureMin = 0
// 30psi (and we want results in millipascals)
// pressureMax = 206842.7
pressureMax = 206843 * 1000
)
func main() {
bus := machine.I2C0
err := bus.Configure(machine.I2CConfig{
Frequency: 400_000, // 100kHz minimum and 400kHz I2C maximum clock. 50 to 800 for SPI.
SDA: machine.I2C0_SDA_PIN,
SCL: machine.I2C0_SCL_PIN,
})
if err != nil {
panic(err.Error())
}
sensor := honeyhsc.NewDevI2C(bus, i2cAddress, outputMinimum, outputMax, pressureMin, pressureMax)
for {
time.Sleep(time.Second)
const measuremask = drivers.Pressure | drivers.Temperature
err := sensor.Update(measuremask)
if err != nil {
println("error updating measurements:", err.Error())
continue
}
P := sensor.Pressure()
T := sensor.Temperature()
println("pressure:", P, "temperature:", T)
}
}
+12 -3
View File
@@ -14,9 +14,18 @@ func main() {
i2c.Configure(machine.I2CConfig{SCL: machine.SCL1_PIN, SDA: machine.SDA1_PIN})
accel := lis3dh.New(i2c)
accel.Address = lis3dh.Address1 // address on the Circuit Playground Express
accel.Configure()
accel.SetRange(lis3dh.RANGE_2_G)
err := accel.Configure(lis3dh.Config{
Address: lis3dh.Address1, // address on the Circuit Playground Express
})
for err != nil {
println("could not configure LIS3DH:", err)
time.Sleep(time.Second)
}
err = accel.SetRange(lis3dh.RANGE_2_G)
for err != nil {
println("could not set acceleration range:", err)
time.Sleep(time.Second)
}
println(accel.Connected())
+9 -12
View File
@@ -5,6 +5,8 @@
package ft6336
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/touch"
@@ -12,21 +14,19 @@ import (
// Device wraps FT6336 I2C Self-Capacitive touch
type Device struct {
bus drivers.I2C
buf []byte
Address uint8
configurePins func()
bus drivers.I2C
buf []byte
Address uint8
intPin machine.Pin
}
// New returns FT6336 device for the provided I2C bus using default address.
func New(i2c drivers.I2C, intPin drivers.PinInput) *Device {
func New(i2c drivers.I2C, intPin machine.Pin) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 11),
Address: Address,
configurePins: func() {
legacy.ConfigurePinInputPulldown(intPin)
},
intPin: intPin,
}
}
@@ -36,11 +36,8 @@ type Config struct {
// Configure the FT6336 device.
func (d *Device) Configure(config Config) error {
if d.configurePins == nil {
return legacy.ErrConfigBeforeInstantiated
}
d.write1Byte(0xA4, 0x00)
d.configurePins()
d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
return nil
}
+15 -15
View File
@@ -5,12 +5,12 @@ package gc9a01 // import "tinygo.org/x/drivers/gc9a01"
import (
"image/color"
"machine"
"time"
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Rotation controls the rotation used by the display.
@@ -22,10 +22,10 @@ type FrameRate uint8
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutputFunc
resetPin drivers.PinOutputFunc
csPin drivers.PinOutputFunc
blPin drivers.PinOutputFunc
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
blPin machine.Pin
width int16
height int16
columnOffsetCfg int16
@@ -52,17 +52,17 @@ type Config struct {
}
// New creates a new ST7789 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) Device {
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
return Device{
bus: bus,
resetPin: resetPin.Set,
dcPin: dcPin.Set,
csPin: csPin.Set,
blPin: blPin.Set,
resetPin: resetPin,
dcPin: dcPin,
csPin: csPin,
blPin: blPin,
}
}
@@ -226,7 +226,7 @@ func (d *Device) Data(data uint8) {
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.dcPin(!isCommand)
d.dcPin.Set(!isCommand)
d.bus.Tx(data, nil)
}
+10 -19
View File
@@ -5,39 +5,30 @@
package hcsr04
import (
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
const TIMEOUT = 23324 // max sensing distance (4m)
// Device holds the pins
type Device struct {
trigger drivers.PinOutputFunc
echo drivers.PinInputFunc
configurePins func()
trigger machine.Pin
echo machine.Pin
}
// New returns a new ultrasonic driver given 2 pins
func New(trigger drivers.PinOutput, echo drivers.PinInput) Device {
func New(trigger, echo machine.Pin) Device {
return Device{
trigger: trigger.Set,
echo: echo.Get,
configurePins: func() {
legacy.ConfigurePinOut(trigger)
legacy.ConfigurePinInput(echo)
},
trigger: trigger,
echo: echo,
}
}
// Configure configures the pins of the Device
func (d *Device) Configure() {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
d.trigger.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.echo.Configure(machine.PinConfig{Mode: machine.PinInput})
}
// ReadDistance returns the distance of the object in mm
@@ -61,7 +52,7 @@ func (d *Device) ReadPulse() int32 {
d.trigger.Low()
i := uint8(0)
for {
if d.echo() {
if d.echo.Get() {
t = time.Now()
break
}
@@ -75,7 +66,7 @@ func (d *Device) ReadPulse() int32 {
}
i = 0
for {
if !d.echo() {
if !d.echo.Get() {
return int32(time.Since(t).Microseconds())
}
i++
+5 -5
View File
@@ -210,7 +210,7 @@ func (d *Device) SendCommand(command byte) {
d.bus.SetCommandMode(true)
d.bus.Write([]byte{command})
for d.isBusy(command == DISPLAY_CLEAR || command == CURSOR_HOME) {
for d.busy(command == DISPLAY_CLEAR || command == CURSOR_HOME) {
}
}
@@ -219,7 +219,7 @@ func (d *Device) sendData(data byte) {
d.bus.SetCommandMode(false)
d.bus.Write([]byte{data})
for d.isBusy(false) {
for d.busy(false) {
}
}
@@ -231,9 +231,9 @@ func (d *Device) CreateCharacter(cgramAddr uint8, data []byte) {
}
}
// isBusy returns true when hd447890 is isBusy
// busy returns true when hd447890 is busy
// or after the timeout specified
func (d *Device) isBusy(longDelay bool) bool {
func (d *Device) busy(longDelay bool) bool {
if d.bus.WriteOnly() {
// Can't read busy flag if write only, so sleep a bit then return
if longDelay {
@@ -261,7 +261,7 @@ func (d *Device) isBusy(longDelay bool) bool {
// Busy returns true when hd447890 is busy
func (d *Device) Busy() bool {
return d.isBusy(false)
return d.busy(false)
}
// Size returns the current size of the display.
+191
View File
@@ -0,0 +1,191 @@
package honeyhsc
import (
"errors"
"math"
"tinygo.org/x/drivers"
)
var (
errSensorMissing = errors.New("hsc: not connected")
errDiagnostic = errors.New("hsc: diagnostic error")
)
const (
measuremask = drivers.Pressure | drivers.Temperature
statusMask = 0b1100_0000
statusOffset = 6
)
// DevI2C is the TruStability® High Accuracy Silicon Ceramic (HSC) Series is a piezoresistive silicon pressure sensor offering a ratiometric
// analog or digital output for reading pressure over the specified full scale pressure span and temperature range.
type DevI2C struct {
bus drivers.I2C
dev
addr uint8
buf [6]byte
}
// NewDevI2C creates and returns a new DevI2C that communicates with an HSC device over the provided I2C bus.
// Parameters:
// - bus: the I2C bus to use.
// - addr: the 7-bit I2C address of the sensor.
// - outMin, outMax: raw output code range (counts) corresponding to the pressure span. Depends on sensor model.
// - pMin, pMax: pressure range endpoints in millipascals (mPa). Depends on sensor model.
//
// The returned DevI2C will use these calibration parameters to convert raw bridge counts to pressure.
func NewDevI2C(bus drivers.I2C, addr, outMin, outMax uint16, pMin, pMax int32) *DevI2C {
h := &DevI2C{
bus: bus,
addr: uint8(addr),
dev: dev{
cmin: outMin,
cmax: outMax,
pmin: pMin,
pmax: pMax,
},
}
return h
}
// ReadTemperature reads and returns the temperature in milliKelvin (mC) from the I2C-attached HSC device.
// It performs an Update internally to get the latest temperature value.
func (h *DevI2C) ReadTemperature() (int32, error) {
err := h.Update(drivers.Temperature)
if err != nil {
return 0, err
}
return h.Temperature(), nil
}
// Update reads both temperature and pressure data from the I2C-attached HSC device when
// the requested measurement mask includes pressure or temperature.
// If neither pressure nor temperature is requested, Update is a no-op.
func (d *DevI2C) Update(which drivers.Measurement) error {
// Update performs an I2C transaction to read 4 bytes, parses the status bits, 14-bit bridge data and
// temperature bits, and forwards them to the internal update routine. Any I2C transport error is returned,
// as well as errors produced by the internal update (e.g. errSensorMissing, errDiagnostic).
if which&measuremask == 0 {
return nil
}
rbuf := d.buf[:4]
wbuf := d.buf[4:6]
const reg = 0
value := (d.addr << 1) | 1
wbuf[0] = reg
wbuf[1] = value
err := d.bus.Tx(uint16(d.addr), wbuf, rbuf)
if err != nil {
return err
}
status := (rbuf[0] & statusMask) >> statusOffset
bridgeData := (uint16(rbuf[0]&^statusMask) << 8) | uint16(rbuf[1])
tempData := uint16(rbuf[2])<<8 | uint16(rbuf[3]&0xe0)>>5
return d.dev.update(status, bridgeData, tempData)
}
type pinout func(level bool)
// DevI2C is the TruStability® High Accuracy Silicon Ceramic (HSC) Series is a piezoresistive silicon pressure sensor offering a ratiometric
// analog or digital output for reading pressure over the specified full scale pressure span and temperature range.
type DevSPI struct {
spi drivers.SPI
cs pinout
dev
buf [4]byte
}
// NewDevSPI creates and returns a new DevSPI that communicates with an HSC device over SPI.
// Parameters:
// - conn: the SPI connection to use.
// - cs: a chip-select function that drives the device select line low/high.
// - outMin, outMax: raw output code range (counts) corresponding to the pressure span. Depends on sensor model.
// - pMin, pMax: pressure range endpoints in millipascals (mPa). Depends on sensor model.
//
// The function returns the constructed DevSPI and an error value (currently always nil).
func NewDevSPI(conn drivers.SPI, cs pinout, outMin, outMax uint16, pMin, pMax int32) (*DevSPI, error) {
h := &DevSPI{
spi: conn,
cs: cs,
dev: dev{
cmin: outMin,
cmax: outMax,
pmin: pMin,
pmax: pMax,
},
}
return h, nil
}
// ReadTemperature reads and returns the temperature in milliKelvin (mC) from the SPI-attached HSC device.
// It performs an Update internally to get the latest temperature value.
func (h *DevSPI) ReadTemperature() (int32, error) {
err := h.Update(drivers.Temperature)
if err != nil {
return 0, err
}
return h.Temperature(), nil
}
// Update reads pressure and temperature data from the SPI-attached HSC device when the requested measurement mask includes
// pressure or temperature. If neither pressure nor temperature is requested, Update is a no-op.
func (h *DevSPI) Update(which drivers.Measurement) error {
// It toggles the provided chip-select, performs an SPI transfer to read 4 bytes, parses the status bits,
// 14-bit bridge data and temperature bits, and forwards them to the internal update routine. Any SPI
// transport error is returned, as well as errors produced by the internal update (e.g. errSensorMissing, errDiagnostic).
if which&measuremask == 0 {
return nil
}
buf := &h.buf
h.cs(false)
err := h.spi.Tx(nil, buf[:4])
h.cs(true)
if err != nil {
return err
}
// First two bits are status bits.
status := (buf[0] & statusMask) >> statusOffset
bridgeData := (uint16(buf[0]&^statusMask) << 8) | uint16(buf[1])
tempData := uint16(buf[2])<<8 | uint16(buf[3]&0xe0)>>5
return h.dev.update(status, bridgeData, tempData)
}
type dev struct {
pressure int32
temp int32
cmin, cmax uint16
pmin, pmax int32
}
// Pressure returns the most recently computed pressure value in millipascals (mPa).
// The value is taken from the last successful Update.
func (d *dev) Pressure() int32 {
return d.pressure
}
// Temperature returns the most recently read temperature value in milliKelvin (mC).
// The value is taken from the last successful Update.
func (d *dev) Temperature() int32 {
return d.temp + 273_150
}
// update interprets raw sensor fields (status, bridgeData, tempData) and updates the dev's stored
// pressure and temperature. It returns errSensorMissing when the temperature raw value indicates no sensor
// (tempData == math.MaxUint16), errDiagnostic when the status indicates a device diagnostic condition
// (status == 3), or nil on success. Pressure is computed with integer arithmetic using the configured
// cmin/cmax -> pmin/pmax linear mapping in order to avoid overflows.
func (d *dev) update(status uint8, bridgeData, tempData uint16) error {
if tempData == math.MaxUint16 {
return errSensorMissing
} else if status == 3 {
return errDiagnostic
}
// Take care not to overflow here.
p := (int32(bridgeData)-int32(d.cmin))*(d.pmax-d.pmin)/int32(d.cmax-d.cmin) + d.pmin
d.temp = int32(tempData)
d.pressure = p
return nil
}
@@ -3,15 +3,23 @@ package legacy
import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
)
// The pingconfig group of files serve to abstract away
// pin configuration calls on the machine.Pin type.
// It was observed this way of developing drivers was
// non-portable and unusable on "big" Go projects so
// future projects should NOT configure pins in driver code.
// Users must configure pins before passing them as arguments
// to drivers.
// ConfigurePinOut is a legacy function used to configure pins as outputs.
//
// Deprecated: Do not configure pins in drivers.
// This is a legacy feature and should only be used by drivers that
// previously configured pins in initialization to avoid breaking users.
func ConfigurePinOut(po drivers.PinOutput) {
func ConfigurePinOut(po pin.Output) {
configurePinOut(po)
}
@@ -20,7 +28,7 @@ func ConfigurePinOut(po drivers.PinOutput) {
// Deprecated: Do not configure pins in drivers.
// This is a legacy feature and should only be used by drivers that
// previously configured pins in initialization to avoid breaking users.
func ConfigurePinInputPulldown(pi drivers.PinInput) {
func ConfigurePinInputPulldown(pi pin.Input) {
configurePinInputPulldown(pi)
}
@@ -29,7 +37,7 @@ func ConfigurePinInputPulldown(pi drivers.PinInput) {
// Deprecated: Do not configure pins in drivers.
// This is a legacy feature and should only be used by drivers that
// previously configured pins in initialization to avoid breaking users.
func ConfigurePinInput(pi drivers.PinInput) {
func ConfigurePinInput(pi pin.Input) {
configurePinInput(pi)
}
@@ -38,7 +46,7 @@ func ConfigurePinInput(pi drivers.PinInput) {
// Deprecated: Do not configure pins in drivers.
// This is a legacy feature and should only be used by drivers that
// previously configured pins in initialization to avoid breaking users.
func ConfigurePinInputPullup(pi drivers.PinInput) {
func ConfigurePinInputPullup(pi pin.Input) {
configurePinInputPullup(pi)
}
+15
View File
@@ -0,0 +1,15 @@
//go:build !tinygo
package legacy
import "tinygo.org/x/drivers/internal/pin"
// This file compiles for non-tinygo builds
// for use with "big" or "upstream" Go where
// there is no machine package.
func configurePinOut(p pin.Output) {}
func configurePinInput(p pin.Input) {}
func configurePinInputPulldown(p pin.Input) {}
func configurePinInputPullup(p pin.Input) {}
func pinIsNoPin(a any) bool { return false }
@@ -5,22 +5,22 @@ package legacy
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
)
func configurePinOut(po drivers.PinOutput) {
func configurePinOut(po pin.Output) {
configurePin(po, machine.PinOutput)
}
func configurePinInputPulldown(pi drivers.PinInput) {
func configurePinInputPulldown(pi pin.Input) {
configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput.
}
func configurePinInput(pi drivers.PinInput) {
func configurePinInput(pi pin.Input) {
configurePin(pi, machine.PinInput)
}
func configurePinInputPullup(pi drivers.PinInput) {
func configurePinInputPullup(pi pin.Input) {
configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput.
}
-13
View File
@@ -1,13 +0,0 @@
//go:build !baremetal
package legacy
import (
"tinygo.org/x/drivers"
)
func configurePinOut(p drivers.PinOutput) {}
func configurePinInput(p drivers.PinInput) {}
func configurePinInputPulldown(p drivers.PinInput) {}
func configurePinInputPullup(p drivers.PinInput) {}
func pinIsNoPin(a any) bool { return false }
+72
View File
@@ -0,0 +1,72 @@
// package pin implements a TinyGo Pin HAL.
// It serves to eliminate machine.Pin from driver constructors
// so that drivers can be used in "big" Go projects where
// there is no machine package.
// This file contains both function and interface-style Pin HAL definitions.
package pin
// OutputFunc is hardware abstraction for a pin which outputs a
// digital signal (high or low level).
//
// // Code conversion demo: from machine.Pin to pin.OutputFunc
// led := machine.LED
// led.Configure(machine.PinConfig{Mode: machine.Output})
// var pin pin.OutputFunc = led.Set // Going from a machine.Pin to a pin.OutputFunc
//
// This is an alternative to [Output] which is an interface type.
type OutputFunc func(level bool)
// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true).
func (setPin OutputFunc) High() {
setPin(true)
}
// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false).
func (setPin OutputFunc) Low() {
setPin(false)
}
// InputFunc is hardware abstraction for a pin which receives a
// digital signal and reads it (high or low level).
//
// // Code conversion demo: from machine.Pin to pin.InputFunc
// input := machine.LED
// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.Input
// var pin pin.InputFunc = input.Get // Going from a machine.Pin to a pin.InputFunc
//
// This is an alternative to [Input] which is an interface type.
type InputFunc func() (level bool)
// // Below is an example on how to define a input/output pin HAL for a
// // pin that must switch between input and output mode:
//
// var pinIsOutput bool
// var po PinOutputFunc = func(b bool) {
// if !pinIsOutput {
// pin.Configure(outputMode)
// pinIsOutput = true
// }
// pin.Set(b)
// }
//
// var pi PinInputFunc = func() bool {
// if pinIsOutput {
// pin.Configure(inputMode)
// pinIsOutput = false
// }
// return pin.Get()
// }
// Output interface represents a pin hardware abstraction layer for a pin that can output a digital signal.
//
// This is an alternative to [OutputFunc] abstraction which is a function type.
type Output interface {
Set(level bool)
}
// Input interface represents a pin hardware abstraction layer for a pin that can read a digital signal.
//
// This is an alternative to [InputFunc] abstraction which is a function type.
type Input interface {
Get() (level bool)
}
@@ -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
+196
View File
@@ -0,0 +1,196 @@
// Package regmap provides transaction-based interfaces for reading and writing
// to device registers over I2C and SPI buses with pre-allocated buffers.
package regmap
import (
"errors"
"tinygo.org/x/drivers"
)
var (
// errNotInTx indicates an operation was attempted outside of an active transaction.
errNotInTx = errors.New("device not in Tx")
// errInTx indicates a transaction was started while another is still active.
errInTx = errors.New("device already in Tx")
// errShortWriteBuffer indicates the write buffer is too small for the requested operation.
errShortWriteBuffer = errors.New("device write buffer too short")
// errShortReadBuffer indicates the read buffer is too small for the requested operation.
errShortReadBuffer = errors.New("device read buffer too short")
)
// Device8Txer wraps a Device8 to provide buffered transaction support for
// I2C and SPI operations. It maintains pre-allocated buffers to avoid heap
// allocations during register access operations.
//
// Users must call SetBuffers to configure the write and read buffers before
// initiating transactions.
type Device8Txer struct {
Device8
writeBuf []byte // Pre-allocated buffer for write operations
readBuf []byte // Pre-allocated buffer for read operations
inTx bool // Tracks whether a transaction is currently active
}
// SetTxBuffers configures the write and read buffers for this device.
// These buffers are reused across transactions to avoid heap allocations.
//
// The writebuf should be large enough to hold the register address plus
// all data bytes to be written in a single transaction.
func (d *Device8Txer) SetTxBuffers(writebuf, readbuf []byte) {
d.readBuf = readbuf
d.writeBuf = writebuf
}
// Tx8 represents an active transaction for an 8-bit register device.
// It tracks the write buffer and current offset as data is added to the transaction.
//
// Use AddWriteByte or AddWriteData to add data to the transaction, then call
// DoTxI2C or DoTxSPI to execute the transaction over the bus.
type Tx8 struct {
dw *Device8Txer // Reference to the parent device
off int // Current offset in the write buffer
}
// Tx initiates a new transaction for writing to the specified register address.
//
// Parameters:
// - writeAddr: The 8-bit register address to write to
//
// Returns a Tx8 handle that can be used to add data and execute the transaction.
//
// Returns an error if:
// - A transaction is already active (errInTx)
// - The write buffer is too short (errShortWriteBuffer)
func (dw *Device8Txer) Tx(writeAddr uint8) (Tx8, error) {
if dw.inTx {
return Tx8{}, errInTx
} else if len(dw.writeBuf) < 1 {
return Tx8{}, errShortWriteBuffer
}
dw.writeBuf[0] = writeAddr
return Tx8{dw: dw, off: 1}, nil
}
// AddWriteData appends multiple bytes to the current transaction's write buffer.
//
// Parameters:
// - buf: Variable number of bytes to add to the transaction
//
// Returns an error if:
// - No transaction is active (errNotInTx)
// - The write buffer doesn't have enough space (errShortWriteBuffer)
func (tx *Tx8) AddWriteData(buf ...byte) error {
if !tx.dw.inTx {
return errNotInTx
}
avail := tx.dw.writeBuf[tx.off:]
if len(avail) < len(buf) {
return errShortWriteBuffer
}
n := copy(avail, buf)
tx.off += n
return nil
}
// AddWriteByte appends a single byte to the current transaction's write buffer.
//
// Parameters:
// - b: The byte to add to the transaction
//
// Returns an error if:
// - No transaction is active (errNotInTx)
// - The write buffer doesn't have enough space (errShortWriteBuffer)
func (tx *Tx8) AddWriteByte(b byte) error {
if !tx.dw.inTx {
return errNotInTx
}
avail := tx.dw.writeBuf[tx.off:]
if len(avail) < 1 {
return errShortWriteBuffer
}
avail[0] = b
tx.off++
return nil
}
// DoTxI2C executes the transaction over an I2C bus.
//
// This performs a combined write-read I2C transaction, first sending the
// register address and any data added to the transaction, then reading
// the specified number of bytes from the device.
//
// Parameters:
// - bus: The I2C bus to communicate over
// - deviceAddr: The I2C address of the target device
// - readLength: Number of bytes to read from the device
//
// Returns the read data as a slice of the internal read buffer, valid until
// the next transaction. The transaction is automatically freed after execution.
//
// Returns an error if:
// - No transaction is active (errNotInTx)
// - The read buffer is too short (errShortReadBuffer)
// - The I2C transaction fails
func (tx *Tx8) DoTxI2C(bus drivers.I2C, deviceAddr uint16, readLength int) ([]byte, error) {
if tx.off == 0 || !tx.dw.inTx {
return nil, errNotInTx
}
defer tx.freeTx()
if len(tx.dw.readBuf) < readLength {
return nil, errShortReadBuffer
}
rbuf := tx.dw.readBuf[:readLength]
err := bus.Tx(deviceAddr, tx.dw.writeBuf[:tx.off], rbuf)
if err != nil {
return nil, err
}
return rbuf, err
}
// DoTxSPI executes the transaction over an SPI bus.
//
// This performs a full-duplex SPI transaction, simultaneously writing the
// register address and data while reading the same number of bytes from the device.
//
// If no read buffer was configured (readBuf is nil), this performs a write-only
// transaction and returns nil without error.
//
// Parameters:
// - bus: The SPI bus to communicate over
//
// Returns the read data as a slice of the internal read buffer (same length as
// the write data), valid until the next transaction. The transaction is
// automatically freed after execution.
//
// Returns an error if:
// - No transaction is active (errNotInTx)
// - The read buffer is too short (errShortReadBuffer)
// - The SPI transaction fails
func (tx *Tx8) DoTxSPI(bus drivers.SPI) (readBuf []byte, err error) {
if tx.off == 0 || !tx.dw.inTx {
return nil, errNotInTx
}
defer tx.freeTx()
if tx.dw.readBuf == nil {
err = bus.Tx(tx.dw.writeBuf[:tx.off], nil) // Special case, only use write buffer functionality.
return nil, err
} else if len(readBuf) < tx.off {
return nil, errShortReadBuffer
}
rbuf := tx.dw.readBuf[:tx.off]
err = bus.Tx(tx.dw.writeBuf[:tx.off], rbuf)
if err != nil {
return nil, err
}
return rbuf, err
}
// freeTx marks the transaction as complete, allowing a new transaction to be started.
// This is called internally by DoTxI2C and DoTxSPI after the transaction completes.
func (tx *Tx8) freeTx() {
tx.dw.inTx = false
}
+123
View File
@@ -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)
}
+34
View File
@@ -0,0 +1,34 @@
package regmap
import (
"fmt"
"tinygo.org/x/drivers"
)
func ExampleDevice8Txer() {
// Initialization.
var dtx Device8Txer
dtx.SetTxBuffers(make([]byte, 256), make([]byte, 256))
// Usage.
const (
defaultAddr = 65
REG_WRITE = 0x1f
IOCTL_CALL = 0xc0
)
tx, err := dtx.Tx(REG_WRITE)
if err != nil {
panic(err)
}
err = tx.AddWriteData(IOCTL_CALL, 0x80, 0x80)
if err != nil {
panic(err)
}
var bus drivers.I2C
readData, err := tx.DoTxI2C(bus, defaultAddr, 20)
if err != nil {
panic(err)
}
fmt.Println(readData)
}
+115 -36
View File
@@ -11,37 +11,57 @@ import (
// Device wraps an I2C connection to a LIS3DH device.
type Device struct {
bus drivers.I2C
Address uint16
address uint16
r Range
accel [6]byte // stored acceleration data (from the Update call)
}
// Driver configuration, used for the Configure call. All fields are optional.
type Config struct {
Address uint16
}
// New creates a new LIS3DH connection. The I2C bus must already be configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{bus: bus, Address: Address0}
return Device{bus: bus, address: Address0}
}
// Configure sets up the device for communication
func (d *Device) Configure() {
func (d *Device) Configure(config Config) error {
if config.Address != 0 {
d.address = config.Address
}
// enable all axes, normal mode
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL1, []byte{0x07})
err := legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL1, []byte{0x07})
if err != nil {
return err
}
// 400Hz rate
d.SetDataRate(DATARATE_400_HZ)
err = d.SetDataRate(DATARATE_400_HZ)
if err != nil {
return err
}
// High res & BDU enabled
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL4, []byte{0x88})
err = legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL4, []byte{0x88})
if err != nil {
return err
}
// get current range
d.r = d.ReadRange()
d.r, err = d.ReadRange()
return err
}
// Connected returns whether a LIS3DH has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
err := legacy.ReadRegister(d.bus, uint8(d.address), WHO_AM_I, data)
if err != nil {
return false
}
@@ -49,46 +69,51 @@ func (d *Device) Connected() bool {
}
// SetDataRate sets the speed of data collected by the LIS3DH.
func (d *Device) SetDataRate(rate DataRate) {
func (d *Device) SetDataRate(rate DataRate) error {
ctl1 := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CTRL1, ctl1)
err := legacy.ReadRegister(d.bus, uint8(d.address), REG_CTRL1, ctl1)
if err != nil {
println(err.Error())
return err
}
// mask off bits
ctl1[0] &^= 0xf0
ctl1[0] |= (byte(rate) << 4)
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL1, ctl1)
return legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL1, ctl1)
}
// SetRange sets the G range for LIS3DH.
func (d *Device) SetRange(r Range) {
func (d *Device) SetRange(r Range) error {
ctl := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CTRL4, ctl)
err := legacy.ReadRegister(d.bus, uint8(d.address), REG_CTRL4, ctl)
if err != nil {
println(err.Error())
return err
}
// mask off bits
ctl[0] &^= 0x30
ctl[0] |= (byte(r) << 4)
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL4, ctl)
err = legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL4, ctl)
if err != nil {
return err
}
// store the new range
d.r = r
return nil
}
// ReadRange returns the current G range for LIS3DH.
func (d *Device) ReadRange() (r Range) {
func (d *Device) ReadRange() (r Range, err error) {
ctl := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CTRL4, ctl)
err = legacy.ReadRegister(d.bus, uint8(d.address), REG_CTRL4, ctl)
if err != nil {
println(err.Error())
return 0, err
}
// mask off bits
r = Range(ctl[0] >> 4)
r &= 0x03
return r
return r, nil
}
// ReadAcceleration reads the current acceleration from the device and returns
@@ -96,28 +121,17 @@ func (d *Device) ReadRange() (r Range) {
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (int32, int32, int32, error) {
x, y, z := d.ReadRawAcceleration()
divider := float32(1)
switch d.r {
case RANGE_16_G:
divider = 1365
case RANGE_8_G:
divider = 4096
case RANGE_4_G:
divider = 8190
case RANGE_2_G:
divider = 16380
}
return int32(float32(x) / divider * 1000000), int32(float32(y) / divider * 1000000), int32(float32(z) / divider * 1000000), nil
rawX, rawY, rawZ := d.ReadRawAcceleration()
x, y, z := normalizeRange(rawX, rawY, rawZ, d.r)
return x, y, z, nil
}
// ReadRawAcceleration returns the raw x, y and z axis from the LIS3DH
func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
legacy.WriteRegister(d.bus, uint8(d.Address), REG_OUT_X_L|0x80, nil)
legacy.WriteRegister(d.bus, uint8(d.address), REG_OUT_X_L|0x80, nil)
data := []byte{0, 0, 0, 0, 0, 0}
d.bus.Tx(d.Address, nil, data)
d.bus.Tx(d.address, nil, data)
x = int16((uint16(data[1]) << 8) | uint16(data[0]))
y = int16((uint16(data[3]) << 8) | uint16(data[2]))
@@ -125,3 +139,68 @@ func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
return
}
// Update the sensor values of the 'which' parameter. Only acceleration is
// supported at the moment.
func (d *Device) Update(which drivers.Measurement) error {
if which&drivers.Acceleration != 0 {
// Read raw acceleration values and store them in the driver.
err := legacy.WriteRegister(d.bus, uint8(d.address), REG_OUT_X_L|0x80, nil)
if err != nil {
return err
}
err = d.bus.Tx(d.address, nil, d.accel[:])
if err != nil {
return err
}
}
return nil
}
// Acceleration returns the last read acceleration in µg (micro-gravity).
// When one of the axes is pointing straight to Earth and the sensor is not
// moving the returned value will be around 1000000 or -1000000.
func (d *Device) Acceleration() (x, y, z int32) {
// Extract the raw 16-bit values.
rawX := int16((uint16(d.accel[1]) << 8) | uint16(d.accel[0]))
rawY := int16((uint16(d.accel[3]) << 8) | uint16(d.accel[2]))
rawZ := int16((uint16(d.accel[5]) << 8) | uint16(d.accel[4]))
// Normalize these values, to be in µg (micro-gravity).
return normalizeRange(rawX, rawY, rawZ, d.r)
}
// Convert raw 16-bit values to normalized 32-bit values while avoiding floats
// and divisions.
func normalizeRange(rawX, rawY, rawZ int16, r Range) (x, y, z int32) {
// We're going to convert the 16-bit raw values to values in the range
// -1000_000..1000_000. For now we're going to assume a range of 16G, we'll
// adjust that range later.
// The formula is derived as follows, and carefully selected to avoid
// overflow and integer divisions (the division will be optimized to a
// bitshift):
// x = x * 1000_000 / 2048
// x = x * (1000_000/64) / (2048/64)
// x = x * 15625 / 32
x = int32(rawX) * 15625 / 32
y = int32(rawY) * 15625 / 32
z = int32(rawZ) * 15625 / 32
// Now we need to normalize the three values, since we assumed 16G before.
shift := uint32(0)
switch r {
case RANGE_16_G:
shift = 0
case RANGE_8_G:
shift = 1
case RANGE_4_G:
shift = 2
case RANGE_2_G:
shift = 3
}
x >>= shift
y >>= shift
z >>= shift
return
}
+35 -28
View File
@@ -7,7 +7,6 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -28,7 +27,7 @@ type Device struct {
accelMultiplier int32
gyroMultiplier int32
magMultiplier int32
buf [6]uint8
buf [7]uint8 // up to 6 bytes for read + 1 byte for the register address
}
// Configuration for LSM9DS1 device.
@@ -61,10 +60,15 @@ func New(bus drivers.I2C) *Device {
// Case of boolean false and error nil means I2C is up,
// but "who am I" responses have unexpected values.
func (d *Device) Connected() bool {
data1, data2 := d.buf[:1], d.buf[1:2]
legacy.ReadRegister(d.bus, d.AccelAddress, WHO_AM_I, data1)
legacy.ReadRegister(d.bus, d.MagAddress, WHO_AM_I_M, data2)
return data1[0] == 0x68 && data2[0] == 0x3D
data, err := d.readBytes(d.AccelAddress, WHO_AM_I, 1)
if err != nil || data[0] != 0x68 {
return false
}
data, err = d.readBytes(d.MagAddress, WHO_AM_I_M, 1)
if err != nil || data[0] != 0x3D {
return false
}
return true
}
// ReadAcceleration reads the current acceleration from the device and returns
@@ -72,8 +76,7 @@ func (d *Device) Connected() bool {
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_X_L_XL, data)
data, err := d.readBytes(d.AccelAddress, OUT_X_L_XL, 6)
if err != nil {
return
}
@@ -88,8 +91,7 @@ func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_X_L_G, data)
data, err := d.readBytes(d.AccelAddress, OUT_X_L_G, 6)
if err != nil {
return
}
@@ -102,8 +104,7 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// ReadMagneticField reads the current magnetic field from the device and returns
// it in nT (nanotesla). 1 G (gauss) = 100_000 nT (nanotesla).
func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.MagAddress), OUT_X_L_M, data)
data, err := d.readBytes(d.MagAddress, OUT_X_L_M, 6)
if err != nil {
return
}
@@ -115,8 +116,7 @@ func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in Celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_TEMP_L, data)
data, err := d.readBytes(d.AccelAddress, OUT_TEMP_L, 2)
if err != nil {
return
}
@@ -167,20 +167,16 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
d.magMultiplier = 58
}
data := d.buf[:1]
// Configure accelerometer
// Sample rate & measurement range
data[0] = uint8(cfg.AccelSampleRate)<<5 | uint8(cfg.AccelRange)<<3
err = legacy.WriteRegister(d.bus, d.AccelAddress, CTRL_REG6_XL, data)
err = d.writeByte(d.AccelAddress, CTRL_REG6_XL, uint8(cfg.AccelSampleRate)<<5|uint8(cfg.AccelRange)<<3)
if err != nil {
return
}
// Configure gyroscope
// Sample rate & measurement range
data[0] = uint8(cfg.GyroSampleRate)<<5 | uint8(cfg.GyroRange)<<3
err = legacy.WriteRegister(d.bus, d.AccelAddress, CTRL_REG1_G, data)
err = d.writeByte(d.AccelAddress, CTRL_REG1_G, uint8(cfg.GyroSampleRate)<<5|uint8(cfg.GyroRange)<<3)
if err != nil {
return
}
@@ -190,33 +186,44 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Temperature compensation enabled
// High-performance mode XY axis
// Sample rate
data[0] = 0b10000000 | 0b01000000 | uint8(cfg.MagSampleRate)<<2
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG1_M, data)
err = d.writeByte(d.MagAddress, CTRL_REG1_M, 0b10000000|0b01000000|uint8(cfg.MagSampleRate)<<2)
if err != nil {
return
}
// Measurement range
data[0] = uint8(cfg.MagRange) << 5
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG2_M, data)
err = d.writeByte(d.MagAddress, CTRL_REG2_M, uint8(cfg.MagRange)<<5)
if err != nil {
return
}
// Continuous-conversion mode
// https://electronics.stackexchange.com/questions/237397/continuous-conversion-vs-single-conversion-mode
data[0] = 0b00000000
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG3_M, data)
err = d.writeByte(d.MagAddress, CTRL_REG3_M, 0b00000000)
if err != nil {
return
}
// High-performance mode Z axis
data[0] = 0b00001000
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG4_M, data)
err = d.writeByte(d.MagAddress, CTRL_REG4_M, 0b00001000)
if err != nil {
return
}
return nil
}
func (d *Device) readBytes(addr, reg, size uint8) ([]byte, error) {
d.buf[0] = reg
err := d.bus.Tx(uint16(addr), d.buf[0:1], d.buf[1:size+1])
if err != nil {
return nil, err
}
return d.buf[1 : size+1], nil
}
func (d *Device) writeByte(addr, reg, value uint8) error {
d.buf[0] = reg
d.buf[1] = value
return d.bus.Tx(uint16(addr), d.buf[0:2], nil)
}
+4 -3
View File
@@ -3,6 +3,7 @@ package max6675
import (
"errors"
"machine"
"tinygo.org/x/drivers"
)
@@ -13,16 +14,16 @@ var ErrThermocoupleOpen = errors.New("thermocouple input open")
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
cs machine.Pin
}
// Create a new Device to read from a MAX6675 thermocouple.
// Pins must be configured before use. Frequency for SPI
// should be 4.3MHz maximum.
func NewDevice(bus drivers.SPI, cs drivers.PinOutput) *Device {
func NewDevice(bus drivers.SPI, cs machine.Pin) *Device {
return &Device{
bus: bus,
cs: cs.Set,
cs: cs,
}
}
+9 -13
View File
@@ -3,35 +3,31 @@
package max72xx
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
configurePins func()
bus drivers.SPI
cs machine.Pin
}
// NewDriver creates a new max7219 connection. The SPI wire must already be configured
// The SPI frequency must not be higher than 10MHz.
// parameter cs: the datasheet also refers to this pin as "load" pin.
func NewDevice(bus drivers.SPI, cs drivers.PinOutput) *Device {
func NewDevice(bus drivers.SPI, cs machine.Pin) *Device {
return &Device{
bus: bus,
cs: cs.Set,
configurePins: func() {
legacy.ConfigurePinOut(cs)
},
cs: cs,
}
}
// Configure setups the pins.
func (driver *Device) Configure() {
if driver.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
driver.configurePins()
outPutConfig := machine.PinConfig{Mode: machine.PinOutput}
driver.cs.Configure(outPutConfig)
}
// SetScanLimit sets the scan limit. Maximum is 8.
+8 -15
View File
@@ -8,19 +8,18 @@ package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
import (
"errors"
"fmt"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps MCP2515 SPI CAN Module.
type Device struct {
spi SPI
cs drivers.PinOutputFunc
msg *CANMsg
mcpMode byte
configurePins func()
spi SPI
cs machine.Pin
msg *CANMsg
mcpMode byte
}
// CANMsg stores CAN message fields.
@@ -37,18 +36,15 @@ const (
)
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI, csPin drivers.PinOutput) *Device {
func New(b drivers.SPI, csPin machine.Pin) *Device {
d := &Device{
spi: SPI{
bus: b,
tx: make([]byte, 0, bufferSize),
rx: make([]byte, 0, bufferSize),
},
cs: csPin.Set,
cs: csPin,
msg: &CANMsg{},
configurePins: func() {
legacy.ConfigurePinOut(csPin)
},
}
return d
@@ -56,10 +52,7 @@ func New(b drivers.SPI, csPin drivers.PinOutput) *Device {
// Configure sets up the device for communication.
func (d *Device) Configure() {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
const beginTimeoutValue int = 10
+8 -7
View File
@@ -6,6 +6,7 @@ package pcd8544 // import "tinygo.org/x/drivers/pcd8544"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
@@ -14,9 +15,9 @@ import (
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutputFunc
rstPin drivers.PinOutputFunc
scePin drivers.PinOutputFunc
dcPin machine.Pin
rstPin machine.Pin
scePin machine.Pin
buffer []byte
width int16
height int16
@@ -29,12 +30,12 @@ type Config struct {
}
// New creates a new PCD8544 connection. The SPI bus must already be configured.
func New(bus drivers.SPI, dcPin, rstPin, scePin drivers.PinOutput) *Device {
func New(bus drivers.SPI, dcPin, rstPin, scePin machine.Pin) *Device {
return &Device{
bus: bus,
dcPin: dcPin.Set,
rstPin: rstPin.Set,
scePin: scePin.Set,
dcPin: dcPin,
rstPin: rstPin,
scePin: scePin,
}
}
-39
View File
@@ -1,39 +0,0 @@
package drivers
// PinOutput represents a pin hardware abstraction layer for a pin that can output a digital signal.
type PinOutput interface {
Set(level bool)
}
// PinInput represents a pin hardware abstraction layer.
type PinInput interface {
Get() (level bool)
}
// PinOutputFunc is hardware abstraction for a function that causes pin to output a
// digital signal (high or low level).
//
// // Code conversion demo: from machine.Pin to drivers.PinOutputFunc
// led := machine.LED
// led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// var pin drivers.PinOutputFunc = led.Set // Going from a machine.Pin to a drivers.PinOutputFunc
type PinOutputFunc func(level bool)
// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true).
func (po PinOutputFunc) High() {
po(true)
}
// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false).
func (po PinOutputFunc) Low() {
po(false)
}
// PinInputFunc is hardware abstraction for a pin which receives a
// digital signal and reads it (high or low level).
//
// // Code conversion demo: from machine.Pin to drivers.PinInputFunc
// input := machine.LED
// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.PinInput
// var pin drivers.PinInputFunc = input.Get // Going from a machine.Pin to a drivers.PinInputFunc
type PinInputFunc func() (level bool)
+12 -19
View File
@@ -2,8 +2,7 @@
package shiftregister
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"machine"
)
type NumberBit int8
@@ -17,10 +16,9 @@ const (
// Device holds pin number
type Device struct {
latch, clock, out drivers.PinOutputFunc // IC wiring
config func()
bits NumberBit // Pin number
mask uint32 // keep all pins state
latch, clock, out machine.Pin // IC wiring
bits NumberBit // Pin number
mask uint32 // keep all pins state
}
// ShiftPin is the implementation of the ShiftPin interface.
@@ -31,25 +29,20 @@ type ShiftPin struct {
}
// New returns a new shift output register device
func New(Bits NumberBit, Latch, Clock, Out drivers.PinOutput) *Device {
func New(Bits NumberBit, Latch, Clock, Out machine.Pin) *Device {
return &Device{
latch: Latch.Set,
clock: Clock.Set,
out: Out.Set,
latch: Latch,
clock: Clock,
out: Out,
bits: Bits,
config: func() {
legacy.ConfigurePinOut(Latch)
legacy.ConfigurePinOut(Clock)
legacy.ConfigurePinOut(Out)
},
}
}
// Configure set hardware configuration
func (d *Device) Configure() {
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.latch.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.clock.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.out.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.latch.High()
}
@@ -60,7 +53,7 @@ func (d *Device) WriteMask(mask uint32) {
d.latch.Low()
for i := 0; i < int(d.bits); i++ {
d.clock.Low()
d.out(mask&1 != 0)
d.out.Set(mask&1 != 0)
mask = mask >> 1
d.clock.High()
}
-2
View File
@@ -1,5 +1,3 @@
//go:build baremetal
package ssd1289
import "machine"
+16 -18
View File
@@ -7,9 +7,6 @@ import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Bus interface {
@@ -17,10 +14,10 @@ type Bus interface {
}
type Device struct {
rs drivers.PinOutputFunc
wr drivers.PinOutputFunc
cs drivers.PinOutputFunc
rst drivers.PinOutputFunc
rs machine.Pin
wr machine.Pin
cs machine.Pin
rst machine.Pin
bus Bus
}
@@ -29,20 +26,21 @@ const height = int16(320)
func New(rs machine.Pin, wr machine.Pin, cs machine.Pin, rst machine.Pin, bus Bus) Device {
d := Device{
rs: rs.Set,
wr: wr.Set,
cs: cs.Set,
rst: rst.Set,
rs: rs,
wr: wr,
cs: cs,
rst: rst,
bus: bus,
}
legacy.ConfigurePinOut(rs)
legacy.ConfigurePinOut(wr)
legacy.ConfigurePinOut(cs)
legacy.ConfigurePinOut(rst)
cs.Set(true)
rst.Set(true)
wr.Set(true)
rs.Configure(machine.PinConfig{Mode: machine.PinOutput})
wr.Configure(machine.PinConfig{Mode: machine.PinOutput})
cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
cs.High()
rst.High()
wr.High()
return d
}
+10 -11
View File
@@ -11,7 +11,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Model uint8
@@ -20,9 +19,9 @@ type Rotation uint8
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutputFunc
resetPin drivers.PinOutputFunc
csPin drivers.PinOutputFunc
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
width int16
height int16
batchLength int16
@@ -38,14 +37,14 @@ type Config struct {
// New creates a new SSD1331 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin machine.Pin) Device {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
return Device{
bus: bus,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: csPin.Set,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
}
}
@@ -252,7 +251,7 @@ func (d *Device) Data(data uint8) {
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.dcPin(!isCommand)
d.dcPin.Set(!isCommand)
d.bus.Tx(data, nil)
}
+24 -31
View File
@@ -6,10 +6,10 @@ package ssd1351 // import "tinygo.org/x/drivers/ssd1351"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
var (
@@ -19,18 +19,17 @@ var (
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutputFunc
resetPin drivers.PinOutputFunc
csPin drivers.PinOutputFunc
enPin drivers.PinOutputFunc
rwPin drivers.PinOutputFunc
configurePins func()
width int16
height int16
rowOffset int16
columnOffset int16
bufferLength int16
bus drivers.SPI
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
enPin machine.Pin
rwPin machine.Pin
width int16
height int16
rowOffset int16
columnOffset int16
bufferLength int16
}
// Config is the configuration for the display
@@ -42,29 +41,19 @@ type Config struct {
}
// New creates a new SSD1351 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, enPin, rwPin drivers.PinOutput) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, enPin, rwPin machine.Pin) Device {
return Device{
bus: bus,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: csPin.Set,
enPin: enPin.Set,
rwPin: rwPin.Set,
configurePins: func() {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(enPin)
legacy.ConfigurePinOut(rwPin)
},
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
enPin: enPin,
rwPin: rwPin,
}
}
// Configure initializes the display with default configuration
func (d *Device) Configure(cfg Config) {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
if cfg.Width == 0 {
cfg.Width = 128
}
@@ -84,7 +73,11 @@ func (d *Device) Configure(cfg Config) {
}
// configure GPIO pins
d.configurePins()
d.dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.enPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.rwPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
// reset the device
d.resetPin.High()
@@ -285,7 +278,7 @@ func (d *Device) Data(data uint8) {
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.dcPin(!isCommand)
d.dcPin.Set(!isCommand)
d.csPin.Low()
d.bus.Tx(data, nil)
d.csPin.High()
+16 -16
View File
@@ -5,12 +5,12 @@ package st7735 // import "tinygo.org/x/drivers/st7735"
import (
"image/color"
"machine"
"time"
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/pixel"
)
@@ -39,10 +39,10 @@ type Device = DeviceOf[pixel.RGB565BE]
// formats.
type DeviceOf[T Color] struct {
bus drivers.SPI
dcPin drivers.PinOutputFunc
resetPin drivers.PinOutputFunc
csPin drivers.PinOutputFunc
blPin drivers.PinOutputFunc
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
blPin machine.Pin
width int16
height int16
columnOffset int16
@@ -65,23 +65,23 @@ type Config struct {
}
// New creates a new ST7735 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
}
// NewOf creates a new ST7735 connection with a particular pixel format. The SPI
// wire must already be configured.
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) DeviceOf[T] {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
return DeviceOf[T]{
bus: bus,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: csPin.Set,
blPin: blPin.Set,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
blPin: blPin,
}
}
@@ -423,7 +423,7 @@ func (d *DeviceOf[T]) Data(data uint8) {
// Tx sends data to the display
func (d *DeviceOf[T]) Tx(data []byte, isCommand bool) {
d.dcPin(!isCommand)
d.dcPin.Set(!isCommand)
d.bus.Tx(data, nil)
}
+17 -21
View File
@@ -7,13 +7,13 @@ package st7789 // import "tinygo.org/x/drivers/st7789"
import (
"image/color"
"machine"
"math"
"time"
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/pixel"
)
@@ -46,10 +46,10 @@ type Device = DeviceOf[pixel.RGB565BE]
// formats.
type DeviceOf[T Color] struct {
bus drivers.SPI
dcPin drivers.PinOutputFunc
resetPin drivers.PinOutputFunc
csPin drivers.PinOutputFunc
blPin drivers.PinOutputFunc
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
blPin machine.Pin
width int16
height int16
columnOffsetCfg int16
@@ -83,27 +83,23 @@ type Config struct {
}
// New creates a new ST7789 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
}
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
// wire must already be configured.
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) DeviceOf[T] {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
var cs drivers.PinOutputFunc
if !legacy.PinIsNoPin(csPin) {
cs = csPin.Set
}
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
return DeviceOf[T]{
bus: bus,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: cs,
blPin: blPin.Set,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
blPin: blPin,
}
}
@@ -233,7 +229,7 @@ func (d *DeviceOf[T]) sendCommand(command uint8, data []byte) error {
// startWrite must be called at the beginning of all exported methods to set the
// chip select pin low.
func (d *DeviceOf[T]) startWrite() {
if d.csPin != nil {
if d.csPin != machine.NoPin {
d.csPin.Low()
}
}
@@ -241,7 +237,7 @@ func (d *DeviceOf[T]) startWrite() {
// endWrite must be called at the end of all exported methods to set the chip
// select pin high.
func (d *DeviceOf[T]) endWrite() {
if d.csPin != nil {
if d.csPin != machine.NoPin {
d.csPin.High()
}
}
+12 -11
View File
@@ -6,6 +6,7 @@ package sx127x
import (
"errors"
"machine"
"time"
"tinygo.org/x/drivers"
@@ -20,15 +21,15 @@ const (
// Device wraps an SPI connection to a SX127x device.
type Device struct {
spi drivers.SPI // SPI bus for module communication
rstPin drivers.PinOutputFunc // GPIO for reset
radioEventChan chan lora.RadioEvent // Channel for Receiving events
loraConf lora.Config // Current Lora configuration
controller RadioController // to manage interactions with the radio
deepSleep bool // Internal Sleep state
deviceType int // sx1261,sx1262,sx1268 (defaults sx1261)
spiTxBuf []byte // global Tx buffer to avoid heap allocations in interrupt
spiRxBuf []byte // global Rx buffer to avoid heap allocations in interrupt
spi drivers.SPI // SPI bus for module communication
rstPin machine.Pin // GPIO for reset
radioEventChan chan lora.RadioEvent // Channel for Receiving events
loraConf lora.Config // Current Lora configuration
controller RadioController // to manage interactions with the radio
deepSleep bool // Internal Sleep state
deviceType int // sx1261,sx1262,sx1268 (defaults sx1261)
spiTxBuf []byte // global Tx buffer to avoid heap allocations in interrupt
spiRxBuf []byte // global Rx buffer to avoid heap allocations in interrupt
}
// --------------------------------------------------
@@ -42,10 +43,10 @@ func (d *Device) GetRadioEventChan() chan lora.RadioEvent {
}
// New creates a new SX127x connection. The SPI bus must already be configured.
func New(spi drivers.SPI, rstPin drivers.PinOutput) *Device {
func New(spi drivers.SPI, rstPin machine.Pin) *Device {
k := Device{
spi: spi,
rstPin: rstPin.Set,
rstPin: rstPin,
radioEventChan: make(chan lora.RadioEvent, RADIOEVENTCHAN_SIZE),
spiTxBuf: make([]byte, SPI_BUFFER_SIZE),
spiRxBuf: make([]byte, SPI_BUFFER_SIZE),
+11 -5
View File
@@ -12,6 +12,7 @@ import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/pixel"
)
@@ -31,10 +32,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
cs pin.OutputFunc
dc pin.OutputFunc
rst pin.OutputFunc
isBusy pin.InputFunc
width int16
height int16
buffer []uint8
@@ -49,7 +50,12 @@ type Device struct {
type Speed uint8
// New returns a new uc8151 driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin drivers.PinOutput, busyPin drivers.PinInput) Device {
// Pins passed in must be configured beforehand.
func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device {
// For backwards compatibility.
// This driver used to configure pins,
// so leave in to not break users.
// May be removed in future so try not to depend on it!
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
+23 -32
View File
@@ -12,9 +12,6 @@ import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Config struct {
@@ -25,14 +22,14 @@ type Config struct {
}
type Device struct {
bus *machine.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
configurePins func()
buffer []uint8
rotation Rotation
bus *machine.SPI
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
buffer []uint8
rotation Rotation
}
type Rotation uint8
@@ -82,28 +79,22 @@ var partialRefresh = [159]uint8{
}
// New returns a new epd1in54 driver. Pass in a fully configured SPI bus.
func New(bus *machine.SPI, csPin, dcPin, rstPin drivers.PinOutput, busyPin drivers.PinInput) Device {
func New(bus *machine.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
return Device{
buffer: make([]uint8, (uint32(Width)*uint32(Height))/8),
bus: bus,
cs: csPin.Set,
dc: dcPin.Set,
rst: rstPin.Set,
isBusy: busyPin.Get,
configurePins: func() {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
},
cs: csPin,
dc: dcPin,
rst: rstPin,
busy: busyPin,
}
}
func (d *Device) LDirInit(cfg Config) {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.busy.Configure(machine.PinConfig{Mode: machine.PinInput})
d.bus.Configure(machine.SPIConfig{
Frequency: 2000000,
@@ -159,10 +150,10 @@ func (d *Device) LDirInit(cfg Config) {
}
func (d *Device) HDirInit(cfg Config) {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.busy.Configure(machine.PinConfig{Mode: machine.PinInput})
d.bus.Configure(machine.SPIConfig{
Frequency: 2000000,
@@ -378,7 +369,7 @@ func (d *Device) Clear() {
// WaitUntilIdle waits until the display is ready
func (d *Device) WaitUntilIdle() {
for d.isBusy() {
for d.busy.Get() {
time.Sleep(100 * time.Millisecond)
}
time.Sleep(200 * time.Millisecond)
@@ -386,7 +377,7 @@ func (d *Device) WaitUntilIdle() {
// IsBusy returns the busy status of the display
func (d *Device) IsBusy() bool {
return d.isBusy()
return d.busy.Get()
}
// ClearBuffer sets the buffer to 0xFF (white)
+17 -17
View File
@@ -6,10 +6,10 @@ package epd2in13 // import "tinygo.org/x/drivers/waveshare-epd/epd2in13"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Config struct {
@@ -21,10 +21,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
logicalWidth int16
width int16
height int16
@@ -53,17 +53,17 @@ var lutPartialUpdate = [30]uint8{
}
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin drivers.PinOutput, busyPin drivers.PinInput) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
return Device{
bus: bus,
cs: csPin.Set,
dc: dcPin.Set,
rst: rstPin.Set,
isBusy: busyPin.Get,
bus: bus,
cs: csPin,
dc: dcPin,
rst: rstPin,
busy: busyPin,
}
}
@@ -298,14 +298,14 @@ func (d *Device) setMemoryPointer(x int16, y int16) {
// WaitUntilIdle waits until the display is ready
func (d *Device) WaitUntilIdle() {
for d.isBusy() {
for d.busy.Get() {
time.Sleep(100 * time.Millisecond)
}
}
// IsBusy returns the busy status of the display
func (d *Device) IsBusy() bool {
return d.isBusy()
return d.busy.Get()
}
// ClearBuffer sets the buffer to 0xFF (white)
+17 -17
View File
@@ -6,10 +6,10 @@ package epd2in13x // import "tinygo.org/x/drivers/waveshare-epd/epd2in13x"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Config struct {
@@ -20,10 +20,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
width int16
height int16
buffer [][]uint8
@@ -33,17 +33,17 @@ type Device struct {
type Color uint8
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin drivers.PinOutput, busyPin drivers.PinInput) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
return Device{
bus: bus,
cs: csPin.Set,
dc: dcPin.Set,
rst: rstPin.Set,
isBusy: busyPin.Get,
bus: bus,
cs: csPin,
dc: dcPin,
rst: rstPin,
busy: busyPin,
}
}
@@ -277,14 +277,14 @@ func (d *Device) ClearDisplay() {
// WaitUntilIdle waits until the display is ready
func (d *Device) WaitUntilIdle() {
for !d.isBusy() {
for !d.busy.Get() {
time.Sleep(100 * time.Millisecond)
}
}
// IsBusy returns the busy status of the display
func (d *Device) IsBusy() bool {
return d.isBusy()
return d.busy.Get()
}
// ClearBuffer sets the buffer to 0xFF (white)
+29 -6
View File
@@ -5,6 +5,7 @@ package epd2in66b
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
@@ -17,12 +18,19 @@ const (
const Baudrate = 4_000_000 // 4 MHz
type Config struct {
ResetPin machine.Pin
DataPin machine.Pin
ChipSelectPin machine.Pin
BusyPin machine.Pin
}
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
bus drivers.SPI
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
blackBuffer []byte
redBuffer []byte
@@ -42,6 +50,21 @@ func New(bus drivers.SPI) Device {
}
}
// Configure configures the device and its pins.
func (d *Device) Configure(c Config) error {
d.cs = c.ChipSelectPin
d.dc = c.DataPin
d.rst = c.ResetPin
d.busy = c.BusyPin
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.busy.Configure(machine.PinConfig{Mode: machine.PinInput})
return nil
}
func (d *Device) Size() (x, y int16) {
return displayWidth, displayHeight
}
@@ -206,7 +229,7 @@ func (d *Device) WaitUntilIdle() {
// give it some time to get busy
time.Sleep(50 * time.Millisecond)
for d.isBusy() { // high = busy
for d.busy.Get() { // high = busy
time.Sleep(10 * time.Millisecond)
}
-30
View File
@@ -1,30 +0,0 @@
//go:build baremetal
package epd2in66b
import "machine"
type Config struct {
ResetPin machine.Pin
DataPin machine.Pin
ChipSelectPin machine.Pin
BusyPin machine.Pin
}
// Configure configures the device and its pins.
func (d *Device) Configure(c Config) error {
cs := c.ChipSelectPin
dc := c.DataPin
rst := c.ResetPin
busy := c.BusyPin
cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
busy.Configure(machine.PinConfig{Mode: machine.PinInput})
d.cs = cs.Set
d.dc = dc.Set
d.rst = rst.Set
d.isBusy = busy.Get
return nil
}
+17 -17
View File
@@ -13,10 +13,10 @@ package epd2in9 // import "tinygo.org/x/drivers/waveshare-epd/epd2in9"
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Config struct {
@@ -28,10 +28,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
logicalWidth int16
width int16
height int16
@@ -61,17 +61,17 @@ var lutPartialUpdate = [30]uint8{
}
// New returns a new epd2in9 driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin drivers.PinOutput, busyPin drivers.PinInput) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
return Device{
bus: bus,
cs: csPin.Set,
dc: dcPin.Set,
rst: rstPin.Set,
isBusy: busyPin.Get,
bus: bus,
cs: csPin,
dc: dcPin,
rst: rstPin,
busy: busyPin,
}
}
@@ -245,14 +245,14 @@ func (d *Device) setMemoryPointer(x int16, y int16) {
// WaitUntilIdle waits until the display is ready
func (d *Device) WaitUntilIdle() {
for d.isBusy() {
for d.busy.Get() {
time.Sleep(100 * time.Millisecond)
}
}
// IsBusy returns the busy status of the display
func (d *Device) IsBusy() bool {
return d.isBusy()
return d.busy.Get()
}
// ClearBuffer sets the buffer to 0xFF (white)
+17 -17
View File
@@ -10,10 +10,10 @@ package epd4in2
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Config struct {
@@ -25,10 +25,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutputFunc
dc drivers.PinOutputFunc
rst drivers.PinOutputFunc
isBusy drivers.PinInputFunc
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
logicalWidth int16
width int16
height int16
@@ -40,17 +40,17 @@ type Device struct {
type Rotation uint8
// New returns a new epd4in2 driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin drivers.PinOutput, busyPin drivers.PinInput) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
return Device{
bus: bus,
cs: csPin.Set,
dc: dcPin.Set,
rst: rstPin.Set,
isBusy: busyPin.Get,
bus: bus,
cs: csPin,
dc: dcPin,
rst: rstPin,
busy: busyPin,
}
}
@@ -311,14 +311,14 @@ func (d *Device) ClearDisplay() {
// WaitUntilIdle waits until the display is ready
func (d *Device) WaitUntilIdle() {
for d.isBusy() {
for d.busy.Get() {
time.Sleep(100 * time.Millisecond)
}
}
// IsBusy returns the busy status of the display
func (d *Device) IsBusy() bool {
return d.isBusy()
return d.busy.Get()
}
// ClearBuffer sets the buffer to 0xFF (white)