Compare commits

..

9 Commits

Author SHA1 Message Date
deadprogram 38c606d813 refactor: add display.Pin interface and use it everywhere that is easy to do so
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-07-06 11:41:03 +02:00
JP Hastings-Spital d02d21ecea feat: allow gps init with address
Adafruit's Mini GPS PA1010D Module works with this device driver, but requires 0x10 as the address, rather than 0x42.

This change allows the device to be initialised with whatever i2c address is needed, while maintaining backward compatibility.

Adds new constants to allow easy configuration of both the ublox device and the PA1010D.
2025-06-30 14:00:55 +02:00
Yurii Soldak 805e2a02f8 lsm6ds3tr: avoid unnecessary heap allocations (#766)
* lsm6ds3tr: avoid unnecessary heap allocations
* lsm6ds3tr: use helper functions, for readability
* lsm6ds3tr: return slice of the internal buffer on readBytes
2025-06-25 10:03:41 +02:00
deadprogram c4ff8242a7 all: updates for drivers release v0.32.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-06-15 22:36:34 +02:00
soypat 82c41dbf14 add driver design pointer to CONTRIBUTING.md 2025-05-28 11:03:09 +02:00
Hikmatulloh Hari Mukti c4168864fd bmp280: remove alloc on read sensor data 2025-05-28 10:29:08 +02:00
Leon Matthews dbc9022f6a ws2812: add 200MHz support for the Cortex-M0/rp2040 2025-05-20 13:09:35 +02:00
Mateusz Nowak d41bc0b85f fix: remove time.Sleep from SSD1306 SPI transfer code 2025-05-20 12:43:13 +02:00
Craig Swank e7f90166ad tmc2209 bug fixes (#755)
* Make write buffer big enough for crc
* crc according to datasheet
* fix build
* a correct crc func already exists
2025-05-20 12:27:30 +02:00
53 changed files with 941 additions and 857 deletions
+27
View File
@@ -1,3 +1,30 @@
0.32.0
---
- **enhancements**
- **bmp280**
- remove alloc on read sensor data
- **ws2812**
- add 200MHz support for the Cortex-M0/rp2040
- **bugfixes**
- **ssd1306**
- remove time.Sleep from SSD1306 SPI transfer code
- **tmc2209**
- tmc2209 bug fixes (#755)
- **docs**
- **contributing**
- add driver design pointer to CONTRIBUTING.md
0.31.0
---
---
- **enhancements**
- **spi**
- update all SPI usage to use either *machine.SPI or drivers.SPI
0.30.0
---
- **new devices**
+3
View File
@@ -8,6 +8,9 @@ We would like your help to make this project better, so we appreciate any contri
We'd love to get your feedback on getting started with TinyGo. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or you can also get in touch directly with us on our Slack channel at [https://gophers.slack.com/messages/CDJD3SUP6](https://gophers.slack.com/messages/CDJD3SUP6).
### Driver design
Before porting or writing a driver from scratch please read **[Driver Design for TinyGo](https://tinygo.org/docs/guides/driver-design)**.
### One of the TinyGo drivers is not working as you expect
Please open a Github issue with your problem, and we will be happy to assist.
+2 -7
View File
@@ -7,8 +7,6 @@ import (
"image/color"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
const (
@@ -38,11 +36,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 pin.Output, 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 drivers.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.
+5 -10
View File
@@ -2,7 +2,6 @@ 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
@@ -11,18 +10,14 @@ 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.PinOutput
SDO drivers.PinOutput
Delay uint32
configurePins func()
SCK drivers.Pin
SDO drivers.Pin
Delay uint32
}
// Configure sets up the SCK and SDO pins as outputs and sets them low
// Configure sets the SCK and SDO pins to low.
// Note that the SCK and SDO pins must already be configured as outputs.
func (s *bbSPI) Configure() {
if s.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
s.configurePins()
s.SCK.Low()
s.SDO.Low()
if s.Delay == 0 {
+23 -34
View File
@@ -4,45 +4,34 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
// 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.PinOutput
CSB drivers.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 pin.Output, spi drivers.SPI) *DeviceSPI {
func NewSPI(csb drivers.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,
}
}
// Configure configures the BMI160 for use. It configures the CSB pin and
// configures the BMI160, but it does not configure the SPI interface (it is
// assumed to be up and running).
// Configure configures the BMI160 for use. The CSB pin anf the SPI interface
// should be configured already. This function configures the BMI160 only.
func (d *DeviceSPI) Configure() error {
if d.configurePins == nil {
return legacy.ErrConfigBeforeInstantiated
}
d.configurePins()
d.csb.High()
d.CSB.High()
// The datasheet recommends doing a register read from address 0x7F to get
// SPI communication going:
@@ -94,9 +83,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
}
@@ -131,9 +120,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
}
@@ -161,9 +150,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
}
@@ -209,9 +198,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]
}
@@ -225,7 +214,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 -8
View File
@@ -23,6 +23,7 @@ type Filter uint
type Device struct {
bus drivers.I2C
Address uint16
buf [6]byte
cali calibrationCoefficients
Temperature Oversampling
Pressure Oversampling
@@ -134,8 +135,8 @@ func (d *Device) PrintCali() {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
func (d *Device) ReadTemperature() (temperature int32, err error) {
data, err := d.readData(REG_TEMP, 3)
if err != nil {
data := d.buf[:3]
if err = d.readData(REG_TEMP, data); err != nil {
return
}
@@ -158,8 +159,8 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
// ReadPressure returns the pressure in milli pascals (mPa).
func (d *Device) ReadPressure() (pressure int32, err error) {
// First 3 bytes are Pressure, last 3 bytes are Temperature
data, err := d.readData(REG_PRES, 6)
if err != nil {
data := d.buf[:6]
if err = d.readData(REG_PRES, data); err != nil {
return
}
@@ -203,7 +204,7 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
}
// readData reads n number of bytes of the specified register
func (d *Device) readData(register int, n int) ([]byte, error) {
func (d *Device) readData(register int, data []byte) error {
// If not in normal mode, set the mode to FORCED mode, to prevent incorrect measurements
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
if d.Mode != MODE_NORMAL {
@@ -218,9 +219,7 @@ func (d *Device) readData(register int, n int) ([]byte, error) {
}
// Read the requested register
data := make([]byte, n)
err := legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
return data, err
return legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
}
// convert3Bytes converts three bytes to int32
+5 -6
View File
@@ -5,20 +5,19 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
)
// Device wraps a GPIO connection to a buzzer.
type Device struct {
pin drivers.PinOutput
pin drivers.Pin
High bool
BPM float64
}
// New returns a new buzzer driver given which pin to use
func New(pin pin.Output) Device {
func New(pin drivers.Pin) Device {
return Device{
pin: pin.Set,
pin: pin,
High: false,
BPM: 96.0,
}
@@ -26,14 +25,14 @@ func New(pin pin.Output) 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
}
+64 -2
View File
@@ -2,6 +2,7 @@
package easystepper // import "tinygo.org/x/drivers/easystepper"
import (
"errors"
"time"
"tinygo.org/x/drivers"
@@ -30,10 +31,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 drivers.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 drivers.Pin
}
// Device holds the pins and the delay between steps
type Device struct {
pins [4]drivers.PinOutput
config func()
pins [4]drivers.Pin
stepDelay time.Duration
stepNumber uint8
stepMode StepMode
@@ -44,6 +63,49 @@ 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]drivers.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
stepMode: config.Mode,
}, nil
}
// Configure does nothing, as it assumes that the pins of the Device have already
// been configured by the user as outputs.
func (d *Device) 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
}
// 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.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
}
-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.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
}
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
println("GPS I2C Example")
machine.I2C0.Configure(machine.I2CConfig{})
ublox := gps.NewI2C(machine.I2C0)
ublox := gps.NewI2CWithAddress(machine.I2C0, gps.UBLOX_I2C_ADDRESS)
parser := gps.NewParser()
var fix gps.Fix
for {
+8 -14
View File
@@ -7,27 +7,24 @@ package ft6336
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/touch"
)
// 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 drivers.Pin
}
// New returns FT6336 device for the provided I2C bus using default address.
func New(i2c drivers.I2C, intPin pin.Input) *Device {
func New(i2c drivers.I2C, intPin drivers.Pin) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 11),
Address: Address,
configurePins: func() {
legacy.ConfigurePinInputPulldown(intPin)
},
intPin: intPin,
}
}
@@ -35,13 +32,10 @@ func New(i2c drivers.I2C, intPin pin.Input) *Device {
type Config struct {
}
// Configure the FT6336 device.
// Configure the FT6336 device. Note that the interrupt pin must be configured
// separately as an input.
func (d *Device) Configure(config Config) error {
if d.configurePins == nil {
return legacy.ErrConfigBeforeInstantiated
}
d.write1Byte(0xA4, 0x00)
d.configurePins()
return nil
}
+12 -17
View File
@@ -10,8 +10,6 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
// Rotation controls the rotation used by the display.
@@ -23,10 +21,10 @@ type FrameRate uint8
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
blPin drivers.PinOutput
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
blPin drivers.Pin
width int16
height int16
columnOffsetCfg int16
@@ -52,18 +50,15 @@ type Config struct {
Height int16
}
// New creates a new ST7789 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin pin.Output) Device {
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
// New creates a new ST7789 connection. The SPI wire must already be configured, along with the
// data/command and reset pins as outputs.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) Device {
return Device{
bus: bus,
resetPin: resetPin.Set,
dcPin: dcPin.Set,
csPin: csPin.Set,
blPin: blPin.Set,
resetPin: resetPin,
dcPin: dcPin,
csPin: csPin,
blPin: blPin,
}
}
@@ -227,7 +222,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)
}
+7 -1
View File
@@ -69,10 +69,16 @@ func NewUART(uart drivers.UART) Device {
}
// NewI2C creates a new I2C GPS connection.
// Uses the default i2c address (0x42) for backward compatibility reasons.
func NewI2C(bus drivers.I2C) Device {
return NewI2CWithAddress(bus, I2C_ADDRESS)
}
// NewI2CWithAddress creates a new I2C GPS connection on the provided address
func NewI2CWithAddress(bus drivers.I2C, i2cAddress uint16) Device {
return Device{
bus: bus,
address: I2C_ADDRESS,
address: i2cAddress,
buffer: make([]byte, bufferSize),
bufIdx: bufferSize,
sentence: strings.Builder{},
+5 -1
View File
@@ -4,7 +4,11 @@ package gps
// The I2C address which this device listens to.
const (
I2C_ADDRESS = 0x42
// To ensure backward compatibility
I2C_ADDRESS = UBLOX_I2C_ADDRESS
UBLOX_I2C_ADDRESS = 0x42
PA1010D_I2C_ADDRESS = 0x10
)
const (
+10 -19
View File
@@ -8,37 +8,28 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
const TIMEOUT = 23324 // max sensing distance (4m)
// Device holds the pins
type Device struct {
trigger drivers.PinOutput
echo drivers.PinInput
configurePins func()
trigger drivers.Pin
echo drivers.Pin
}
// New returns a new ultrasonic driver given 2 pins
func New(trigger pin.Output, echo pin.Input) Device {
func New(trigger, echo drivers.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
// Configure expects that the pins of the Device have already
// been configured by the user. Trigger pin should be an output
// and echo pin should be an input.
func (d *Device) Configure() {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
}
// ReadDistance returns the distance of the object in mm
@@ -62,7 +53,7 @@ func (d *Device) ReadPulse() int32 {
d.trigger.Low()
i := uint8(0)
for {
if d.echo() {
if d.echo.Get() {
t = time.Now()
break
}
@@ -76,7 +67,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.
-54
View File
@@ -1,54 +0,0 @@
package legacy
import (
"errors"
"tinygo.org/x/drivers/internal/pin"
)
// 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 pin.Output) {
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 pin.Input) {
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 pin.Input) {
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 pin.Input) {
configurePinInputPullup(pi)
}
// PinIsNoPin returns true if the argument is a machine.Pin type and is the machine.NoPin predeclared type.
//
// Deprecated: Drivers do not require pin knowledge from now on.
func PinIsNoPin(pin any) bool {
return pinIsNoPin(pin)
}
var (
ErrConfigBeforeInstantiated = errors.New("device must be instantiated with New before calling Configure method")
)
-11
View File
@@ -1,11 +0,0 @@
//go:build !baremetal
package legacy
import "tinygo.org/x/drivers/internal/pin"
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 }
-10
View File
@@ -1,10 +0,0 @@
//go:build baremetal && fe310
package legacy
import "machine"
const (
pulldown = machine.PinInput
pullup = machine.PinInput
)
-13
View File
@@ -1,13 +0,0 @@
//go:build baremetal && !fe310
package legacy
import "machine"
// If you are getting a build error here you then we missed adding
// your CPU build tag to the list of CPUs that do not have pulldown/pullups.
// Add it above and in pinhal_nopulls! You should also add a smoketest for it :)
const (
pulldown = machine.PinInputPulldown
pullup = machine.PinInputPullup
)
-37
View File
@@ -1,37 +0,0 @@
//go:build baremetal
package legacy
import (
"machine"
"tinygo.org/x/drivers/internal/pin"
)
func configurePinOut(po pin.Output) {
configurePin(po, machine.PinOutput)
}
func configurePinInputPulldown(pi pin.Input) {
configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput.
}
func configurePinInput(pi pin.Input) {
configurePin(pi, machine.PinInput)
}
func configurePinInputPullup(pi pin.Input) {
configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput.
}
func pinIsNoPin(a any) bool {
p, ok := a.(machine.Pin)
return ok && p == machine.NoPin
}
func configurePin(p any, mode machine.PinMode) {
machinePin, ok := p.(machine.Pin)
if ok {
machinePin.Configure(machine.PinConfig{Mode: mode})
}
}
-23
View File
@@ -1,23 +0,0 @@
package pin
import "tinygo.org/x/drivers"
// Here to aid relevant documentation links of [drivers.PinOutput] and [drivers.PinInput].
var _ drivers.PinOutput
// Output 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 and has
// not been standardized as of yet as a standard HAL in the drivers package,
// [discussion ongoing here].
//
// [discussion ongoing here]: https://github.com/orgs/tinygo-org/discussions/5043
type Output interface {
Set(level bool)
}
// Input represents a pin hardware abstraction layer.
// See [Output] for more information on why this type exists separate to drivers.
type Input interface {
Get() (level bool)
}
+35 -24
View File
@@ -8,7 +8,6 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -26,7 +25,7 @@ type Device struct {
accelSampleRate AccelSampleRate
gyroRange GyroRange
gyroSampleRate GyroSampleRate
buf [6]uint8
buf [7]uint8 // up to 6 bytes for read + 1 byte for the register address
}
// Configuration for LSM6DS3TR device.
@@ -84,30 +83,20 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
d.gyroSampleRate = GYRO_SR_104
}
data := d.buf[:1]
// Configure accelerometer
data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
err = d.writeByte(CTRL1_XL, uint8(d.accelRange)|uint8(d.accelSampleRate))
if err != nil {
return
}
// Set ODR bit
err = legacy.ReadRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
data[0] |= BW_SCAL_ODR_ENABLED
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL4_C, data)
// Enable ODR scaling
err = d.setBits(CTRL4_C, BW_SCAL_ODR_ENABLED)
if err != nil {
return
}
// Configure gyroscope
data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
err = d.writeByte(CTRL2_G, uint8(d.gyroRange)|uint8(d.gyroSampleRate))
if err != nil {
return
}
@@ -118,8 +107,10 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Connected returns whether a LSM6DS3TR has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := d.buf[:1]
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
data, err := d.readBytes(WHO_AM_I, 1)
if err != nil {
return false
}
return data[0] == 0x6A
}
@@ -128,8 +119,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.Address), OUTX_L_XL, data)
data, err := d.readBytes(OUTX_L_XL, 6)
if err != nil {
return
}
@@ -153,8 +143,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.Address), OUTX_L_G, data)
data, err := d.readBytes(OUTX_L_G, 6)
if err != nil {
return
}
@@ -177,8 +166,7 @@ func (d *Device) ReadRotation() (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.Address), OUT_TEMP_L, data)
data, err := d.readBytes(OUT_TEMP_L, 2)
if err != nil {
return
}
@@ -187,3 +175,26 @@ func (d *Device) ReadTemperature() (t int32, err error) {
t = 25000 + (int32(int16((int16(data[1])<<8)|int16(data[0])))*125)/32
return
}
func (d *Device) readBytes(reg, size uint8) ([]byte, error) {
d.buf[0] = reg
err := d.bus.Tx(d.Address, 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(reg, value uint8) error {
d.buf[0] = reg
d.buf[1] = value
return d.bus.Tx(d.Address, d.buf[0:2], nil)
}
func (d *Device) setBits(reg, bits uint8) error {
data, err := d.readBytes(reg, 1)
if err != nil {
return err
}
return d.writeByte(reg, (data[0]&^bits)|bits)
}
+3 -4
View File
@@ -5,7 +5,6 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
)
// ErrThermocoupleOpen is returned when the thermocouple input is open.
@@ -14,16 +13,16 @@ var ErrThermocoupleOpen = errors.New("thermocouple input open")
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
cs drivers.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 pin.Output) *Device {
func NewDevice(bus drivers.SPI, cs drivers.Pin) *Device {
return &Device{
bus: bus,
cs: cs.Set,
cs: cs,
}
}
+5 -15
View File
@@ -4,35 +4,25 @@ package max72xx
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
configurePins func()
bus drivers.SPI
cs drivers.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 pin.Output) *Device {
func NewDevice(bus drivers.SPI, cs drivers.Pin) *Device {
return &Device{
bus: bus,
cs: cs.Set,
configurePins: func() {
legacy.ConfigurePinOut(cs)
},
cs: cs,
}
}
// Configure setups the pins.
// Configure expects that the pin of the Device has already been configured by the user as output.
func (driver *Device) Configure() {
if driver.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
driver.configurePins()
}
// SetScanLimit sets the scan limit. Maximum is 8.
+8 -17
View File
@@ -11,17 +11,14 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
// Device wraps MCP2515 SPI CAN Module.
type Device struct {
spi SPI
cs drivers.PinOutput
msg *CANMsg
mcpMode byte
configurePins func()
spi SPI
cs drivers.Pin
msg *CANMsg
mcpMode byte
}
// CANMsg stores CAN message fields.
@@ -38,29 +35,23 @@ const (
)
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI, csPin pin.Output) *Device {
func New(b drivers.SPI, csPin drivers.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
}
// Configure sets up the device for communication.
// Configure sets up the device for communication. It expects the SPI interface to be already
// configured, and the CS configured as output.
func (d *Device) Configure() {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
}
const beginTimeoutValue int = 10
+16 -24
View File
@@ -5,9 +5,8 @@ package onewire // import "tinygo.org/x/drivers/onewire"
import (
"errors"
"machine"
"time"
"tinygo.org/x/drivers"
)
// OneWire ROM commands
@@ -20,8 +19,7 @@ const (
// Device wraps a connection to an 1-Wire devices.
type Device struct {
set drivers.PinOutput
get drivers.PinInput
p machine.Pin
}
// Config wraps a configuration to an 1-Wire devices.
@@ -34,30 +32,24 @@ var (
errReadAddress = errors.New("Error: OneWire. Read address error: CRC mismatch.")
)
// NewFromFuncs expects pin setter and getter for DQ line. Ideally this driver should receive
// a one-wire bus HAL abstraction, but I was asked to show how this could be done using pin HAL so here goes.
func NewFromFuncs(getPinLevel drivers.PinInput, setPinLevel drivers.PinOutput) *Device {
return &Device{
set: setPinLevel,
get: getPinLevel,
// New creates a new GPIO 1-Wire connection.
// The pin must be pulled up to the VCC via a resistor greater than 500 ohms (default 4.7k).
func New(p machine.Pin) Device {
return Device{
p: p,
}
}
// Configure initializes the protocol.
func (d *Device) Configure(config Config) {}
// By setting the pin value one should configure as output and also expect a more
// consistent behaviour across all tinygo hosts by pulling DQ line low consistently. Win-win.
func (d *Device) cfgOut() { d.set.Low() }
func (d *Device) cfgIn() { d.get() }
// Reset pull DQ line low, then up.
func (d Device) Reset() error {
d.cfgOut()
d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
time.Sleep(480 * time.Microsecond)
d.cfgIn()
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
time.Sleep(70 * time.Microsecond)
precence := d.get()
precence := d.p.Get()
time.Sleep(410 * time.Microsecond)
if precence {
return errNoPresence
@@ -67,14 +59,14 @@ func (d Device) Reset() error {
// WriteBit transmits a bit to 1-Wire bus.
func (d Device) WriteBit(data uint8) {
d.cfgOut()
d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
if data&1 == 1 { // Send '1'
time.Sleep(5 * time.Microsecond)
d.cfgIn()
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
time.Sleep(60 * time.Microsecond)
} else { // Send '0'
time.Sleep(60 * time.Microsecond)
d.cfgIn()
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
time.Sleep(5 * time.Microsecond)
}
}
@@ -89,11 +81,11 @@ func (d Device) Write(data uint8) {
// ReadBit receives a bit from 1-Wire bus.
func (d Device) ReadBit() (data uint8) {
d.cfgOut()
d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
time.Sleep(3 * time.Microsecond)
d.cfgIn()
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
time.Sleep(8 * time.Microsecond)
if d.get() {
if d.p.Get() {
data = 1
}
time.Sleep(60 * time.Microsecond)
-29
View File
@@ -1,29 +0,0 @@
package onewire
import (
"machine"
"tinygo.org/x/drivers/internal/legacy"
)
// New creates a new GPIO 1-Wire connection.
// The pin must be pulled up to the VCC via a resistor greater than 500 ohms (default 4.7k).
func New(p machine.Pin) Device {
isOut := false
return Device{
set: func(level bool) {
if !isOut {
legacy.ConfigurePinOut(p)
isOut = true
}
p.Set(level)
},
get: func() (level bool) {
if isOut {
legacy.ConfigurePinInputPullup(p)
isOut = false
}
return p.Get()
},
}
}
+8 -9
View File
@@ -9,15 +9,14 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
)
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutput
rstPin drivers.PinOutput
scePin drivers.PinOutput
dcPin drivers.Pin
rstPin drivers.Pin
scePin drivers.Pin
buffer []byte
width int16
height int16
@@ -29,13 +28,13 @@ type Config struct {
Height int16
}
// New creates a new PCD8544 connection. The SPI bus must already be configured.
func New(bus drivers.SPI, dcPin, rstPin, scePin pin.Output) *Device {
// New creates a new PCD8544 connection. The SPI bus and pins must already be configured.
func New(bus drivers.SPI, dcPin, rstPin, scePin drivers.Pin) *Device {
return &Device{
bus: bus,
dcPin: dcPin.Set,
rstPin: rstPin.Set,
scePin: scePin.Set,
dcPin: dcPin,
rstPin: rstPin,
scePin: scePin,
}
}
+7 -26
View File
@@ -1,29 +1,10 @@
package drivers
// PinOutput is hardware abstraction for a pin which outputs a
// digital signal (high or low level).
//
// // Code conversion demo: from machine.Pin to drivers.PinOutput
// led := machine.LED
// led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// var pin drivers.PinOutput = led.Set // Going from a machine.Pin to a drivers.PinOutput
type PinOutput func(level bool)
// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true).
func (po PinOutput) High() {
po(true)
// Pin is a digital pin interface. It is notably implemented by the
// machine.Pin type.
type Pin interface {
Get() bool
High()
Low()
Set(high bool)
}
// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false).
func (po PinOutput) Low() {
po(false)
}
// PinInput 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.PinInput
// input := machine.LED
// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.PinInput
// var pin drivers.PinInput = input.Get // Going from a machine.Pin to a drivers.PinInput
type PinInput func() (level bool)
+11 -21
View File
@@ -3,8 +3,6 @@ package shiftregister
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type NumberBit int8
@@ -18,39 +16,31 @@ const (
// Device holds pin number
type Device struct {
latch, clock, out drivers.PinOutput // IC wiring
config func()
bits NumberBit // Pin number
mask uint32 // keep all pins state
latch, clock, out drivers.Pin // IC wiring
bits NumberBit // Pin number
mask uint32 // keep all pins state
}
// ShiftPin is the implementation of the ShiftPin interface.
// ShiftPin provide an interface like regular machine.Pin
// ShiftPin provide an interface like regular drivers.Pin
type ShiftPin struct {
mask uint32 // Bit representing the pin
d *Device // Reference to the register
}
// New returns a new shift output register device
func New(Bits NumberBit, Latch, Clock, Out pin.Output) *Device {
func New(Bits NumberBit, Latch, Clock, Out drivers.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
// Configure set hardware configuration. Make sure that the pins are already configured
// as output.
func (d *Device) Configure() {
if d.config == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.latch.High()
}
@@ -61,7 +51,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"
+12 -18
View File
@@ -5,11 +5,9 @@ package ssd1289
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Bus interface {
@@ -17,32 +15,28 @@ type Bus interface {
}
type Device struct {
rs drivers.PinOutput
wr drivers.PinOutput
cs drivers.PinOutput
rst drivers.PinOutput
rs drivers.Pin
wr drivers.Pin
cs drivers.Pin
rst drivers.Pin
bus Bus
}
const width = int16(240)
const height = int16(320)
func New(rs machine.Pin, wr machine.Pin, cs machine.Pin, rst machine.Pin, bus Bus) Device {
func New(rs drivers.Pin, wr drivers.Pin, cs drivers.Pin, rst drivers.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)
cs.High()
rst.High()
wr.High()
return d
}
+5 -11
View File
@@ -6,7 +6,6 @@ package ssd1306 // import "tinygo.org/x/drivers/ssd1306"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
@@ -58,9 +57,9 @@ type I2CBus struct {
type SPIBus struct {
wire drivers.SPI
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
}
type Buser interface {
@@ -81,11 +80,8 @@ func NewI2C(bus drivers.I2C) Device {
}
}
// NewSPI creates a new SSD1306 connection. The SPI wire must already be configured.
func NewSPI(bus drivers.SPI, dcPin, resetPin, 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})
// NewSPI creates a new SSD1306 connection. The SPI wire and pins must already be configured.
func NewSPI(bus drivers.SPI, dcPin, resetPin, csPin drivers.Pin) Device {
return Device{
bus: &SPIBus{
wire: bus,
@@ -322,7 +318,6 @@ func (b *SPIBus) tx(data []byte, isCommand bool) error {
if isCommand {
b.csPin.High()
time.Sleep(1 * time.Millisecond)
b.dcPin.Low()
b.csPin.Low()
@@ -330,7 +325,6 @@ func (b *SPIBus) tx(data []byte, isCommand bool) error {
b.csPin.High()
} else {
b.csPin.High()
time.Sleep(1 * time.Millisecond)
b.dcPin.High()
b.csPin.Low()
+9 -14
View File
@@ -5,13 +5,11 @@ package ssd1331 // import "tinygo.org/x/drivers/ssd1331"
import (
"image/color"
"machine"
"errors"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Model uint8
@@ -20,9 +18,9 @@ type Rotation uint8
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
width int16
height int16
batchLength int16
@@ -36,16 +34,13 @@ type Config struct {
Height int16
}
// 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)
// New creates a new SSD1331 connection. The SPI wire and pins must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin drivers.Pin) Device {
return Device{
bus: bus,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: csPin.Set,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
}
}
@@ -252,7 +247,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)
}
+18 -34
View File
@@ -9,8 +9,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
var (
@@ -20,18 +18,17 @@ var (
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
enPin drivers.PinOutput
rwPin drivers.PinOutput
configurePins func()
width int16
height int16
rowOffset int16
columnOffset int16
bufferLength int16
bus drivers.SPI
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
enPin drivers.Pin
rwPin drivers.Pin
width int16
height int16
rowOffset int16
columnOffset int16
bufferLength int16
}
// Config is the configuration for the display
@@ -43,29 +40,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 pin.Output) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, enPin, rwPin drivers.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,9 +71,6 @@ func (d *Device) Configure(cfg Config) {
d.bufferLength = d.height
}
// configure GPIO pins
d.configurePins()
// reset the device
d.resetPin.High()
time.Sleep(100 * time.Millisecond)
@@ -286,7 +270,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()
+12 -18
View File
@@ -10,8 +10,6 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/pixel"
)
@@ -40,10 +38,10 @@ type Device = DeviceOf[pixel.RGB565BE]
// formats.
type DeviceOf[T Color] struct {
bus drivers.SPI
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
blPin drivers.PinOutput
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
blPin drivers.Pin
width int16
height int16
columnOffset int16
@@ -66,23 +64,19 @@ 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 pin.Output) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.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 pin.Output) DeviceOf[T] {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
// wire and pins must already be configured.
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) DeviceOf[T] {
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,
}
}
@@ -424,7 +418,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)
}
+14 -23
View File
@@ -7,14 +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/internal/pin"
"tinygo.org/x/drivers/pixel"
)
@@ -47,10 +46,10 @@ type Device = DeviceOf[pixel.RGB565BE]
// formats.
type DeviceOf[T Color] struct {
bus drivers.SPI
dcPin drivers.PinOutput
resetPin drivers.PinOutput
csPin drivers.PinOutput
blPin drivers.PinOutput
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
blPin drivers.Pin
width int16
height int16
columnOffsetCfg int16
@@ -84,27 +83,19 @@ 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 pin.Output) Device {
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.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 pin.Output) DeviceOf[T] {
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
var cs drivers.PinOutput
if !legacy.PinIsNoPin(csPin) {
cs = csPin.Set
}
// wire and pins must already be configured.
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) DeviceOf[T] {
return DeviceOf[T]{
bus: bus,
dcPin: dcPin.Set,
resetPin: resetPin.Set,
csPin: cs,
blPin: blPin.Set,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
blPin: blPin,
}
}
@@ -234,7 +225,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()
}
}
@@ -242,7 +233,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()
}
}
+3 -4
View File
@@ -9,7 +9,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/lora"
)
@@ -22,7 +21,7 @@ const (
// Device wraps an SPI connection to a SX127x device.
type Device struct {
spi drivers.SPI // SPI bus for module communication
rstPin drivers.PinOutput // GPIO for reset
rstPin drivers.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
@@ -43,10 +42,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 pin.Output) *Device {
func New(spi drivers.SPI, rstPin drivers.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),
+7 -15
View File
@@ -57,14 +57,10 @@ func (comm *UARTComm) WriteRegister(register uint8, value uint32, driverIndex ui
byte((value >> 16) & 0xFF), // Middle byte
byte((value >> 8) & 0xFF), // Next byte
byte(value & 0xFF), // LSB of value
0, // CRC
}
// Calculate checksum by XORing all bytes
checksum := byte(0)
for _, b := range buffer[:7] {
checksum ^= b
}
buffer[7] = checksum // Set checksum byte
buffer[7] = CalculateCRC(buffer[:7])
// Write the data to the TMC2209
done := make(chan error, 1)
@@ -86,10 +82,10 @@ func (comm *UARTComm) WriteRegister(register uint8, value uint32, driverIndex ui
// ReadRegister sends a register read command to the TMC2209 with a timeout.
func (comm *UARTComm) ReadRegister(register uint8, driverIndex uint8) (uint32, error) {
var writeBuffer [4]byte
writeBuffer[0] = 0x05 // Sync byte
writeBuffer[1] = 0x00 // Slave address
writeBuffer[2] = register & 0x7F // Read command (MSB clear for read)
writeBuffer[3] = writeBuffer[0] ^ writeBuffer[1] ^ writeBuffer[2] // Checksum
writeBuffer[0] = 0x05 // Sync byte
writeBuffer[1] = 0x00 // Slave address
writeBuffer[2] = register & 0x7F // Read command (MSB clear for read)
writeBuffer[3] = CalculateCRC(writeBuffer[:3])
// Send the read command
done := make(chan []byte, 1)
@@ -103,11 +99,7 @@ func (comm *UARTComm) ReadRegister(register uint8, driverIndex uint8) (uint32, e
// Implementing timeout using a 100ms timer
select {
case readBuffer := <-done:
// Validate checksum
checksum := byte(0)
for i := 0; i < 7; i++ {
checksum ^= readBuffer[i]
}
checksum := CalculateCRC(readBuffer[:7])
if checksum != readBuffer[7] {
return 0, CustomError("checksum error")
}
+14 -19
View File
@@ -11,8 +11,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/pixel"
)
@@ -32,10 +30,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
width int16
height int16
buffer []uint8
@@ -49,18 +47,15 @@ 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 pin.Output, busyPin pin.Input) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
// New returns a new uc8151 driver. Pass in a fully configured SPI bus and pins.
// busyPin should be set and input, the others as outputs.
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
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,
}
}
@@ -314,14 +309,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(10 * 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)
+1 -1
View File
@@ -2,4 +2,4 @@ package drivers
// Version returns a user-readable string showing the version of the drivers package for support purposes.
// Update this value before release of new version of software.
const Version = "0.30.0"
const Version = "0.32.0"
+15 -33
View File
@@ -14,8 +14,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type Config struct {
@@ -26,14 +24,14 @@ type Config struct {
}
type Device struct {
bus *machine.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
configurePins func()
buffer []uint8
rotation Rotation
bus *machine.SPI
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
buffer []uint8
rotation Rotation
}
type Rotation uint8
@@ -83,29 +81,18 @@ 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 pin.Output, busyPin pin.Input) Device {
func New(bus *machine.SPI, csPin, dcPin, rstPin, busyPin drivers.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.bus.Configure(machine.SPIConfig{
Frequency: 2000000,
Mode: 0,
@@ -160,11 +147,6 @@ func (d *Device) LDirInit(cfg Config) {
}
func (d *Device) HDirInit(cfg Config) {
if d.configurePins == nil {
panic(legacy.ErrConfigBeforeInstantiated)
}
d.configurePins()
d.bus.Configure(machine.SPIConfig{
Frequency: 2000000,
Mode: 0,
@@ -379,7 +361,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)
@@ -387,7 +369,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)
+14 -19
View File
@@ -9,8 +9,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type Config struct {
@@ -22,10 +20,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
logicalWidth int16
width int16
height int16
@@ -53,18 +51,15 @@ var lutPartialUpdate = [30]uint8{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus and pins.
// Busy pin should input, the rest should be output.
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
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,
}
}
@@ -299,14 +294,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)
+14 -19
View File
@@ -9,8 +9,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type Config struct {
@@ -21,10 +19,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
width int16
height int16
buffer [][]uint8
@@ -33,18 +31,15 @@ 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 pin.Output, busyPin pin.Input) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus and pins.
// Busy pin should input, the rest should be output.
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
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,
}
}
@@ -278,14 +273,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)
+24 -6
View File
@@ -17,12 +17,19 @@ const (
const Baudrate = 4_000_000 // 4 MHz
type Config struct {
ResetPin drivers.Pin
DataPin drivers.Pin
ChipSelectPin drivers.Pin
BusyPin drivers.Pin
}
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
bus drivers.SPI
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
blackBuffer []byte
redBuffer []byte
@@ -42,6 +49,17 @@ func New(bus drivers.SPI) Device {
}
}
// Configure configures the device. Note that pins should already
// be configured. Busy pin should be input, the rest should be output.
func (d *Device) Configure(c Config) error {
d.cs = c.ChipSelectPin
d.dc = c.DataPin
d.rst = c.ResetPin
d.busy = c.BusyPin
return nil
}
func (d *Device) Size() (x, y int16) {
return displayWidth, displayHeight
}
@@ -206,7 +224,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
}
+14 -19
View File
@@ -16,8 +16,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type Config struct {
@@ -29,10 +27,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
logicalWidth int16
width int16
height int16
@@ -61,18 +59,15 @@ var lutPartialUpdate = [30]uint8{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
// New returns a new epd2in9 driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
// New returns a new epd2in9 driver. Pass in a fully configured SPI bus and pins.
// Busy pin should input, the rest should be output.
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
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,
}
}
@@ -246,14 +241,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)
+14 -19
View File
@@ -13,8 +13,6 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
)
type Config struct {
@@ -26,10 +24,10 @@ type Config struct {
type Device struct {
bus drivers.SPI
cs drivers.PinOutput
dc drivers.PinOutput
rst drivers.PinOutput
isBusy drivers.PinInput
cs drivers.Pin
dc drivers.Pin
rst drivers.Pin
busy drivers.Pin
logicalWidth int16
width int16
height int16
@@ -40,18 +38,15 @@ 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 pin.Output, busyPin pin.Input) Device {
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(dcPin)
legacy.ConfigurePinOut(rstPin)
legacy.ConfigurePinInput(busyPin)
// New returns a new epd4in2 driver. Pass in a fully configured SPI bus and pins.
// Busy pin should input, the rest should be output.
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
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,
}
}
@@ -312,14 +307,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)
+469
View File
@@ -1320,6 +1320,465 @@ void ws2812_writeByte168(char c, uint32_t *portSet, uint32_t *portClear, uint32_
[maskClear]"r"(maskClear),
[portClear]"m"(*portClear));
}
__attribute__((always_inline))
void ws2812_writeByte200(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) {
// Timings:
// T0H: 70 - 72 cycles or 350.0ns - 360.0ns
// T1H: 210 - 212 cycles or 1050.0ns - 1060.0ns
// TLD: 230 - cycles or 1150.0ns -
uint32_t value = (uint32_t)c << 24;
char i = 8;
__asm__ __volatile__(
"1: @ send_bit\n"
"\t str %[maskSet], %[portSet] @ [2] T0H and T0L start here\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t lsls %[value], #1 @ [1]\n"
"\t bcs.n 2f @ [1/3] skip_store\n"
"\t str %[maskClear], %[portClear] @ [2] T0H -> T0L transition\n"
"\t2: @ skip_store\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t str %[maskClear], %[portClear] @ [2] T1H -> T1L transition\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t subs %[i], #1 @ [1]\n"
"\t beq.n 3f @ [1/3] end\n"
"\t b 1b @ [1/3] send_bit\n"
"\t3: @ end\n"
: [value]"+r"(value),
[i]"+r"(i)
: [maskSet]"r"(maskSet),
[portSet]"m"(*portSet),
[maskClear]"r"(maskClear),
[portClear]"m"(*portClear));
}
*/
import "C"
@@ -1382,3 +1841,13 @@ func (d Device) writeByte168(c byte) {
interrupt.Restore(mask)
}
func (d Device) writeByte200(c byte) {
portSet, maskSet := d.Pin.PortMaskSet()
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte200(C.char(c), (*C.uint32_t)(unsafe.Pointer(portSet)), (*C.uint32_t)(unsafe.Pointer(portClear)), C.uint32_t(maskSet), C.uint32_t(maskClear))
interrupt.Restore(mask)
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips.
package ws2812 // import "tinygo.org/x/drivers/ws2812"
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 168
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 168 200
//go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320
import (
+4 -1
View File
@@ -28,12 +28,15 @@ func (d Device) WriteByte(c byte) error {
case 120_000_000: // 120MHz
d.writeByte120(c)
return nil
case 125_000_000: // 125 MHz e.g. rp2040
case 125_000_000: // 125 MHz e.g. rp2040 originally
d.writeByte125(c)
return nil
case 168_000_000: // 168MHz, e.g. stm32f405
d.writeByte168(c)
return nil
case 200_000_000: // 200MHz, e.g. rp2040 starting with TinyGo v0.37
d.writeByte200(c)
return nil
default:
return errUnknownClockSpeed
}