more drivers are now cross platform

This commit is contained in:
soypat
2025-07-02 22:03:58 -03:00
committed by deadprogram
parent 7d3404f060
commit cd37668592
20 changed files with 481 additions and 325 deletions
+4
View File
@@ -2,6 +2,7 @@ package apa102
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
@@ -18,6 +19,9 @@ type bbSPI struct {
// Configure sets up the SCK and SDO pins as outputs and sets them low
func (s *bbSPI) Configure() {
if s.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
s.config()
s.SCK(false)
s.SDO(false)
+24 -20
View File
@@ -11,12 +11,12 @@ import (
// also an I2C interface, but it is not yet supported.
type DeviceSPI struct {
// Chip select pin
CSB drivers.PinOutput
csb drivers.PinOutput
buf [7]byte
// SPI bus (requires chip select to be usable).
Bus drivers.SPI
bus drivers.SPI
config func()
}
@@ -25,8 +25,8 @@ type DeviceSPI struct {
// using this device.
func NewSPI(csb legacy.PinOutput, spi drivers.SPI) *DeviceSPI {
return &DeviceSPI{
CSB: csb.Set, // chip select
Bus: spi,
csb: csb.Set, // chip select
bus: spi,
config: func() {
legacy.ConfigurePinOut(csb)
},
@@ -37,7 +37,11 @@ func NewSPI(csb legacy.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 {
d.CSB(true)
if d.config == nil {
return legacy.ErrConfigBeforeInstantiated
}
d.config()
d.csb(true)
// The datasheet recommends doing a register read from address 0x7F to get
// SPI communication going:
@@ -89,9 +93,9 @@ func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
data[0] = 0x80 | reg_TEMPERATURE_0
data[1] = 0
data[2] = 0
d.CSB(false)
err = d.Bus.Tx(data, data)
d.CSB(true)
d.csb(false)
err = d.bus.Tx(data, data)
d.csb(true)
if err != nil {
return
}
@@ -126,9 +130,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(false)
err = d.Bus.Tx(data, data)
d.CSB(true)
d.csb(false)
err = d.bus.Tx(data, data)
d.csb(true)
if err != nil {
return
}
@@ -156,9 +160,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(false)
err = d.Bus.Tx(data, data)
d.CSB(true)
d.csb(false)
err = d.bus.Tx(data, data)
d.csb(true)
if err != nil {
return
}
@@ -204,9 +208,9 @@ func (d *DeviceSPI) readRegister(address uint8) uint8 {
data := d.buf[:2]
data[0] = 0x80 | address
data[1] = 0
d.CSB(false)
d.Bus.Tx(data, data)
d.CSB(true)
d.csb(false)
d.bus.Tx(data, data)
d.csb(true)
return data[1]
}
@@ -220,7 +224,7 @@ func (d *DeviceSPI) writeRegister(address, data uint8) {
buf[0] = address
buf[1] = data
d.CSB(false)
d.Bus.Tx(buf, buf)
d.CSB(true)
d.csb(false)
d.bus.Tx(buf, buf)
d.csb(true)
}
+55 -116
View File
@@ -1,10 +1,12 @@
//go:build baremetal
// Package easystepper provides a simple driver to rotate a 4-wire stepper motor.
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,28 +32,10 @@ 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]machine.Pin
pins [4]drivers.PinOutput
config func()
stepDelay time.Duration
stepNumber uint8
stepMode StepMode
@@ -62,51 +46,6 @@ 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) {
@@ -126,7 +65,7 @@ func (d *Device) Move(steps int32) {
// Off turns off all motor pins
func (d *Device) Off() {
for _, pin := range d.pins {
pin.Low()
pin(false)
}
}
@@ -187,28 +126,28 @@ func (d *Device) stepMotor(step uint8) {
func (d *Device) stepMotor4(step uint8) {
switch step {
case 0:
d.pins[0].High()
d.pins[1].Low()
d.pins[2].High()
d.pins[3].Low()
d.pins[0](true)
d.pins[1](false)
d.pins[2](true)
d.pins[3](false)
break
case 1:
d.pins[0].Low()
d.pins[1].High()
d.pins[2].High()
d.pins[3].Low()
d.pins[0](false)
d.pins[1](true)
d.pins[2](true)
d.pins[3](false)
break
case 2:
d.pins[0].Low()
d.pins[1].High()
d.pins[2].Low()
d.pins[3].High()
d.pins[0](false)
d.pins[1](true)
d.pins[2](false)
d.pins[3](true)
break
case 3:
d.pins[0].High()
d.pins[1].Low()
d.pins[2].Low()
d.pins[3].High()
d.pins[0](true)
d.pins[1](false)
d.pins[2](false)
d.pins[3](true)
break
}
d.stepNumber = step
@@ -218,45 +157,45 @@ func (d *Device) stepMotor4(step uint8) {
func (d *Device) stepMotor8(step uint8) {
switch step {
case 0:
d.pins[0].High()
d.pins[2].Low()
d.pins[1].Low()
d.pins[3].Low()
d.pins[0](true)
d.pins[2](false)
d.pins[1](false)
d.pins[3](false)
case 1:
d.pins[0].High()
d.pins[2].High()
d.pins[1].Low()
d.pins[3].Low()
d.pins[0](true)
d.pins[2](true)
d.pins[1](false)
d.pins[3](false)
case 2:
d.pins[0].Low()
d.pins[2].High()
d.pins[1].Low()
d.pins[3].Low()
d.pins[0](false)
d.pins[2](true)
d.pins[1](false)
d.pins[3](false)
case 3:
d.pins[0].Low()
d.pins[2].High()
d.pins[1].High()
d.pins[3].Low()
d.pins[0](false)
d.pins[2](true)
d.pins[1](true)
d.pins[3](false)
case 4:
d.pins[0].Low()
d.pins[2].Low()
d.pins[1].High()
d.pins[3].Low()
d.pins[0](false)
d.pins[2](false)
d.pins[1](true)
d.pins[3](false)
case 5:
d.pins[0].Low()
d.pins[2].Low()
d.pins[1].High()
d.pins[3].High()
d.pins[0](false)
d.pins[2](false)
d.pins[1](true)
d.pins[3](true)
case 6:
d.pins[0].Low()
d.pins[2].Low()
d.pins[1].Low()
d.pins[3].High()
d.pins[0](false)
d.pins[2](false)
d.pins[1](false)
d.pins[3](true)
case 7:
d.pins[0].High()
d.pins[2].Low()
d.pins[1].Low()
d.pins[3].High()
d.pins[0](true)
d.pins[2](false)
d.pins[1](false)
d.pins[3](true)
}
d.stepNumber = step
}
+83
View File
@@ -0,0 +1,83 @@
//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.PinOutput{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
}
+26
View File
@@ -0,0 +1,26 @@
package easystepper
import (
"errors"
"time"
"tinygo.org/x/drivers"
)
func NewCrossPlatform(stepcount, rpm uint, mode StepMode, pins [4]drivers.PinOutput) (*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
}
+9 -6
View File
@@ -5,8 +5,6 @@
package ft6336
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/touch"
@@ -17,16 +15,18 @@ type Device struct {
bus drivers.I2C
buf []byte
Address uint8
intPin machine.Pin
config func()
}
// New returns FT6336 device for the provided I2C bus using default address.
func New(i2c drivers.I2C, intPin machine.Pin) *Device {
func New(i2c drivers.I2C, intPin legacy.PinInput) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 11),
Address: Address,
intPin: intPin,
config: func() {
legacy.ConfigurePinInputPulldown(intPin)
},
}
}
@@ -36,8 +36,11 @@ type Config struct {
// Configure the FT6336 device.
func (d *Device) Configure(config Config) error {
if d.config == nil {
return legacy.ErrConfigBeforeInstantiated
}
d.write1Byte(0xA4, 0x00)
d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
d.config()
return nil
}
+25 -25
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 machine.Pin
resetPin machine.Pin
csPin machine.Pin
blPin machine.Pin
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
blPin drivers.PinOutput
width int16
height int16
columnOffsetCfg int16
@@ -52,27 +52,27 @@ 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 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})
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin legacy.PinOutput) Device {
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
return Device{
bus: bus,
resetPin: resetPin,
dcPin: dcPin,
csPin: csPin,
blPin: blPin,
resetPin: resetPin.Set,
dcPin: dcPin.Set,
csPin: csPin.Set,
blPin: blPin.Set,
}
}
// Reset the Device
func (d *Device) Reset() {
d.resetPin.High()
d.resetPin(true)
time.Sleep(100 * time.Millisecond)
d.resetPin.Low()
d.resetPin(false)
time.Sleep(100 * time.Millisecond)
d.resetPin.High()
d.resetPin(true)
time.Sleep(100 * time.Millisecond)
}
@@ -226,20 +226,20 @@ func (d *Device) Data(data uint8) {
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.dcPin.Set(!isCommand)
d.dcPin(!isCommand)
d.bus.Tx(data, nil)
}
// Rx reads data from the display
func (d *Device) Rx(command uint8, data []byte) {
d.dcPin.Low()
d.csPin.Low()
d.dcPin(false)
d.csPin(false)
d.bus.Transfer(command)
d.dcPin.High()
d.dcPin(true)
for i := range data {
data[i], _ = d.bus.Transfer(0xFF)
}
d.csPin.High()
d.csPin(true)
}
// Size returns the current size of the display.
@@ -250,9 +250,9 @@ func (d *Device) Size() (w, h int16) {
// EnableBacklight enables or disables the backlight
func (d *Device) EnableBacklight(enable bool) {
if enable {
d.blPin.High()
d.blPin(true)
} else {
d.blPin.Low()
d.blPin(false)
}
}
@@ -563,5 +563,5 @@ func (d *Device) Configure(cfg Config) {
d.Command(DISPON)
time.Sleep(20 * time.Millisecond)
d.blPin.High()
d.blPin(true)
}
+22 -13
View File
@@ -5,30 +5,39 @@
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 machine.Pin
echo machine.Pin
trigger drivers.PinOutput
echo drivers.PinInput
config func()
}
// New returns a new ultrasonic driver given 2 pins
func New(trigger, echo machine.Pin) Device {
func New(trigger legacy.PinOutput, echo legacy.PinInput) Device {
return Device{
trigger: trigger,
echo: echo,
trigger: trigger.Set,
echo: echo.Get,
config: func() {
legacy.ConfigurePinOut(trigger)
legacy.ConfigurePinInput(echo)
},
}
}
// Configure configures the pins of the Device
func (d *Device) Configure() {
d.trigger.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.echo.Configure(machine.PinConfig{Mode: machine.PinInput})
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.config()
}
// ReadDistance returns the distance of the object in mm
@@ -45,14 +54,14 @@ func (d *Device) ReadDistance() int32 {
// ReadPulse returns the time of the pulse (roundtrip) in microseconds
func (d *Device) ReadPulse() int32 {
t := time.Now()
d.trigger.Low()
d.trigger(false)
time.Sleep(2 * time.Microsecond)
d.trigger.High()
d.trigger(true)
time.Sleep(10 * time.Microsecond)
d.trigger.Low()
d.trigger(false)
i := uint8(0)
for {
if d.echo.Get() {
if d.echo() {
t = time.Now()
break
}
@@ -66,7 +75,7 @@ func (d *Device) ReadPulse() int32 {
}
i = 0
for {
if !d.echo.Get() {
if !d.echo() {
return int32(time.Since(t).Microseconds())
}
i++
+41 -2
View File
@@ -1,5 +1,7 @@
package legacy
import "errors"
// PinOutput represents a pin hardware abstraction layer for a pin that can output a digital signal.
// This is an alternative to drivers.PinOutput abstraction which is a function type. Pros and cons
// of both approaches have been discussed in the [relevant issue]. PinOutput should only be used
@@ -19,11 +21,48 @@ type PinOutput interface {
Set(level bool)
}
// PinInput represents a pin hardware abstraction layer. See [PinOutput] for
// more information on why this is "legacy".
type PinInput interface {
Get() (level bool)
}
// 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(p PinOutput) {
configurePinOut(p)
func ConfigurePinOut(po PinOutput) {
configurePinOut(po)
}
// ConfigurePinInput is a legacy function used to configure pins as inputs.
//
// 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 PinInput) {
configurePinInputPulldown(pi)
}
// ConfigurePinInput is a legacy function used to configure pins as inputs.
//
// 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 PinInput) {
configurePinInput(pi)
}
// ConfigurePinInput is a legacy function used to configure pins as inputs.
//
// 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 PinInput) {
configurePinInputPullup(pi)
}
var (
ErrConfigBeforeInstantiated = errors.New("device must be instantiated with New before calling Configure method")
)
+17 -1
View File
@@ -5,8 +5,24 @@ package legacy
import "machine"
func configurePinOut(p PinOutput) {
configurePin(p, machine.PinInputPulldown)
}
func configurePinInputPulldown(p PinInput) {
configurePin(p, machine.PinInputPulldown)
}
func configurePinInput(p PinInput) {
configurePin(p, machine.PinInput)
}
func configurePinInputPullup(p PinInput) {
configurePin(p, machine.PinInputPullup)
}
func configurePin(p any, mode machine.PinMode) {
machinePin, ok := p.(machine.Pin)
if ok {
machinePin.Configure(machine.PinConfig{Mode: machine.PinOutput})
machinePin.Configure(machine.PinConfig{Mode: mode})
}
}
+4 -1
View File
@@ -2,4 +2,7 @@
package legacy
func configurePinOut(p PinOutput) {}
func configurePinOut(p PinOutput) {}
func configurePinInput(p PinInput) {}
func configurePinInputPulldown(p PinInput) {}
func configurePinInputPullup(p PinInput) {}
+6 -6
View File
@@ -3,9 +3,9 @@ package max6675
import (
"errors"
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// ErrThermocoupleOpen is returned when the thermocouple input is open.
@@ -14,16 +14,16 @@ var ErrThermocoupleOpen = errors.New("thermocouple input open")
type Device struct {
bus drivers.SPI
cs machine.Pin
cs drivers.PinOutput
}
// 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 machine.Pin) *Device {
func NewDevice(bus drivers.SPI, cs legacy.PinOutput) *Device {
return &Device{
bus: bus,
cs: cs,
cs: cs.Set,
}
}
@@ -34,11 +34,11 @@ func (d *Device) Read() (float32, error) {
value uint16
)
d.cs.Low()
d.cs(false)
if err := d.bus.Tx([]byte{0, 0}, read); err != nil {
return 0, err
}
d.cs.High()
d.cs(true)
// datasheet: Bit D2 is normally low and goes high if the thermocouple input is open.
if read[1]&0x04 == 0x04 {
+15 -11
View File
@@ -3,31 +3,35 @@
package max72xx
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Device struct {
bus drivers.SPI
cs machine.Pin
bus drivers.SPI
cs drivers.PinOutput
config func()
}
// 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 machine.Pin) *Device {
func NewDevice(bus drivers.SPI, cs legacy.PinOutput) *Device {
return &Device{
bus: bus,
cs: cs,
cs: cs.Set,
config: func() {
legacy.ConfigurePinOut(cs)
},
}
}
// Configure setups the pins.
func (driver *Device) Configure() {
outPutConfig := machine.PinConfig{Mode: machine.PinOutput}
driver.cs.Configure(outPutConfig)
if driver.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
driver.config()
}
// SetScanLimit sets the scan limit. Maximum is 8.
@@ -89,8 +93,8 @@ func (driver *Device) writeByte(data byte) {
// WriteCommand write data to a given register.
func (driver *Device) WriteCommand(register, data byte) {
driver.cs.Low()
driver.cs(false)
driver.writeByte(register)
driver.writeByte(data)
driver.cs.High()
driver.cs(true)
}
+29 -22
View File
@@ -8,18 +8,19 @@ 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 machine.Pin
cs drivers.PinOutput
msg *CANMsg
mcpMode byte
config func()
}
// CANMsg stores CAN message fields.
@@ -36,15 +37,18 @@ const (
)
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI, csPin machine.Pin) *Device {
func New(b drivers.SPI, csPin legacy.PinOutput) *Device {
d := &Device{
spi: SPI{
bus: b,
tx: make([]byte, 0, bufferSize),
rx: make([]byte, 0, bufferSize),
},
cs: csPin,
cs: csPin.Set,
msg: &CANMsg{},
config: func() {
legacy.ConfigurePinOut(csPin)
},
}
return d
@@ -52,7 +56,10 @@ func New(b drivers.SPI, csPin machine.Pin) *Device {
// Configure sets up the device for communication.
func (d *Device) Configure() {
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.config()
}
const beginTimeoutValue int = 10
@@ -159,9 +166,9 @@ func (d *Device) init(speed, clock byte) error {
// Reset resets mcp2515.
func (d *Device) Reset() error {
d.cs.Low()
d.cs(false)
_, err := d.spi.readWrite(mcpReset)
d.cs.High()
d.cs(true)
// time.Sleep(time.Microsecond * 4)
if err != nil {
return err
@@ -449,8 +456,8 @@ func (d *Device) readMsg() error {
func (d *Device) readRxBuffer(loadAddr uint8) error {
msg := d.msg
d.cs.Low()
defer d.cs.High()
d.cs(false)
defer d.cs(true)
_, err := d.spi.readWrite(loadAddr)
if err != nil {
return err
@@ -517,8 +524,8 @@ func (d *Device) getNextFreeTxBuf() (uint8, uint8, error) {
}
func (d *Device) writeCANMsg(bufNum uint8, canid uint32, ext, rtrBit, dlc uint8, data []byte) error {
d.cs.Low()
defer d.cs.High()
d.cs(false)
defer d.cs(true)
_, err := d.spi.readWrite(txSidhToLoad(bufNum))
if err != nil {
return err
@@ -537,7 +544,7 @@ func (d *Device) writeCANMsg(bufNum uint8, canid uint32, ext, rtrBit, dlc uint8,
}
// Since cs.Low and cs.High are executed in d.startTransmission,
// it is necessary to set cs.High once to separate the instruction of mcp2515.
d.cs.High()
d.cs(true)
err = d.startTransmission(bufNum)
if err != nil {
@@ -605,9 +612,9 @@ func (s *SPI) setTxBufData(canid uint32, ext, rtrBit, dlc uint8, data []byte) er
}
func (d *Device) startTransmission(bufNum uint8) error {
d.cs.Low()
d.cs(false)
_, err := d.spi.readWrite(txSidhToRTS(bufNum))
d.cs.High()
d.cs(true)
if err != nil {
return err
}
@@ -701,8 +708,8 @@ func txSidhToLoad(i uint8) uint8 {
}
func (d *Device) setRegister(addr, value byte) error {
d.cs.Low()
defer d.cs.High()
d.cs(false)
defer d.cs(true)
_, err := d.spi.readWrite(mcpWrite)
if err != nil {
return err
@@ -721,8 +728,8 @@ func (d *Device) setRegister(addr, value byte) error {
}
func (d *Device) readRegister(addr byte) (byte, error) {
d.cs.Low()
defer d.cs.High()
d.cs(false)
defer d.cs(true)
_, err := d.spi.readWrite(mcpRead)
if err != nil {
return 0, err
@@ -740,8 +747,8 @@ func (d *Device) readRegister(addr byte) (byte, error) {
}
func (d *Device) modifyRegister(addr, mask, data byte) error {
d.cs.Low()
defer d.cs.High()
d.cs(false)
defer d.cs(true)
_, err := d.spi.readWrite(mcpBitMod)
if err != nil {
return err
@@ -783,8 +790,8 @@ func (d *Device) requestNewMode(newMode byte) error {
}
func (d *Device) readStatus() (byte, error) {
d.cs.Low()
defer d.cs.High()
d.cs(false)
defer d.cs(true)
_, err := d.spi.readWrite(mcpReadStatus)
if err != nil {
return 0, err
+14 -14
View File
@@ -6,18 +6,18 @@ package pcd8544 // import "tinygo.org/x/drivers/pcd8544"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin machine.Pin
rstPin machine.Pin
scePin machine.Pin
dcPin drivers.PinOutput
rstPin drivers.PinOutput
scePin drivers.PinOutput
buffer []byte
width int16
height int16
@@ -30,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 machine.Pin) *Device {
func New(bus drivers.SPI, dcPin, rstPin, scePin legacy.PinOutput) *Device {
return &Device{
bus: bus,
dcPin: dcPin,
rstPin: rstPin,
scePin: scePin,
dcPin: dcPin.Set,
rstPin: rstPin.Set,
scePin: scePin.Set,
}
}
@@ -54,9 +54,9 @@ func (d *Device) Configure(cfg Config) {
d.bufferSize = d.width * d.height / 8
d.buffer = make([]byte, d.bufferSize)
d.rstPin.Low()
d.rstPin(false)
time.Sleep(100 * time.Nanosecond)
d.rstPin.High()
d.rstPin(true)
d.SendCommand(FUNCTIONSET | EXTENDEDINSTRUCTION) // H = 1
d.SendCommand(SETVOP | 0x3f) // 0x3f : Vop6 = 0, Vop5 to Vop0 = 1
d.SendCommand(SETTEMP | 0x03) // Experimentally determined
@@ -91,13 +91,13 @@ func (d *Device) Display() error {
// sendDataCommand sends image data or a command to the screen
func (d *Device) sendDataCommand(isCommand bool, data uint8) {
if isCommand {
d.dcPin.Low()
d.dcPin(false)
} else {
d.dcPin.High()
d.dcPin(true)
}
d.scePin.Low()
d.scePin(false)
d.bus.Transfer(data)
d.scePin.High()
d.scePin(true)
}
// SetPixel enables or disables a pixel in the buffer
+24 -17
View File
@@ -2,7 +2,8 @@
package shiftregister
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type NumberBit int8
@@ -16,9 +17,10 @@ const (
// Device holds pin number
type Device struct {
latch, clock, out machine.Pin // IC wiring
bits NumberBit // Pin number
mask uint32 // keep all pins state
latch, clock, out drivers.PinOutput // IC wiring
config func()
bits NumberBit // Pin number
mask uint32 // keep all pins state
}
// ShiftPin is the implementation of the ShiftPin interface.
@@ -29,35 +31,40 @@ type ShiftPin struct {
}
// New returns a new shift output register device
func New(Bits NumberBit, Latch, Clock, Out machine.Pin) *Device {
func New(Bits NumberBit, Latch, Clock, Out legacy.PinOutput) *Device {
return &Device{
latch: Latch,
clock: Clock,
out: Out,
latch: Latch.Set,
clock: Clock.Set,
out: Out.Set,
bits: Bits,
config: func() {
legacy.ConfigurePinOut(Latch)
legacy.ConfigurePinOut(Clock)
legacy.ConfigurePinOut(Out)
},
}
}
// Configure set hardware configuration
func (d *Device) Configure() {
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()
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.latch(true)
}
// WriteMask applies mask's bits to register's outputs pin
// mask's MSB set Q1, LSB set Q8 (for 8 bits mask)
func (d *Device) WriteMask(mask uint32) {
d.mask = mask // Keep the mask for individual addressing
d.latch.Low()
d.latch(false)
for i := 0; i < int(d.bits); i++ {
d.clock.Low()
d.out.Set(mask&1 != 0)
d.clock(false)
d.out(mask&1 != 0)
mask = mask >> 1
d.clock.High()
d.clock(true)
}
d.latch.High()
d.latch(true)
}
// GetShiftPin return an individually addressable pin
+2
View File
@@ -1,3 +1,5 @@
//go:build baremetal
package ssd1289
import "machine"
+34 -32
View File
@@ -7,6 +7,9 @@ import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Bus interface {
@@ -14,10 +17,10 @@ type Bus interface {
}
type Device struct {
rs machine.Pin
wr machine.Pin
cs machine.Pin
rst machine.Pin
rs drivers.PinOutput
wr drivers.PinOutput
cs drivers.PinOutput
rst drivers.PinOutput
bus Bus
}
@@ -26,32 +29,31 @@ 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,
wr: wr,
cs: cs,
rst: rst,
rs: rs.Set,
wr: wr.Set,
cs: cs.Set,
rst: rst.Set,
bus: bus,
}
legacy.ConfigurePinOut(rs)
legacy.ConfigurePinOut(wr)
legacy.ConfigurePinOut(cs)
legacy.ConfigurePinOut(rst)
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()
cs.Set(true)
rst.Set(true)
wr.Set(true)
return d
}
func (d *Device) lcdWriteCom(cmd Command) {
d.rs.Low()
d.rs(false)
d.lcdWriteBusInt(uint16(cmd))
}
func (d *Device) lcdWriteDataInt(data uint16) {
d.rs.High()
d.rs(true)
d.lcdWriteBusInt(data)
}
@@ -61,8 +63,8 @@ func (d *Device) lcdWriteComData(cmd Command, data uint16) {
}
func (d *Device) tx() {
d.wr.Low()
d.wr.High()
d.wr(false)
d.wr(true)
}
func (d *Device) lcdWriteBusInt(data uint16) {
@@ -71,13 +73,13 @@ func (d *Device) lcdWriteBusInt(data uint16) {
}
func (d *Device) Configure() {
d.rst.High()
d.rst(true)
time.Sleep(time.Millisecond * 5)
d.rst.Low()
d.rst(false)
time.Sleep(time.Millisecond * 15)
d.rst.High()
d.rst(true)
time.Sleep(time.Millisecond * 15)
d.cs.Low()
d.cs(false)
//Power supply setting
d.lcdWriteComData(POWERCONTROL1, 0xA8A4)
@@ -137,7 +139,7 @@ func (d *Device) Configure() {
//MUX 319 --> Number of lines in display
d.lcdWriteComData(DRIVEROUTPUTCONTROL, 0x233F)
d.cs.High()
d.cs(true)
}
@@ -167,25 +169,25 @@ func (d *Device) SetPixel(x, y int16, c color.RGBA) {
encoded := encodeColor(c)
d.cs.Low()
d.cs(false)
d.setXY(uint16(x), uint16(y), uint16(x), uint16(y))
d.rs.High()
d.rs(true)
d.lcdWriteBusInt(encoded)
d.cs.High()
d.cs(true)
}
func (d *Device) FillRect(x, y, w, h int16, c color.RGBA) {
encoded := encodeColor(c)
d.cs.Low()
d.cs(false)
d.setXY(uint16(x), uint16(y), uint16(x+(w-1)), uint16(y+(h-1)))
d.rs.High()
d.rs(true)
d.bus.Set(encoded)
for i := int64(0); i < int64(w)*int64(h); i++ {
d.tx()
}
d.cs.High()
d.rs.Low()
d.cs(true)
d.rs(false)
}
+14 -13
View File
@@ -11,6 +11,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Model uint8
@@ -19,9 +20,9 @@ type Rotation uint8
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
width int16
height int16
batchLength int16
@@ -37,14 +38,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 {
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
return Device{
bus: bus,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: csPin.Set,
}
}
@@ -69,11 +70,11 @@ func (d *Device) Configure(cfg Config) {
d.batchData = make([]uint8, d.batchLength*2)
// reset the device
d.resetPin.High()
d.resetPin(true)
time.Sleep(100 * time.Millisecond)
d.resetPin.Low()
d.resetPin(false)
time.Sleep(100 * time.Millisecond)
d.resetPin.High()
d.resetPin(true)
time.Sleep(200 * time.Millisecond)
// Initialization
@@ -251,7 +252,7 @@ func (d *Device) Data(data uint8) {
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.dcPin.Set(!isCommand)
d.dcPin(!isCommand)
d.bus.Tx(data, nil)
}
+33 -26
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 (
@@ -20,11 +20,12 @@ var (
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
enPin machine.Pin
rwPin machine.Pin
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
enPin drivers.PinOutput
rwPin drivers.PinOutput
config func()
width int16
height int16
rowOffset int16
@@ -41,19 +42,29 @@ 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 machine.Pin) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, enPin, rwPin legacy.PinOutput) Device {
return Device{
bus: bus,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
enPin: enPin,
rwPin: rwPin,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: csPin.Set,
enPin: enPin.Set,
rwPin: rwPin.Set,
config: func() {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(enPin)
legacy.ConfigurePinOut(rwPin)
},
}
}
// Configure initializes the display with default configuration
func (d *Device) Configure(cfg Config) {
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
if cfg.Width == 0 {
cfg.Width = 128
}
@@ -73,23 +84,19 @@ func (d *Device) Configure(cfg Config) {
}
// configure GPIO pins
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})
d.config()
// reset the device
d.resetPin.High()
d.resetPin(true)
time.Sleep(100 * time.Millisecond)
d.resetPin.Low()
d.resetPin(false)
time.Sleep(100 * time.Millisecond)
d.resetPin.High()
d.resetPin(true)
time.Sleep(200 * time.Millisecond)
d.rwPin.Low()
d.dcPin.Low()
d.enPin.High()
d.rwPin(false)
d.dcPin(false)
d.enPin(true)
// Initialization
d.Command(SET_COMMAND_LOCK)
@@ -278,10 +285,10 @@ func (d *Device) Data(data uint8) {
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.dcPin.Set(!isCommand)
d.csPin.Low()
d.dcPin(!isCommand)
d.csPin(false)
d.bus.Tx(data, nil)
d.csPin.High()
d.csPin(true)
}
// Size returns the current size of the display