mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-12 19:03:42 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 228e57cf98 | |||
| 6cf1eb86e5 | |||
| 857ab80ae6 | |||
| a31ba26a6c | |||
| 303ec94529 | |||
| 833990f44d | |||
| 28d87eb0c5 | |||
| ae9e8f915e | |||
| 45fad80c3e | |||
| 0304d30b78 | |||
| 7de0a0814e | |||
| 80356fd9d9 |
@@ -1,3 +1,28 @@
|
|||||||
|
0.33.0
|
||||||
|
---
|
||||||
|
- **new devices**
|
||||||
|
- **ens160**
|
||||||
|
- Add ens160 i2c driver
|
||||||
|
- **lsm303dlhc**
|
||||||
|
- added support for LSM303DLHC e-Compass; (#783)
|
||||||
|
- **seesaw**
|
||||||
|
- add support for Adafruit Seesaw encoders
|
||||||
|
|
||||||
|
- **enhancements**
|
||||||
|
- **ws2812**
|
||||||
|
- add RP2350 support
|
||||||
|
- **ssd1306**
|
||||||
|
- avoid unnecessary heap allocations (#767)
|
||||||
|
- **gps**
|
||||||
|
- allow gps init with address
|
||||||
|
- **lsm6ds3tr**
|
||||||
|
- avoid unnecessary heap allocations (#766)
|
||||||
|
|
||||||
|
- **bugfixes**
|
||||||
|
- **gps**
|
||||||
|
- Fix gps time calculation (#785)
|
||||||
|
|
||||||
|
|
||||||
0.32.0
|
0.32.0
|
||||||
---
|
---
|
||||||
- **enhancements**
|
- **enhancements**
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ package apa102 // import "tinygo.org/x/drivers/apa102"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
)
|
)
|
||||||
@@ -36,7 +37,7 @@ func New(b drivers.SPI) *Device {
|
|||||||
|
|
||||||
// NewSoftwareSPI returns a new APA102 driver that will use a software based
|
// NewSoftwareSPI returns a new APA102 driver that will use a software based
|
||||||
// implementation of the SPI protocol.
|
// implementation of the SPI protocol.
|
||||||
func NewSoftwareSPI(sckPin, sdoPin drivers.Pin, delay uint32) *Device {
|
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
|
||||||
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
|
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-7
@@ -1,8 +1,6 @@
|
|||||||
package apa102
|
package apa102
|
||||||
|
|
||||||
import (
|
import "machine"
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
|
||||||
|
|
||||||
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
|
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
|
||||||
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
|
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
|
||||||
@@ -10,14 +8,15 @@ import (
|
|||||||
// most purposes other than the APA102 package. It might be desirable to make
|
// 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.
|
// this more generic and include it in the TinyGo "machine" package instead.
|
||||||
type bbSPI struct {
|
type bbSPI struct {
|
||||||
SCK drivers.Pin
|
SCK machine.Pin
|
||||||
SDO drivers.Pin
|
SDO machine.Pin
|
||||||
Delay uint32
|
Delay uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure sets the SCK and SDO pins to low.
|
// Configure sets up the SCK and SDO pins as outputs and sets them low
|
||||||
// Note that the SCK and SDO pins must already be configured as outputs.
|
|
||||||
func (s *bbSPI) Configure() {
|
func (s *bbSPI) Configure() {
|
||||||
|
s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
s.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
s.SCK.Low()
|
s.SCK.Low()
|
||||||
s.SDO.Low()
|
s.SDO.Low()
|
||||||
if s.Delay == 0 {
|
if s.Delay == 0 {
|
||||||
|
|||||||
+7
-4
@@ -1,6 +1,7 @@
|
|||||||
package bmi160
|
package bmi160
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -10,7 +11,7 @@ import (
|
|||||||
// also an I2C interface, but it is not yet supported.
|
// also an I2C interface, but it is not yet supported.
|
||||||
type DeviceSPI struct {
|
type DeviceSPI struct {
|
||||||
// Chip select pin
|
// Chip select pin
|
||||||
CSB drivers.Pin
|
CSB machine.Pin
|
||||||
|
|
||||||
buf [7]byte
|
buf [7]byte
|
||||||
|
|
||||||
@@ -21,16 +22,18 @@ type DeviceSPI struct {
|
|||||||
// NewSPI returns a new device driver. The pin and SPI interface are not
|
// 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
|
// touched, provide a fully configured SPI object and call Configure to start
|
||||||
// using this device.
|
// using this device.
|
||||||
func NewSPI(csb drivers.Pin, spi drivers.SPI) *DeviceSPI {
|
func NewSPI(csb machine.Pin, spi drivers.SPI) *DeviceSPI {
|
||||||
return &DeviceSPI{
|
return &DeviceSPI{
|
||||||
CSB: csb, // chip select
|
CSB: csb, // chip select
|
||||||
Bus: spi,
|
Bus: spi,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures the BMI160 for use. The CSB pin anf the SPI interface
|
// Configure configures the BMI160 for use. It configures the CSB pin and
|
||||||
// should be configured already. This function configures the BMI160 only.
|
// configures the BMI160, but it does not configure the SPI interface (it is
|
||||||
|
// assumed to be up and running).
|
||||||
func (d *DeviceSPI) Configure() error {
|
func (d *DeviceSPI) Configure() error {
|
||||||
|
d.CSB.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
d.CSB.High()
|
d.CSB.High()
|
||||||
|
|
||||||
// The datasheet recommends doing a register read from address 0x7F to get
|
// The datasheet recommends doing a register read from address 0x7F to get
|
||||||
|
|||||||
+4
-4
@@ -2,20 +2,20 @@
|
|||||||
package buzzer // import "tinygo.org/x/drivers/buzzer"
|
package buzzer // import "tinygo.org/x/drivers/buzzer"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"machine"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Device wraps a GPIO connection to a buzzer.
|
// Device wraps a GPIO connection to a buzzer.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
pin drivers.Pin
|
pin machine.Pin
|
||||||
High bool
|
High bool
|
||||||
BPM float64
|
BPM float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new buzzer driver given which pin to use
|
// New returns a new buzzer driver given which pin to use
|
||||||
func New(pin drivers.Pin) Device {
|
func New(pin machine.Pin) Device {
|
||||||
return Device{
|
return Device{
|
||||||
pin: pin,
|
pin: pin,
|
||||||
High: false,
|
High: false,
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ package easystepper // import "tinygo.org/x/drivers/easystepper"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// StepMode determines the coil sequence used to perform a single step
|
// StepMode determines the coil sequence used to perform a single step
|
||||||
@@ -34,7 +33,7 @@ func (sm StepMode) stepCount() uint {
|
|||||||
// DeviceConfig contains the configuration data for a single easystepper driver
|
// DeviceConfig contains the configuration data for a single easystepper driver
|
||||||
type DeviceConfig struct {
|
type DeviceConfig struct {
|
||||||
// Pin1 ... Pin4 determines the pins to configure and use for the device
|
// Pin1 ... Pin4 determines the pins to configure and use for the device
|
||||||
Pin1, Pin2, Pin3, Pin4 drivers.Pin
|
Pin1, Pin2, Pin3, Pin4 machine.Pin
|
||||||
// StepCount is the number of steps required to perform a full revolution of the stepper motor
|
// StepCount is the number of steps required to perform a full revolution of the stepper motor
|
||||||
StepCount uint
|
StepCount uint
|
||||||
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
|
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
|
||||||
@@ -47,12 +46,12 @@ type DeviceConfig struct {
|
|||||||
type DualDeviceConfig struct {
|
type DualDeviceConfig struct {
|
||||||
DeviceConfig
|
DeviceConfig
|
||||||
// Pin5 ... Pin8 determines the pins to configure and use for the second device
|
// Pin5 ... Pin8 determines the pins to configure and use for the second device
|
||||||
Pin5, Pin6, Pin7, Pin8 drivers.Pin
|
Pin5, Pin6, Pin7, Pin8 machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device holds the pins and the delay between steps
|
// Device holds the pins and the delay between steps
|
||||||
type Device struct {
|
type Device struct {
|
||||||
pins [4]drivers.Pin
|
pins [4]machine.Pin
|
||||||
stepDelay time.Duration
|
stepDelay time.Duration
|
||||||
stepNumber uint8
|
stepNumber uint8
|
||||||
stepMode StepMode
|
stepMode StepMode
|
||||||
@@ -69,15 +68,17 @@ func New(config DeviceConfig) (*Device, error) {
|
|||||||
return nil, errors.New("config.StepCount and config.RPM must be > 0")
|
return nil, errors.New("config.StepCount and config.RPM must be > 0")
|
||||||
}
|
}
|
||||||
return &Device{
|
return &Device{
|
||||||
pins: [4]drivers.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
|
pins: [4]machine.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
|
||||||
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
|
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
|
||||||
stepMode: config.Mode,
|
stepMode: config.Mode,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure does nothing, as it assumes that the pins of the Device have already
|
// Configure configures the pins of the Device
|
||||||
// been configured by the user as outputs.
|
|
||||||
func (d *Device) Configure() {
|
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
|
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
// Package ens160 provides a driver for the ScioSense ENS160 digital gas sensor.
|
||||||
|
//
|
||||||
|
// Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
|
||||||
|
package ens160
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultTimeout = 30 * time.Millisecond
|
||||||
|
shortTimeout = 1 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
|
// Conversion constants for environment data compensation.
|
||||||
|
const (
|
||||||
|
kelvinOffsetMilli = 273150 // 273.15 K in milli-units
|
||||||
|
tempRawFactor = 64 // As per datasheet for TEMP_IN
|
||||||
|
humRawFactor = 512 // As per datasheet for RH_IN
|
||||||
|
milliFactor = 1000 // For converting from milli-units
|
||||||
|
roundingTerm = milliFactor / 2 // For rounding before integer division
|
||||||
|
)
|
||||||
|
|
||||||
|
// validityStrings provides human-readable descriptions for validity flags.
|
||||||
|
var validityStrings = [...]string{
|
||||||
|
ValidityNormalOperation: "normal operation",
|
||||||
|
ValidityWarmUpPhase: "warm-up phase, wait ~3 minutes for valid data",
|
||||||
|
ValidityInitialStartUpPhase: "initial start-up phase, wait ~1 hour for valid data",
|
||||||
|
ValidityInvalidOutput: "invalid output",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device wraps an I2C connection to an ENS160 device.
|
||||||
|
type Device struct {
|
||||||
|
bus drivers.I2C // I²C implementation
|
||||||
|
addr uint16 // 7‑bit bus address, promoted to uint16 per drivers.I2C
|
||||||
|
|
||||||
|
// shadow registers / last measurements
|
||||||
|
lastTvocPPB uint16
|
||||||
|
lastEco2PPM uint16
|
||||||
|
lastAqiUBA uint8
|
||||||
|
lastValidity uint8 // Store the latest validity status
|
||||||
|
|
||||||
|
// pre‑allocated buffers
|
||||||
|
wbuf [5]byte // longest write: reg + 4 bytes (TEMP+RH)
|
||||||
|
rbuf [5]byte // longest read: DATA burst (5 bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new ENS160 driver.
|
||||||
|
func New(bus drivers.I2C, addr uint16) *Device {
|
||||||
|
if addr == 0 {
|
||||||
|
addr = DefaultAddress
|
||||||
|
}
|
||||||
|
return &Device{
|
||||||
|
bus: bus,
|
||||||
|
addr: addr,
|
||||||
|
lastValidity: ValidityInvalidOutput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connected returns whether a ENS160 has been found.
|
||||||
|
func (d *Device) Connected() bool {
|
||||||
|
d.wbuf[0] = regPartID
|
||||||
|
err := d.bus.Tx(d.addr, d.wbuf[:1], d.rbuf[:2])
|
||||||
|
return err == nil && d.rbuf[0] == LowPartID && d.rbuf[1] == HighPartID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure sets up the device for reading.
|
||||||
|
func (d *Device) Configure() error {
|
||||||
|
// 1. Soft-reset. The device will automatically enter IDLE mode.
|
||||||
|
if err := d.write1(regOpMode, ModeReset); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(defaultTimeout)
|
||||||
|
|
||||||
|
// 2. Clear GPR registers, then go to STANDARD mode.
|
||||||
|
if err := d.write1(regCommand, cmdClrGPR); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(defaultTimeout)
|
||||||
|
|
||||||
|
if err := d.write1(regOpMode, ModeStandard); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(defaultTimeout)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateTempRaw converts temperature from milli-degrees Celsius to the sensor's raw format.
|
||||||
|
func calculateTempRaw(tempMilliC int32) uint16 {
|
||||||
|
// Clip temperature
|
||||||
|
const (
|
||||||
|
minC = -40 * 1000
|
||||||
|
maxC = 85 * 1000
|
||||||
|
)
|
||||||
|
if tempMilliC < minC {
|
||||||
|
tempMilliC = minC
|
||||||
|
} else if tempMilliC > maxC {
|
||||||
|
tempMilliC = maxC
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integer fixed-point conversion to format required by the sensor.
|
||||||
|
// Formula from datasheet: T_IN = (T_ambient_C + 273.15) * 64
|
||||||
|
return uint16((((tempMilliC + kelvinOffsetMilli) * tempRawFactor) + roundingTerm) / milliFactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateHumRaw converts relative humidity from milli-percent to the sensor's raw format.
|
||||||
|
func calculateHumRaw(rhMilliPct int32) uint16 {
|
||||||
|
// Clip humidity
|
||||||
|
if rhMilliPct < 0 {
|
||||||
|
rhMilliPct = 0
|
||||||
|
} else if rhMilliPct > 100*1000 {
|
||||||
|
rhMilliPct = 100 * 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integer fixed-point conversion to format required by the sensor.
|
||||||
|
// Formula from datasheet: RH_IN = (RH_ambient_% * 512)
|
||||||
|
return uint16(((rhMilliPct * humRawFactor) + roundingTerm) / milliFactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEnvDataMilli sets the ambient temperature and humidity for compensation.
|
||||||
|
//
|
||||||
|
// tempMilliC is the temperature in milli-degrees Celsius.
|
||||||
|
// rhMilliPct is the relative humidity in milli-percent.
|
||||||
|
func (d *Device) SetEnvDataMilli(tempMilliC, rhMilliPct int32) error {
|
||||||
|
tempRaw := calculateTempRaw(tempMilliC)
|
||||||
|
humRaw := calculateHumRaw(rhMilliPct)
|
||||||
|
|
||||||
|
d.wbuf[0] = regTempIn // start address (auto‑increment)
|
||||||
|
binary.LittleEndian.PutUint16(d.wbuf[1:3], tempRaw)
|
||||||
|
binary.LittleEndian.PutUint16(d.wbuf[3:5], humRaw)
|
||||||
|
|
||||||
|
return d.bus.Tx(d.addr, d.wbuf[:5], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update refreshes the concentration measurements.
|
||||||
|
func (d *Device) Update(which drivers.Measurement) error {
|
||||||
|
if which&drivers.Concentration == 0 {
|
||||||
|
return nil // nothing requested
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxTries = 1000
|
||||||
|
var (
|
||||||
|
status uint8
|
||||||
|
validity uint8
|
||||||
|
)
|
||||||
|
var gotData bool
|
||||||
|
|
||||||
|
// Poll DEVICE_STATUS until NEWDAT or timeout
|
||||||
|
for range maxTries {
|
||||||
|
var err error
|
||||||
|
status, err = d.read1(regStatus)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if status&statusSTATER != 0 {
|
||||||
|
return errors.New("ENS160: error (STATER set)")
|
||||||
|
}
|
||||||
|
validity = (status & statusValidityMask) >> statusValidityShift
|
||||||
|
|
||||||
|
if status&statusNEWDAT != 0 {
|
||||||
|
gotData = true
|
||||||
|
break // Always break when data available
|
||||||
|
}
|
||||||
|
time.Sleep(shortTimeout)
|
||||||
|
}
|
||||||
|
if !gotData {
|
||||||
|
return errors.New("ENS160: timeout waiting for NEWDAT")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst-read data regardless of validity state
|
||||||
|
d.wbuf[0] = regAQI
|
||||||
|
if err := d.bus.Tx(d.addr, d.wbuf[:1], d.rbuf[:5]); err != nil {
|
||||||
|
return errors.New("ENS160: burst read failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.lastAqiUBA = d.rbuf[0]
|
||||||
|
d.lastTvocPPB = binary.LittleEndian.Uint16(d.rbuf[1:3])
|
||||||
|
d.lastEco2PPM = binary.LittleEndian.Uint16(d.rbuf[3:5])
|
||||||
|
d.lastValidity = validity // Store the validity status
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TVOC returns the last total‑VOC concentration in parts‑per‑billion.
|
||||||
|
func (d *Device) TVOC() uint16 { return d.lastTvocPPB }
|
||||||
|
|
||||||
|
// ECO2 returns the last equivalent CO₂ concentration in parts‑per‑million.
|
||||||
|
func (d *Device) ECO2() uint16 { return d.lastEco2PPM }
|
||||||
|
|
||||||
|
// AQI returns the last Air‑Quality Index according to UBA (1–5).
|
||||||
|
func (d *Device) AQI() uint8 { return d.lastAqiUBA }
|
||||||
|
|
||||||
|
// Validity returns the current operating state of the sensor.
|
||||||
|
func (d *Device) Validity() uint8 {
|
||||||
|
return d.lastValidity
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidityString returns a human-readable string describing the current validity status.
|
||||||
|
func (d *Device) ValidityString() string {
|
||||||
|
if int(d.lastValidity) < len(validityStrings) {
|
||||||
|
return validityStrings[d.lastValidity]
|
||||||
|
}
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// write1 writes a single byte to a register.
|
||||||
|
func (d *Device) write1(reg, val uint8) error {
|
||||||
|
d.wbuf[0] = reg
|
||||||
|
d.wbuf[1] = val
|
||||||
|
return d.bus.Tx(d.addr, d.wbuf[:2], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read1 reads a single byte from a register.
|
||||||
|
func (d *Device) read1(reg uint8) (uint8, error) {
|
||||||
|
d.wbuf[0] = reg
|
||||||
|
if err := d.bus.Tx(d.addr, d.wbuf[:1], d.rbuf[:1]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return d.rbuf[0], nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package ens160
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCalculateTempRaw(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tempMilliC int32
|
||||||
|
expectedRaw uint16
|
||||||
|
}{
|
||||||
|
{"25°C", 25000, 19082},
|
||||||
|
{"-10.5°C", -10500, 16810},
|
||||||
|
{"Min temp", -40000, 14922},
|
||||||
|
{"Below min", -50000, 14922},
|
||||||
|
{"Max temp", 85000, 22922},
|
||||||
|
{"Above max", 90000, 22922},
|
||||||
|
{"Zero", 0, 17482},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
raw := calculateTempRaw(tc.tempMilliC)
|
||||||
|
if raw != tc.expectedRaw {
|
||||||
|
t.Errorf("expected %d, got %d", tc.expectedRaw, raw)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculateHumRaw(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
rhMilliPct int32
|
||||||
|
expectedRaw uint16
|
||||||
|
}{
|
||||||
|
{"50%", 50000, 25600},
|
||||||
|
{"0%", 0, 0},
|
||||||
|
{"100%", 100000, 51200},
|
||||||
|
{"Below 0%", -10000, 0},
|
||||||
|
{"Above 100%", 110000, 51200},
|
||||||
|
{"33.3%", 33300, 17050},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
raw := calculateHumRaw(tc.rhMilliPct)
|
||||||
|
if raw != tc.expectedRaw {
|
||||||
|
t.Errorf("expected %d, got %d", tc.expectedRaw, raw)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package ens160
|
||||||
|
|
||||||
|
// DefaultAddress is the default I2C address for the ENS160 when the ADDR pin is
|
||||||
|
// connected to high (3.3V). When connected to low (GND), the address is 0x52.
|
||||||
|
const DefaultAddress = 0x53
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
const (
|
||||||
|
regPartID = 0x00
|
||||||
|
regOpMode = 0x10
|
||||||
|
regConfig = 0x11
|
||||||
|
regCommand = 0x12
|
||||||
|
regTempIn = 0x13
|
||||||
|
regRhIn = 0x15
|
||||||
|
regStatus = 0x20
|
||||||
|
regAQI = 0x21
|
||||||
|
regTVOC = 0x22
|
||||||
|
regECO2 = 0x24
|
||||||
|
regDataT = 0x30
|
||||||
|
regDataRH = 0x32
|
||||||
|
regMISR = 0x38
|
||||||
|
regGPRWrite = 0x40
|
||||||
|
regGPRRead = 0x48
|
||||||
|
)
|
||||||
|
|
||||||
|
// Operating modes
|
||||||
|
const (
|
||||||
|
ModeDeepSleep = 0x00
|
||||||
|
ModeIdle = 0x01
|
||||||
|
ModeStandard = 0x02
|
||||||
|
ModeReset = 0xF0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status register bits
|
||||||
|
const (
|
||||||
|
statusSTATAS = 1 << 7
|
||||||
|
statusSTATER = 1 << 6
|
||||||
|
|
||||||
|
statusValidityMask = 0x0C
|
||||||
|
statusValidityShift = 2
|
||||||
|
|
||||||
|
statusNEWDAT = 1 << 1
|
||||||
|
statusNEWGPR = 1 << 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validity flags
|
||||||
|
const (
|
||||||
|
ValidityNormalOperation = 0x00
|
||||||
|
ValidityWarmUpPhase = 0x01 // need ~3 minutes until valid data
|
||||||
|
ValidityInitialStartUpPhase = 0x02 // need ~1 hour until valid data
|
||||||
|
ValidityInvalidOutput = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
const (
|
||||||
|
cmdNOP = 0x00
|
||||||
|
cmdGetAppVer = 0x0E
|
||||||
|
cmdClrGPR = 0xCC
|
||||||
|
)
|
||||||
|
|
||||||
|
// Part IDs
|
||||||
|
const (
|
||||||
|
LowPartID = 0x60
|
||||||
|
HighPartID = 0x01
|
||||||
|
)
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// This example demonstrates ENS160 usage.
|
||||||
|
//
|
||||||
|
// Wiring:
|
||||||
|
// - VCC to 3.3V, GND to ground
|
||||||
|
// - SDA to board SDA, SCL to board SCL
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
"tinygo.org/x/drivers/ens160"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := machine.I2C0.Configure(machine.I2CConfig{
|
||||||
|
Frequency: 400 * machine.KHz,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
println("Failed to configure I2C:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dev := ens160.New(machine.I2C0, ens160.DefaultAddress)
|
||||||
|
|
||||||
|
connected := dev.Connected()
|
||||||
|
if !connected {
|
||||||
|
println("ENS160 not detected")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println("ENS160 detected")
|
||||||
|
|
||||||
|
if err := dev.Configure(); err != nil {
|
||||||
|
println("Failed to configure ENS160:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
err := dev.Update(drivers.Concentration)
|
||||||
|
if err != nil {
|
||||||
|
println("Error reading ENS160: %v\n", err)
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
println(
|
||||||
|
"AQI:", dev.AQI(),
|
||||||
|
"TVOC:", dev.TVOC(),
|
||||||
|
"eCO2:", dev.ECO2(),
|
||||||
|
"Validity:", dev.ValidityString(),
|
||||||
|
)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/lsm303dlhc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// LSM303DLHC is connected to the I2C0 bus on Adafruit Feather M4 via pins: 20(SDA) and 21(SCL).
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
|
|
||||||
|
sensor := lsm303dlhc.New(machine.I2C0)
|
||||||
|
//default settings
|
||||||
|
err := sensor.Configure(lsm303dlhc.Configuration{
|
||||||
|
AccelPowerMode: lsm303dlhc.ACCEL_POWER_NORMAL,
|
||||||
|
AccelRange: lsm303dlhc.ACCEL_RANGE_2G,
|
||||||
|
AccelDataRate: lsm303dlhc.ACCEL_DATARATE_100HZ,
|
||||||
|
MagPowerMode: lsm303dlhc.MAG_POWER_NORMAL,
|
||||||
|
MagSystemMode: lsm303dlhc.MAG_SYSTEM_CONTINUOUS,
|
||||||
|
MagDataRate: lsm303dlhc.MAG_DATARATE_10HZ,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
for {
|
||||||
|
println("Failed to configure", err.Error())
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
accel_x, accel_y, accel_z, err := sensor.ReadAcceleration()
|
||||||
|
if err != nil {
|
||||||
|
println("Failed to read accel", err.Error())
|
||||||
|
}
|
||||||
|
println("ACCEL_X:", accel_x, " ACCEL_Y:", accel_y, " ACCEL_Z:", accel_z)
|
||||||
|
|
||||||
|
mag_x, mag_y, mag_z, err := sensor.ReadMagneticField()
|
||||||
|
if err != nil {
|
||||||
|
println("Failed to read mag", err.Error())
|
||||||
|
}
|
||||||
|
println("MAG_X:", mag_x, " MAG_Y:", mag_y, " MAG_Z:", mag_z)
|
||||||
|
|
||||||
|
pitch, roll, _ := sensor.ReadPitchRoll()
|
||||||
|
println("Pitch:", float32(pitch), " Roll:", float32(roll))
|
||||||
|
|
||||||
|
heading, _ := sensor.ReadCompass()
|
||||||
|
println("Heading:", float32(heading), "degrees")
|
||||||
|
|
||||||
|
temp, _ := sensor.ReadTemperature()
|
||||||
|
println("Temperature:", float32(temp)/1000, "*C")
|
||||||
|
|
||||||
|
println("\n")
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/seesaw"
|
||||||
|
)
|
||||||
|
|
||||||
|
// example reading the position of a rotary encoder (4991) powered by a seesaw
|
||||||
|
// https://learn.adafruit.com/adafruit-i2c-qt-rotary-encoder/arduino
|
||||||
|
func main() {
|
||||||
|
// This assumes you are using an Adafruit QT Py RP2040 for its Stemma QT connector
|
||||||
|
// https://www.adafruit.com/product/4900
|
||||||
|
i2c := machine.I2C1
|
||||||
|
i2c.Configure(machine.I2CConfig{
|
||||||
|
SCL: machine.I2C1_QT_SCL_PIN,
|
||||||
|
SDA: machine.I2C1_QT_SDA_PIN,
|
||||||
|
})
|
||||||
|
|
||||||
|
dev := seesaw.New(i2c)
|
||||||
|
dev.Address = 0x36
|
||||||
|
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
pos, err := dev.GetEncoderPosition(0, false)
|
||||||
|
if err != nil {
|
||||||
|
println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
println(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"image/color"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/ssd1306"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.I2C0.Configure(machine.I2CConfig{
|
|
||||||
Frequency: machine.TWI_FREQ_400KHZ,
|
|
||||||
})
|
|
||||||
|
|
||||||
display := ssd1306.NewI2C(machine.I2C0)
|
|
||||||
display.Configure(ssd1306.Config{
|
|
||||||
Address: ssd1306.Address_128_32,
|
|
||||||
Width: 128,
|
|
||||||
Height: 32,
|
|
||||||
})
|
|
||||||
|
|
||||||
display.ClearDisplay()
|
|
||||||
|
|
||||||
x := int16(0)
|
|
||||||
y := int16(0)
|
|
||||||
deltaX := int16(1)
|
|
||||||
deltaY := int16(1)
|
|
||||||
for {
|
|
||||||
pixel := display.GetPixel(x, y)
|
|
||||||
c := color.RGBA{255, 255, 255, 255}
|
|
||||||
if pixel {
|
|
||||||
c = color.RGBA{0, 0, 0, 255}
|
|
||||||
}
|
|
||||||
display.SetPixel(x, y, c)
|
|
||||||
display.Display()
|
|
||||||
|
|
||||||
x += deltaX
|
|
||||||
y += deltaY
|
|
||||||
|
|
||||||
if x == 0 || x == 127 {
|
|
||||||
deltaX = -deltaX
|
|
||||||
}
|
|
||||||
|
|
||||||
if y == 0 || y == 31 {
|
|
||||||
deltaY = -deltaY
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// This example shows how to use 128x64 display over I2C
|
|
||||||
// Tested on Seeeduino XIAO Expansion Board https://wiki.seeedstudio.com/Seeeduino-XIAO-Expansion-Board/
|
|
||||||
//
|
|
||||||
// According to manual, I2C address of the display is 0x78, but that's 8-bit address.
|
|
||||||
// TinyGo operates on 7-bit addresses and respective 7-bit address would be 0x3C, which we use below.
|
|
||||||
//
|
|
||||||
// To learn more about different types of I2C addresses, please see following page
|
|
||||||
// https://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"image/color"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/ssd1306"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.I2C0.Configure(machine.I2CConfig{
|
|
||||||
Frequency: machine.TWI_FREQ_400KHZ,
|
|
||||||
})
|
|
||||||
|
|
||||||
display := ssd1306.NewI2C(machine.I2C0)
|
|
||||||
display.Configure(ssd1306.Config{
|
|
||||||
Address: 0x3C,
|
|
||||||
Width: 128,
|
|
||||||
Height: 64,
|
|
||||||
})
|
|
||||||
|
|
||||||
display.ClearDisplay()
|
|
||||||
|
|
||||||
x := int16(0)
|
|
||||||
y := int16(0)
|
|
||||||
deltaX := int16(1)
|
|
||||||
deltaY := int16(1)
|
|
||||||
for {
|
|
||||||
pixel := display.GetPixel(x, y)
|
|
||||||
c := color.RGBA{255, 255, 255, 255}
|
|
||||||
if pixel {
|
|
||||||
c = color.RGBA{0, 0, 0, 255}
|
|
||||||
}
|
|
||||||
display.SetPixel(x, y, c)
|
|
||||||
display.Display()
|
|
||||||
|
|
||||||
x += deltaX
|
|
||||||
y += deltaY
|
|
||||||
|
|
||||||
if x == 0 || x == 127 {
|
|
||||||
deltaX = -deltaX
|
|
||||||
}
|
|
||||||
|
|
||||||
if y == 0 || y == 63 {
|
|
||||||
deltaY = -deltaY
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// This example shows how to use SSD1306 OLED display driver over I2C and SPI.
|
||||||
|
//
|
||||||
|
// Check the `newSSD1306Display()` functions for I2C and SPI initializations.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"image/color"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
display := newSSD1306Display()
|
||||||
|
display.ClearDisplay()
|
||||||
|
|
||||||
|
w, h := display.Size()
|
||||||
|
x := int16(0)
|
||||||
|
y := int16(0)
|
||||||
|
deltaX := int16(1)
|
||||||
|
deltaY := int16(1)
|
||||||
|
|
||||||
|
traceTime := time.Now().UnixMilli() + 1000
|
||||||
|
frames := 0
|
||||||
|
ms := runtime.MemStats{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
pixel := display.GetPixel(x, y)
|
||||||
|
c := color.RGBA{255, 255, 255, 255}
|
||||||
|
if pixel {
|
||||||
|
c = color.RGBA{0, 0, 0, 255}
|
||||||
|
}
|
||||||
|
display.SetPixel(x, y, c)
|
||||||
|
display.Display()
|
||||||
|
|
||||||
|
x += deltaX
|
||||||
|
y += deltaY
|
||||||
|
|
||||||
|
if x == 0 || x == w-1 {
|
||||||
|
deltaX = -deltaX
|
||||||
|
}
|
||||||
|
|
||||||
|
if y == 0 || y == h-1 {
|
||||||
|
deltaY = -deltaY
|
||||||
|
}
|
||||||
|
|
||||||
|
frames++
|
||||||
|
now := time.Now().UnixMilli()
|
||||||
|
if now >= traceTime {
|
||||||
|
runtime.ReadMemStats(&ms)
|
||||||
|
println("TS", now, "| FPS", frames, "| HeapInuse", ms.HeapInuse)
|
||||||
|
traceTime = now + 1000
|
||||||
|
frames = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//go:build xiao_ble
|
||||||
|
|
||||||
|
// This initializes SSD1306 OLED display driver over I2C.
|
||||||
|
//
|
||||||
|
// Seeed XIAO BLE board + SSD1306 128x32 I2C OLED display.
|
||||||
|
//
|
||||||
|
// Wiring:
|
||||||
|
// - XIAO GND -> OLED GND
|
||||||
|
// - XIAO 3v3 -> OLED VCC
|
||||||
|
// - XIAO D4 (SDA) -> OLED SDA
|
||||||
|
// - XIAO D5 (SCL) -> OLED SCK
|
||||||
|
//
|
||||||
|
// For your case:
|
||||||
|
// - Connect the display to I2C pins on your board.
|
||||||
|
// - Adjust I2C address and display size as needed.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/ssd1306"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSSD1306Display() *ssd1306.Device {
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{
|
||||||
|
Frequency: 400 * machine.KHz,
|
||||||
|
SDA: machine.SDA0_PIN,
|
||||||
|
SCL: machine.SCL0_PIN,
|
||||||
|
})
|
||||||
|
display := ssd1306.NewI2C(machine.I2C0)
|
||||||
|
display.Configure(ssd1306.Config{
|
||||||
|
Address: ssd1306.Address_128_32, // or ssd1306.Address
|
||||||
|
Width: 128,
|
||||||
|
Height: 32, // or 64
|
||||||
|
})
|
||||||
|
return display
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//go:build thumby
|
||||||
|
|
||||||
|
// This initializes SSD1306 OLED display driver over SPI.
|
||||||
|
//
|
||||||
|
// Thumby board has a tiny built-in 72x40 display.
|
||||||
|
//
|
||||||
|
// As the display is built-in, no wiring is needed.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/ssd1306"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSSD1306Display() *ssd1306.Device {
|
||||||
|
machine.SPI0.Configure(machine.SPIConfig{})
|
||||||
|
display := ssd1306.NewSPI(machine.SPI0, machine.THUMBY_DC_PIN, machine.THUMBY_RESET_PIN, machine.THUMBY_CS_PIN)
|
||||||
|
display.Configure(ssd1306.Config{
|
||||||
|
Width: 72,
|
||||||
|
Height: 40,
|
||||||
|
ResetCol: ssd1306.ResetValue{28, 99},
|
||||||
|
ResetPage: ssd1306.ResetValue{0, 5},
|
||||||
|
})
|
||||||
|
return display
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
//go:build xiao_rp2040
|
||||||
|
|
||||||
|
// This initializes SSD1306 OLED display driver over SPI.
|
||||||
|
//
|
||||||
|
// Seeed XIAO RP2040 board + SSD1306 128x64 SPI OLED display.
|
||||||
|
//
|
||||||
|
// Wiring:
|
||||||
|
// - XIAO GND -> OLED GND
|
||||||
|
// - XIAO 3v3 -> OLED VCC
|
||||||
|
// - XIAO D8 (SCK) -> OLED D0
|
||||||
|
// - XIAO D10 (SDO) -> OLED D1
|
||||||
|
// - XIAO D4 -> OLED RES
|
||||||
|
// - XIAO D5 -> OLED DC
|
||||||
|
// - XIAO D6 -> OLED CS
|
||||||
|
//
|
||||||
|
// For your case:
|
||||||
|
// - Connect the display to SPI pins on your board.
|
||||||
|
// - Adjust RES, DC and CS pins as needed.
|
||||||
|
// - Adjust SPI frequency as needed.
|
||||||
|
// - Adjust display size as needed.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/ssd1306"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSSD1306Display() *ssd1306.Device {
|
||||||
|
machine.SPI0.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 50 * machine.MHz,
|
||||||
|
})
|
||||||
|
display := ssd1306.NewSPI(machine.SPI0, machine.D5, machine.D4, machine.D6)
|
||||||
|
display.Configure(ssd1306.Config{
|
||||||
|
Width: 128,
|
||||||
|
Height: 64,
|
||||||
|
})
|
||||||
|
return display
|
||||||
|
}
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image/color"
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/ssd1306"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.SPI0.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8000000,
|
|
||||||
})
|
|
||||||
display := ssd1306.NewSPI(machine.SPI0, machine.P8, machine.P7, machine.P9)
|
|
||||||
display.Configure(ssd1306.Config{
|
|
||||||
Width: 128,
|
|
||||||
Height: 64,
|
|
||||||
})
|
|
||||||
|
|
||||||
display.ClearDisplay()
|
|
||||||
|
|
||||||
x := int16(64)
|
|
||||||
y := int16(32)
|
|
||||||
deltaX := int16(1)
|
|
||||||
deltaY := int16(1)
|
|
||||||
for {
|
|
||||||
pixel := display.GetPixel(x, y)
|
|
||||||
c := color.RGBA{255, 255, 255, 255}
|
|
||||||
if pixel {
|
|
||||||
c = color.RGBA{0, 0, 0, 255}
|
|
||||||
}
|
|
||||||
display.SetPixel(x, y, c)
|
|
||||||
display.Display()
|
|
||||||
|
|
||||||
x += deltaX
|
|
||||||
y += deltaY
|
|
||||||
|
|
||||||
if x == 0 || x == 127 {
|
|
||||||
deltaX = -deltaX
|
|
||||||
}
|
|
||||||
|
|
||||||
if y == 0 || y == 63 {
|
|
||||||
deltaY = -deltaY
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// This example using the SSD1306 OLED display over SPI on the Thumby board
|
|
||||||
// A very tiny 72x40 display.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image/color"
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/ssd1306"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.SPI0.Configure(machine.SPIConfig{})
|
|
||||||
display := ssd1306.NewSPI(machine.SPI0, machine.THUMBY_DC_PIN, machine.THUMBY_RESET_PIN, machine.THUMBY_CS_PIN)
|
|
||||||
display.Configure(ssd1306.Config{
|
|
||||||
Width: 72,
|
|
||||||
Height: 40,
|
|
||||||
ResetCol: ssd1306.ResetValue{28, 99},
|
|
||||||
ResetPage: ssd1306.ResetValue{0, 5},
|
|
||||||
})
|
|
||||||
|
|
||||||
display.ClearDisplay()
|
|
||||||
|
|
||||||
x := int16(36)
|
|
||||||
y := int16(20)
|
|
||||||
deltaX := int16(1)
|
|
||||||
deltaY := int16(1)
|
|
||||||
for {
|
|
||||||
pixel := display.GetPixel(x, y)
|
|
||||||
c := color.RGBA{255, 255, 255, 255}
|
|
||||||
if pixel {
|
|
||||||
c = color.RGBA{0, 0, 0, 255}
|
|
||||||
}
|
|
||||||
display.SetPixel(x, y, c)
|
|
||||||
display.Display()
|
|
||||||
|
|
||||||
x += deltaX
|
|
||||||
y += deltaY
|
|
||||||
|
|
||||||
if x == 0 || x == 71 {
|
|
||||||
deltaX = -deltaX
|
|
||||||
}
|
|
||||||
|
|
||||||
if y == 0 || y == 39 {
|
|
||||||
deltaY = -deltaY
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+6
-4
@@ -5,6 +5,8 @@
|
|||||||
package ft6336
|
package ft6336
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
"tinygo.org/x/drivers/internal/legacy"
|
||||||
"tinygo.org/x/drivers/touch"
|
"tinygo.org/x/drivers/touch"
|
||||||
@@ -15,11 +17,11 @@ type Device struct {
|
|||||||
bus drivers.I2C
|
bus drivers.I2C
|
||||||
buf []byte
|
buf []byte
|
||||||
Address uint8
|
Address uint8
|
||||||
intPin drivers.Pin
|
intPin machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns FT6336 device for the provided I2C bus using default address.
|
// New returns FT6336 device for the provided I2C bus using default address.
|
||||||
func New(i2c drivers.I2C, intPin drivers.Pin) *Device {
|
func New(i2c drivers.I2C, intPin machine.Pin) *Device {
|
||||||
return &Device{
|
return &Device{
|
||||||
bus: i2c,
|
bus: i2c,
|
||||||
buf: make([]byte, 11),
|
buf: make([]byte, 11),
|
||||||
@@ -32,10 +34,10 @@ func New(i2c drivers.I2C, intPin drivers.Pin) *Device {
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the FT6336 device. Note that the interrupt pin must be configured
|
// Configure the FT6336 device.
|
||||||
// separately as an input.
|
|
||||||
func (d *Device) Configure(config Config) error {
|
func (d *Device) Configure(config Config) error {
|
||||||
d.write1Byte(0xA4, 0x00)
|
d.write1Byte(0xA4, 0x00)
|
||||||
|
d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -5,6 +5,7 @@ package gc9a01 // import "tinygo.org/x/drivers/gc9a01"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
@@ -21,10 +22,10 @@ type FrameRate uint8
|
|||||||
// Device wraps an SPI connection.
|
// Device wraps an SPI connection.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
dcPin drivers.Pin
|
dcPin machine.Pin
|
||||||
resetPin drivers.Pin
|
resetPin machine.Pin
|
||||||
csPin drivers.Pin
|
csPin machine.Pin
|
||||||
blPin drivers.Pin
|
blPin machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
columnOffsetCfg int16
|
columnOffsetCfg int16
|
||||||
@@ -50,9 +51,12 @@ type Config struct {
|
|||||||
Height int16
|
Height int16
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ST7789 connection. The SPI wire must already be configured, along with the
|
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
||||||
// data/command and reset pins as outputs.
|
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) Device {
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
resetPin: resetPin,
|
resetPin: resetPin,
|
||||||
|
|||||||
+4
-1
@@ -96,7 +96,10 @@ func (parser *Parser) Parse(sentence string) (Fix, error) {
|
|||||||
fix.Speed = findSpeed(fields[7])
|
fix.Speed = findSpeed(fields[7])
|
||||||
fix.Heading = findHeading(fields[8])
|
fix.Heading = findHeading(fields[8])
|
||||||
date := findDate(fields[9])
|
date := findDate(fields[9])
|
||||||
fix.Time = fix.Time.AddDate(date.Year(), int(date.Month()), date.Day())
|
fix.Time = date.Add(time.Duration(fix.Time.Hour())*time.Hour +
|
||||||
|
time.Duration(fix.Time.Minute())*time.Minute +
|
||||||
|
time.Duration(fix.Time.Second())*time.Second +
|
||||||
|
time.Duration(fix.Time.Nanosecond())*time.Nanosecond)
|
||||||
|
|
||||||
return fix, nil
|
return fix, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,15 +70,15 @@ func TestParseRMC(t *testing.T) {
|
|||||||
t.Error("should have errInvalidRMCSentence error")
|
t.Error("should have errInvalidRMCSentence error")
|
||||||
}
|
}
|
||||||
|
|
||||||
val = "$GPRMC,203522.00,A,5109.0262308,N,11401.8407342,W,0.004,133.4,130522,0.0,E,D*2B"
|
val = "$GPRMC,203522.00,A,5109.0262308,N,11401.8407342,W,0.004,133.4,010622,0.0,E,D*2B"
|
||||||
fix, err := p.Parse(val)
|
fix, err := p.Parse(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("should have parsed")
|
t.Error("should have parsed")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Assert(fix.Time.Year(), qt.Equals, 2022)
|
c.Assert(fix.Time.Year(), qt.Equals, 2022)
|
||||||
c.Assert(fix.Time.Month(), qt.Equals, time.May)
|
c.Assert(fix.Time.Month(), qt.Equals, time.June)
|
||||||
c.Assert(fix.Time.Day(), qt.Equals, 13)
|
c.Assert(fix.Time.Day(), qt.Equals, 1)
|
||||||
c.Assert(fix.Time.Hour(), qt.Equals, 20)
|
c.Assert(fix.Time.Hour(), qt.Equals, 20)
|
||||||
c.Assert(fix.Time.Minute(), qt.Equals, 35)
|
c.Assert(fix.Time.Minute(), qt.Equals, 35)
|
||||||
c.Assert(fix.Time.Second(), qt.Equals, 22)
|
c.Assert(fix.Time.Second(), qt.Equals, 22)
|
||||||
|
|||||||
+7
-8
@@ -5,31 +5,30 @@
|
|||||||
package hcsr04
|
package hcsr04
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const TIMEOUT = 23324 // max sensing distance (4m)
|
const TIMEOUT = 23324 // max sensing distance (4m)
|
||||||
|
|
||||||
// Device holds the pins
|
// Device holds the pins
|
||||||
type Device struct {
|
type Device struct {
|
||||||
trigger drivers.Pin
|
trigger machine.Pin
|
||||||
echo drivers.Pin
|
echo machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new ultrasonic driver given 2 pins
|
// New returns a new ultrasonic driver given 2 pins
|
||||||
func New(trigger, echo drivers.Pin) Device {
|
func New(trigger, echo machine.Pin) Device {
|
||||||
return Device{
|
return Device{
|
||||||
trigger: trigger,
|
trigger: trigger,
|
||||||
echo: echo,
|
echo: echo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure expects that the pins of the Device have already
|
// Configure configures the pins of the Device
|
||||||
// been configured by the user. Trigger pin should be an output
|
|
||||||
// and echo pin should be an input.
|
|
||||||
func (d *Device) Configure() {
|
func (d *Device) Configure() {
|
||||||
|
d.trigger.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.echo.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDistance returns the distance of the object in mm
|
// ReadDistance returns the distance of the object in mm
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type Configuration struct {
|
|||||||
MagDataRate uint8
|
MagDataRate uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
var errNotConnected = errors.New("lsm303agr: failed to communicate with either acel or magnet sensor")
|
var errNotConnected = errors.New("lsm303agr: failed to communicate with either accel or magnet sensor")
|
||||||
|
|
||||||
// New creates a new LSM303AGR connection. The I2C bus must already be configured.
|
// New creates a new LSM303AGR connection. The I2C bus must already be configured.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
// Package lsm303dlhc implements a driver for the LSM303dlhc,
|
||||||
|
// a 3 axis accelerometer/magnetic sensor typically available on breakout boards.
|
||||||
|
//
|
||||||
|
// Datasheet: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
|
||||||
|
|
||||||
|
package lsm303dlhc // import "tinygo.org/x/drivers/lsm303dlhc"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
"tinygo.org/x/drivers/internal/legacy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Device wraps an I2C connection to a LSM303dlhc device.
|
||||||
|
type Device struct {
|
||||||
|
bus drivers.I2C
|
||||||
|
AccelAddress uint8
|
||||||
|
MagAddress uint8
|
||||||
|
AccelPowerMode uint8
|
||||||
|
AccelRange uint8
|
||||||
|
AccelDataRate uint8
|
||||||
|
MagPowerMode uint8
|
||||||
|
MagSystemMode uint8
|
||||||
|
MagDataRate uint8
|
||||||
|
buf [6]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration for LSM303dlhc device.
|
||||||
|
type Configuration struct {
|
||||||
|
AccelPowerMode uint8
|
||||||
|
AccelRange uint8
|
||||||
|
AccelDataRate uint8
|
||||||
|
MagPowerMode uint8
|
||||||
|
MagSystemMode uint8
|
||||||
|
MagDataRate uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new LSM303DLHC connection. The I2C bus must already be configured.
|
||||||
|
// This function only creates the Device object, it does not touch the device.
|
||||||
|
func New(bus drivers.I2C) *Device {
|
||||||
|
return &Device{
|
||||||
|
bus: bus,
|
||||||
|
AccelAddress: ACCEL_ADDRESS,
|
||||||
|
MagAddress: MAG_ADDRESS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure sets up the LSM303dlhc device for communication.
|
||||||
|
func (d *Device) Configure(cfg Configuration) (err error) {
|
||||||
|
|
||||||
|
if cfg.AccelDataRate != 0 {
|
||||||
|
d.AccelDataRate = cfg.AccelDataRate
|
||||||
|
} else {
|
||||||
|
d.AccelDataRate = ACCEL_DATARATE_100HZ
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.AccelPowerMode != 0 {
|
||||||
|
d.AccelPowerMode = cfg.AccelPowerMode
|
||||||
|
} else {
|
||||||
|
d.AccelPowerMode = ACCEL_POWER_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.AccelRange != 0 {
|
||||||
|
d.AccelRange = cfg.AccelRange
|
||||||
|
} else {
|
||||||
|
d.AccelRange = ACCEL_RANGE_2G
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.MagPowerMode != 0 {
|
||||||
|
d.MagPowerMode = cfg.MagPowerMode
|
||||||
|
} else {
|
||||||
|
d.MagPowerMode = MAG_POWER_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.MagDataRate != 0 {
|
||||||
|
d.MagDataRate = cfg.MagDataRate
|
||||||
|
} else {
|
||||||
|
d.MagDataRate = MAG_DATARATE_10HZ
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.MagSystemMode != 0 {
|
||||||
|
d.MagSystemMode = cfg.MagSystemMode
|
||||||
|
} else {
|
||||||
|
d.MagSystemMode = MAG_SYSTEM_CONTINUOUS
|
||||||
|
}
|
||||||
|
|
||||||
|
data := d.buf[:1]
|
||||||
|
|
||||||
|
data[0] = byte(d.AccelDataRate<<4 | d.AccelPowerMode | 0x07)
|
||||||
|
err = legacy.WriteRegister(d.bus, uint8(d.AccelAddress), ACCEL_CTRL_REG1_A, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data[0] = byte(0x80 | d.AccelRange<<4)
|
||||||
|
err = legacy.WriteRegister(d.bus, uint8(d.AccelAddress), ACCEL_CTRL_REG4_A, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data[0] = byte(0xC0)
|
||||||
|
err = legacy.WriteRegister(d.bus, uint8(d.AccelAddress), CRA_REG_M, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temperature compensation is on for magnetic sensor
|
||||||
|
data[0] = byte(0x80 | d.MagPowerMode<<4 | d.MagDataRate<<2 | d.MagSystemMode)
|
||||||
|
err = legacy.WriteRegister(d.bus, uint8(d.MagAddress), MAG_MR_REG_M, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAcceleration reads the current acceleration from the device and returns
|
||||||
|
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
|
||||||
|
// and the sensor is not moving the returned value will be around 1000000 or
|
||||||
|
// -1000000.
|
||||||
|
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
|
||||||
|
data := d.buf[:6]
|
||||||
|
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), ACCEL_OUT_AUTO_INC, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rangeFactor := int16(0)
|
||||||
|
switch d.AccelRange {
|
||||||
|
case ACCEL_RANGE_2G:
|
||||||
|
rangeFactor = 1
|
||||||
|
case ACCEL_RANGE_4G:
|
||||||
|
rangeFactor = 2
|
||||||
|
case ACCEL_RANGE_8G:
|
||||||
|
rangeFactor = 4
|
||||||
|
case ACCEL_RANGE_16G:
|
||||||
|
rangeFactor = 12 // the readings in 16G are a bit lower
|
||||||
|
}
|
||||||
|
|
||||||
|
x = int32(int32(int16((uint16(data[1])<<8|uint16(data[0])))>>4*rangeFactor) * 1000000 / 1024)
|
||||||
|
y = int32(int32(int16((uint16(data[3])<<8|uint16(data[2])))>>4*rangeFactor) * 1000000 / 1024)
|
||||||
|
z = int32(int32(int16((uint16(data[5])<<8|uint16(data[4])))>>4*rangeFactor) * 1000000 / 1024)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPitchRoll reads the current pitch and roll angles from the device and
|
||||||
|
// returns it in micro-degrees. When the z axis is pointing straight to Earth
|
||||||
|
// the returned values of pitch and roll would be zero.
|
||||||
|
func (d *Device) ReadPitchRoll() (pitch, roll int32, err error) {
|
||||||
|
|
||||||
|
x, y, z, err := d.ReadAcceleration()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
xf, yf, zf := float64(x), float64(y), float64(z)
|
||||||
|
pitch = int32((math.Round(math.Atan2(yf, math.Sqrt(math.Pow(xf, 2)+math.Pow(zf, 2)))*(180/math.Pi)*100) / 100) * 1000000)
|
||||||
|
roll = int32((math.Round(math.Atan2(xf, math.Sqrt(math.Pow(yf, 2)+math.Pow(zf, 2)))*(180/math.Pi)*100) / 100) * 1000000)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadMagneticField reads the current magnetic field from the device and returns
|
||||||
|
// it in mG (milligauss). 1 mG = 0.1 µT (microtesla).
|
||||||
|
func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
|
||||||
|
|
||||||
|
if d.MagSystemMode == MAG_SYSTEM_SINGLE {
|
||||||
|
cmd := d.buf[:1]
|
||||||
|
cmd[0] = byte(0x80 | d.MagPowerMode<<4 | d.MagDataRate<<2 | d.MagSystemMode)
|
||||||
|
err = legacy.WriteRegister(d.bus, uint8(d.MagAddress), MAG_MR_REG_M, cmd)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data := d.buf[0:6]
|
||||||
|
legacy.ReadRegister(d.bus, uint8(d.MagAddress), MAG_OUT_AUTO_INC, data)
|
||||||
|
|
||||||
|
x = int32(int16((uint16(data[1])<<8 | uint16(data[0]))))
|
||||||
|
y = int32(int16((uint16(data[3])<<8 | uint16(data[2]))))
|
||||||
|
z = int32(int16((uint16(data[5])<<8 | uint16(data[4]))))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadCompass reads the current compass heading from the device and returns
|
||||||
|
// it in micro-degrees. When the z axis is pointing straight to Earth and
|
||||||
|
// the y axis is pointing to North, the heading would be zero.
|
||||||
|
//
|
||||||
|
// However, the heading may be off due to electronic compasses would be effected
|
||||||
|
// by strong magnetic fields and require constant calibration.
|
||||||
|
func (d *Device) ReadCompass() (h int32, err error) {
|
||||||
|
|
||||||
|
x, y, _, err := d.ReadMagneticField()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
xf, yf := float64(x), float64(y)
|
||||||
|
h = int32(float32((180/math.Pi)*math.Atan2(yf, xf)) * 1000000)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.MagAddress), TEMP_OUT_AUTO_INC, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r := int16((uint16(data[1])<<8 | uint16(data[0]))) >> 4 // temperature offset from 25 °C
|
||||||
|
t = 25000 + int32((float32(r)/8)*1000)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package lsm303dlhc
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// Constants/addresses used for I2C.
|
||||||
|
ACCEL_ADDRESS = 0x19
|
||||||
|
MAG_ADDRESS = 0x1E
|
||||||
|
|
||||||
|
// i2C 8-bit subaddress (SUB): the 7 LSb represent the actual register address
|
||||||
|
// while the MSB enables address auto increment.
|
||||||
|
// If the MSb of the SUB field is 1, the SUB (register address) is
|
||||||
|
// automatically increased to allow multiple data read/writes.
|
||||||
|
ADDR_AUTO_INC_MASK = 0x80
|
||||||
|
|
||||||
|
// accelerometer registers.
|
||||||
|
ACCEL_CTRL_REG1_A = 0x20
|
||||||
|
ACCEL_CTRL_REG4_A = 0x23
|
||||||
|
ACCEL_OUT_X_L_A = 0x28
|
||||||
|
ACCEL_OUT_X_H_A = 0x29
|
||||||
|
ACCEL_OUT_Y_L_A = 0x2A
|
||||||
|
ACCEL_OUT_Y_H_A = 0x2B
|
||||||
|
ACCEL_OUT_Z_L_A = 0x2C
|
||||||
|
ACCEL_OUT_Z_H_A = 0x2D
|
||||||
|
ACCEL_OUT_AUTO_INC = ACCEL_OUT_X_L_A | ADDR_AUTO_INC_MASK
|
||||||
|
|
||||||
|
// magnetic sensor registers.
|
||||||
|
MAG_MR_REG_M = 0x02
|
||||||
|
MAG_OUT_X_L_M = 0x68
|
||||||
|
MAG_OUT_X_H_M = 0x69
|
||||||
|
MAG_OUT_Y_L_M = 0x6A
|
||||||
|
MAG_OUT_Y_H_M = 0x6B
|
||||||
|
MAG_OUT_Z_L_M = 0x6C
|
||||||
|
MAG_OUT_Z_H_M = 0x6D
|
||||||
|
MAG_OUT_AUTO_INC = MAG_OUT_X_L_M | ADDR_AUTO_INC_MASK
|
||||||
|
|
||||||
|
// temperature sensor registers.
|
||||||
|
CRA_REG_M = 0x80
|
||||||
|
TEMP_OUT_L_M = 0x32
|
||||||
|
TEMP_OUT_H_M = 0x31
|
||||||
|
TEMP_OUT_AUTO_INC = TEMP_OUT_L_M | ADDR_AUTO_INC_MASK
|
||||||
|
|
||||||
|
// accelerometer power mode.
|
||||||
|
ACCEL_POWER_NORMAL = 0x00 // default
|
||||||
|
ACCEL_POWER_LOW = 0x08
|
||||||
|
|
||||||
|
// accelerometer range.
|
||||||
|
ACCEL_RANGE_2G = 0x00 // default
|
||||||
|
ACCEL_RANGE_4G = 0x01
|
||||||
|
ACCEL_RANGE_8G = 0x02
|
||||||
|
ACCEL_RANGE_16G = 0x03
|
||||||
|
|
||||||
|
// accelerometer data rate.
|
||||||
|
ACCEL_DATARATE_1HZ = 0x01
|
||||||
|
ACCEL_DATARATE_10HZ = 0x02
|
||||||
|
ACCEL_DATARATE_25HZ = 0x03
|
||||||
|
ACCEL_DATARATE_50HZ = 0x04
|
||||||
|
ACCEL_DATARATE_100HZ = 0x05 // default
|
||||||
|
ACCEL_DATARATE_200HZ = 0x06
|
||||||
|
ACCEL_DATARATE_400HZ = 0x07
|
||||||
|
ACCEL_DATARATE_1344HZ = 0x09 // 5376Hz in low-power mode
|
||||||
|
|
||||||
|
// magnetic sensor power mode.
|
||||||
|
MAG_POWER_NORMAL = 0x00 // default
|
||||||
|
MAG_POWER_LOW = 0x01
|
||||||
|
|
||||||
|
// magnetic sensor operate mode.
|
||||||
|
MAG_SYSTEM_CONTINUOUS = 0x00 // default
|
||||||
|
MAG_SYSTEM_SINGLE = 0x01
|
||||||
|
|
||||||
|
// magnetic sensor data rate
|
||||||
|
MAG_DATARATE_10HZ = 0x00 // default
|
||||||
|
MAG_DATARATE_20HZ = 0x01
|
||||||
|
MAG_DATARATE_50HZ = 0x02
|
||||||
|
MAG_DATARATE_100HZ = 0x03
|
||||||
|
)
|
||||||
+3
-2
@@ -3,6 +3,7 @@ package max6675
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"machine"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
)
|
)
|
||||||
@@ -13,13 +14,13 @@ var ErrThermocoupleOpen = errors.New("thermocouple input open")
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new Device to read from a MAX6675 thermocouple.
|
// Create a new Device to read from a MAX6675 thermocouple.
|
||||||
// Pins must be configured before use. Frequency for SPI
|
// Pins must be configured before use. Frequency for SPI
|
||||||
// should be 4.3MHz maximum.
|
// should be 4.3MHz maximum.
|
||||||
func NewDevice(bus drivers.SPI, cs drivers.Pin) *Device {
|
func NewDevice(bus drivers.SPI, cs machine.Pin) *Device {
|
||||||
return &Device{
|
return &Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: cs,
|
cs: cs,
|
||||||
|
|||||||
+8
-3
@@ -3,26 +3,31 @@
|
|||||||
package max72xx
|
package max72xx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDriver creates a new max7219 connection. The SPI wire must already be configured
|
// NewDriver creates a new max7219 connection. The SPI wire must already be configured
|
||||||
// The SPI frequency must not be higher than 10MHz.
|
// The SPI frequency must not be higher than 10MHz.
|
||||||
// parameter cs: the datasheet also refers to this pin as "load" pin.
|
// parameter cs: the datasheet also refers to this pin as "load" pin.
|
||||||
func NewDevice(bus drivers.SPI, cs drivers.Pin) *Device {
|
func NewDevice(bus drivers.SPI, cs machine.Pin) *Device {
|
||||||
return &Device{
|
return &Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: cs,
|
cs: cs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure expects that the pin of the Device has already been configured by the user as output.
|
// Configure setups the pins.
|
||||||
func (driver *Device) Configure() {
|
func (driver *Device) Configure() {
|
||||||
|
outPutConfig := machine.PinConfig{Mode: machine.PinOutput}
|
||||||
|
|
||||||
|
driver.cs.Configure(outPutConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetScanLimit sets the scan limit. Maximum is 8.
|
// SetScanLimit sets the scan limit. Maximum is 8.
|
||||||
|
|||||||
+5
-4
@@ -8,6 +8,7 @@ package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -16,7 +17,7 @@ import (
|
|||||||
// Device wraps MCP2515 SPI CAN Module.
|
// Device wraps MCP2515 SPI CAN Module.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
spi SPI
|
spi SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
msg *CANMsg
|
msg *CANMsg
|
||||||
mcpMode byte
|
mcpMode byte
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
|
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
|
||||||
func New(b drivers.SPI, csPin drivers.Pin) *Device {
|
func New(b drivers.SPI, csPin machine.Pin) *Device {
|
||||||
d := &Device{
|
d := &Device{
|
||||||
spi: SPI{
|
spi: SPI{
|
||||||
bus: b,
|
bus: b,
|
||||||
@@ -49,9 +50,9 @@ func New(b drivers.SPI, csPin drivers.Pin) *Device {
|
|||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure sets up the device for communication. It expects the SPI interface to be already
|
// Configure sets up the device for communication.
|
||||||
// configured, and the CS configured as output.
|
|
||||||
func (d *Device) Configure() {
|
func (d *Device) Configure() {
|
||||||
|
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
}
|
}
|
||||||
|
|
||||||
const beginTimeoutValue int = 10
|
const beginTimeoutValue int = 10
|
||||||
|
|||||||
+6
-5
@@ -6,6 +6,7 @@ package pcd8544 // import "tinygo.org/x/drivers/pcd8544"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -14,9 +15,9 @@ import (
|
|||||||
// Device wraps an SPI connection.
|
// Device wraps an SPI connection.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
dcPin drivers.Pin
|
dcPin machine.Pin
|
||||||
rstPin drivers.Pin
|
rstPin machine.Pin
|
||||||
scePin drivers.Pin
|
scePin machine.Pin
|
||||||
buffer []byte
|
buffer []byte
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
@@ -28,8 +29,8 @@ type Config struct {
|
|||||||
Height int16
|
Height int16
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new PCD8544 connection. The SPI bus and pins must already be configured.
|
// New creates a new PCD8544 connection. The SPI bus must already be configured.
|
||||||
func New(bus drivers.SPI, dcPin, rstPin, scePin drivers.Pin) *Device {
|
func New(bus drivers.SPI, dcPin, rstPin, scePin machine.Pin) *Device {
|
||||||
return &Device{
|
return &Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
dcPin: dcPin,
|
dcPin: dcPin,
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
package drivers
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package seesaw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errInvalidEncoderNumber = errors.New("invalid encoder choice, 0-15 are supported")
|
||||||
|
|
||||||
|
// GetEncoderPosition returns the absolute position (or delta since the previous call) of the specified rotary encoder.
|
||||||
|
func (d *Device) GetEncoderPosition(encoder uint, asDelta bool) (int32, error) {
|
||||||
|
if encoder >= 16 {
|
||||||
|
return 0, errInvalidEncoderNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// The function address' upper nibble is the function, the lower nibble selects which encoder to communicate with
|
||||||
|
fnAddr := FunctionAddress(encoder)
|
||||||
|
if asDelta {
|
||||||
|
fnAddr |= FunctionEncoderDelta
|
||||||
|
} else {
|
||||||
|
fnAddr |= FunctionEncoderPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf [4]byte
|
||||||
|
err := d.Read(ModuleEncoderBase, fnAddr, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int32(buf[0])<<24 | int32(buf[1])<<16 | int32(buf[2])<<8 | int32(buf[3]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEncoderPosition calibrate's the encoder's current absolute position to be whatever the provided position is.
|
||||||
|
func (d *Device) SetEncoderPosition(encoder uint, position int32) error {
|
||||||
|
if encoder >= 16 {
|
||||||
|
return errInvalidEncoderNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// The function address' upper nibble is the function, the lower nibble selects which encoder to communicate with
|
||||||
|
fnAddr := FunctionEncoderPosition | FunctionAddress(encoder)
|
||||||
|
|
||||||
|
buf := [4]byte{
|
||||||
|
byte(position >> 24),
|
||||||
|
byte(position >> 16),
|
||||||
|
byte(position >> 8),
|
||||||
|
byte(position),
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.Write(ModuleEncoderBase, fnAddr, buf[:])
|
||||||
|
}
|
||||||
@@ -98,3 +98,13 @@ const (
|
|||||||
FunctionKeypadCount FunctionAddress = 0x04
|
FunctionKeypadCount FunctionAddress = 0x04
|
||||||
FunctionKeypadFifo FunctionAddress = 0x10
|
FunctionKeypadFifo FunctionAddress = 0x10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// encoder module function address registers
|
||||||
|
// these are the defaults for encoder 0, change the lower nibble to address other encoders
|
||||||
|
// see the Device.GetEncoderPosition and SetEncoderPosition methods for examples.
|
||||||
|
const (
|
||||||
|
FunctionEncoderIntenset FunctionAddress = 0x10
|
||||||
|
FunctionEncoderIntenclr FunctionAddress = 0x20
|
||||||
|
FunctionEncoderPosition FunctionAddress = 0x30
|
||||||
|
FunctionEncoderDelta FunctionAddress = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package shiftregister
|
package shiftregister
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"tinygo.org/x/drivers"
|
"machine"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NumberBit int8
|
type NumberBit int8
|
||||||
@@ -16,20 +16,20 @@ const (
|
|||||||
|
|
||||||
// Device holds pin number
|
// Device holds pin number
|
||||||
type Device struct {
|
type Device struct {
|
||||||
latch, clock, out drivers.Pin // IC wiring
|
latch, clock, out machine.Pin // IC wiring
|
||||||
bits NumberBit // Pin number
|
bits NumberBit // Pin number
|
||||||
mask uint32 // keep all pins state
|
mask uint32 // keep all pins state
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShiftPin is the implementation of the ShiftPin interface.
|
// ShiftPin is the implementation of the ShiftPin interface.
|
||||||
// ShiftPin provide an interface like regular drivers.Pin
|
// ShiftPin provide an interface like regular machine.Pin
|
||||||
type ShiftPin struct {
|
type ShiftPin struct {
|
||||||
mask uint32 // Bit representing the pin
|
mask uint32 // Bit representing the pin
|
||||||
d *Device // Reference to the register
|
d *Device // Reference to the register
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new shift output register device
|
// New returns a new shift output register device
|
||||||
func New(Bits NumberBit, Latch, Clock, Out drivers.Pin) *Device {
|
func New(Bits NumberBit, Latch, Clock, Out machine.Pin) *Device {
|
||||||
return &Device{
|
return &Device{
|
||||||
latch: Latch,
|
latch: Latch,
|
||||||
clock: Clock,
|
clock: Clock,
|
||||||
@@ -38,9 +38,11 @@ func New(Bits NumberBit, Latch, Clock, Out drivers.Pin) *Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure set hardware configuration. Make sure that the pins are already configured
|
// Configure set hardware configuration
|
||||||
// as output.
|
|
||||||
func (d *Device) Configure() {
|
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()
|
d.latch.High()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -44,6 +44,7 @@ tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341
|
|||||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
|
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/lsm303dlhc/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mag3110/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mag3110/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
|
||||||
@@ -58,15 +59,17 @@ tinygo build -size short -o ./build/test.hex -target=p1am-100 ./examples/p1am/ma
|
|||||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/pca9685/main.go
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/pca9685/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/seesaw
|
tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/seesaw/soil-sensor
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=qtpy-rp2040 ./examples/seesaw/rotary-encoder
|
||||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo
|
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo
|
||||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/sgp30
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/sgp30
|
||||||
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go
|
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht4x/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht4x/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
|
tinygo build -size short -o ./build/test.hex -target=xiao-ble ./examples/ssd1306/
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
|
tinygo build -size short -o ./build/test.hex -target=xiao-rp2040 ./examples/ssd1306/
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=thumby ./examples/ssd1306/
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1331/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1331/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7735/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7735/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7789/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7789/main.go
|
||||||
@@ -140,6 +143,7 @@ tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/tmc2209/mai
|
|||||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/tmc5160/main.go
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/tmc5160/main.go
|
||||||
tinygo build -size short -o ./build/test.uf2 -target=nicenano ./examples/sharpmem/main.go
|
tinygo build -size short -o ./build/test.uf2 -target=nicenano ./examples/sharpmem/main.go
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-nrf52840 ./examples/max6675/main.go
|
tinygo build -size short -o ./build/test.hex -target=feather-nrf52840 ./examples/max6675/main.go
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/ens160/main.go
|
||||||
# network examples (espat)
|
# network examples (espat)
|
||||||
tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/
|
tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/
|
||||||
# network examples (wifinina)
|
# network examples (wifinina)
|
||||||
|
|||||||
+11
-7
@@ -5,9 +5,8 @@ package ssd1289
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bus interface {
|
type Bus interface {
|
||||||
@@ -15,17 +14,17 @@ type Bus interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
rs drivers.Pin
|
rs machine.Pin
|
||||||
wr drivers.Pin
|
wr machine.Pin
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
bus Bus
|
bus Bus
|
||||||
}
|
}
|
||||||
|
|
||||||
const width = int16(240)
|
const width = int16(240)
|
||||||
const height = int16(320)
|
const height = int16(320)
|
||||||
|
|
||||||
func New(rs drivers.Pin, wr drivers.Pin, cs drivers.Pin, rst drivers.Pin, bus Bus) Device {
|
func New(rs machine.Pin, wr machine.Pin, cs machine.Pin, rst machine.Pin, bus Bus) Device {
|
||||||
d := Device{
|
d := Device{
|
||||||
rs: rs,
|
rs: rs,
|
||||||
wr: wr,
|
wr: wr,
|
||||||
@@ -34,6 +33,11 @@ func New(rs drivers.Pin, wr drivers.Pin, cs drivers.Pin, rst drivers.Pin, bus Bu
|
|||||||
bus: bus,
|
bus: bus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
cs.High()
|
||||||
rst.High()
|
rst.High()
|
||||||
wr.High()
|
wr.High()
|
||||||
|
|||||||
+29
-133
@@ -9,7 +9,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
"tinygo.org/x/drivers/pixel"
|
"tinygo.org/x/drivers/pixel"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,16 +21,15 @@ type ResetValue [2]byte
|
|||||||
|
|
||||||
// Device wraps I2C or SPI connection.
|
// Device wraps I2C or SPI connection.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus Buser
|
bus Buser
|
||||||
buffer []byte
|
buffer []byte
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
bufferSize int16
|
vccState VccMode
|
||||||
vccState VccMode
|
canReset bool
|
||||||
canReset bool
|
resetCol ResetValue
|
||||||
resetCol ResetValue
|
resetPage ResetValue
|
||||||
resetPage ResetValue
|
rotation drivers.Rotation
|
||||||
rotation drivers.Rotation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is the configuration for the display
|
// Config is the configuration for the display
|
||||||
@@ -50,48 +48,15 @@ type Config struct {
|
|||||||
Rotation drivers.Rotation
|
Rotation drivers.Rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
type I2CBus struct {
|
|
||||||
wire drivers.I2C
|
|
||||||
Address uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
type SPIBus struct {
|
|
||||||
wire drivers.SPI
|
|
||||||
dcPin drivers.Pin
|
|
||||||
resetPin drivers.Pin
|
|
||||||
csPin drivers.Pin
|
|
||||||
}
|
|
||||||
|
|
||||||
type Buser interface {
|
type Buser interface {
|
||||||
configure() error
|
configure(address uint16, size int16) []byte // configure the bus and return the image buffer to use
|
||||||
tx(data []byte, isCommand bool) error
|
command(cmd uint8) error // send a command to the display
|
||||||
setAddress(address uint16) error
|
flush() error // send the image to the display, faster than "tx()" in i2c case since avoids slice copy
|
||||||
|
tx(data []byte, isCommand bool) error // generic transmit function
|
||||||
}
|
}
|
||||||
|
|
||||||
type VccMode uint8
|
type VccMode uint8
|
||||||
|
|
||||||
// NewI2C creates a new SSD1306 connection. The I2C wire must already be configured.
|
|
||||||
func NewI2C(bus drivers.I2C) Device {
|
|
||||||
return Device{
|
|
||||||
bus: &I2CBus{
|
|
||||||
wire: bus,
|
|
||||||
Address: Address,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
dcPin: dcPin,
|
|
||||||
resetPin: resetPin,
|
|
||||||
csPin: csPin,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure initializes the display with default configuration
|
// Configure initializes the display with default configuration
|
||||||
func (d *Device) Configure(cfg Config) {
|
func (d *Device) Configure(cfg Config) {
|
||||||
var zeroReset ResetValue
|
var zeroReset ResetValue
|
||||||
@@ -105,9 +70,6 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
} else {
|
} else {
|
||||||
d.height = 64
|
d.height = 64
|
||||||
}
|
}
|
||||||
if cfg.Address != 0 {
|
|
||||||
d.bus.setAddress(cfg.Address)
|
|
||||||
}
|
|
||||||
if cfg.VccState != 0 {
|
if cfg.VccState != 0 {
|
||||||
d.vccState = cfg.VccState
|
d.vccState = cfg.VccState
|
||||||
} else {
|
} else {
|
||||||
@@ -123,11 +85,9 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
} else {
|
} else {
|
||||||
d.resetPage = ResetValue{0, uint8(d.height/8) - 1}
|
d.resetPage = ResetValue{0, uint8(d.height/8) - 1}
|
||||||
}
|
}
|
||||||
d.bufferSize = d.width * d.height / 8
|
|
||||||
d.buffer = make([]byte, d.bufferSize)
|
|
||||||
d.canReset = cfg.Address != 0 || d.width != 128 || d.height != 64 // I2C or not 128x64
|
d.canReset = cfg.Address != 0 || d.width != 128 || d.height != 64 // I2C or not 128x64
|
||||||
|
|
||||||
d.bus.configure()
|
d.buffer = d.bus.configure(cfg.Address, d.width*d.height/8)
|
||||||
|
|
||||||
time.Sleep(100 * time.Nanosecond)
|
time.Sleep(100 * time.Nanosecond)
|
||||||
d.Command(DISPLAYOFF)
|
d.Command(DISPLAYOFF)
|
||||||
@@ -189,11 +149,22 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
d.Command(NORMALDISPLAY)
|
d.Command(NORMALDISPLAY)
|
||||||
d.Command(DEACTIVATE_SCROLL)
|
d.Command(DEACTIVATE_SCROLL)
|
||||||
d.Command(DISPLAYON)
|
d.Command(DISPLAYON)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command sends a command to the display
|
||||||
|
func (d *Device) Command(command uint8) {
|
||||||
|
d.bus.command(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tx sends data to the display; if isCommand is false, this also updates the image buffer.
|
||||||
|
func (d *Device) Tx(data []byte, isCommand bool) error {
|
||||||
|
return d.bus.tx(data, isCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearBuffer clears the image buffer
|
// ClearBuffer clears the image buffer
|
||||||
func (d *Device) ClearBuffer() {
|
func (d *Device) ClearBuffer() {
|
||||||
for i := int16(0); i < d.bufferSize; i++ {
|
for i := 0; i < len(d.buffer); i++ {
|
||||||
d.buffer[i] = 0
|
d.buffer[i] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +190,7 @@ func (d *Device) Display() error {
|
|||||||
d.Command(d.resetPage[1])
|
d.Command(d.resetPage[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.Tx(d.buffer, false)
|
return d.bus.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPixel enables or disables a pixel in the buffer
|
// SetPixel enables or disables a pixel in the buffer
|
||||||
@@ -248,12 +219,10 @@ func (d *Device) GetPixel(x int16, y int16) bool {
|
|||||||
|
|
||||||
// SetBuffer changes the whole buffer at once
|
// SetBuffer changes the whole buffer at once
|
||||||
func (d *Device) SetBuffer(buffer []byte) error {
|
func (d *Device) SetBuffer(buffer []byte) error {
|
||||||
if int16(len(buffer)) != d.bufferSize {
|
if len(buffer) != len(d.buffer) {
|
||||||
return errBufferSize
|
return errBufferSize
|
||||||
}
|
}
|
||||||
for i := int16(0); i < d.bufferSize; i++ {
|
copy(d.buffer, buffer)
|
||||||
d.buffer[i] = buffer[i]
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,79 +231,6 @@ func (d *Device) GetBuffer() []byte {
|
|||||||
return d.buffer
|
return d.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command sends a command to the display
|
|
||||||
func (d *Device) Command(command uint8) {
|
|
||||||
d.bus.tx([]byte{command}, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// setAddress sets the address to the I2C bus
|
|
||||||
func (b *I2CBus) setAddress(address uint16) error {
|
|
||||||
b.Address = address
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setAddress does nothing, but it's required to avoid reflection
|
|
||||||
func (b *SPIBus) setAddress(address uint16) error {
|
|
||||||
// do nothing
|
|
||||||
println("trying to Configure an address on a SPI device")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure does nothing, but it's required to avoid reflection
|
|
||||||
func (b *I2CBus) configure() error { return nil }
|
|
||||||
|
|
||||||
// configure configures some pins with the SPI bus
|
|
||||||
func (b *SPIBus) configure() error {
|
|
||||||
b.csPin.Low()
|
|
||||||
b.dcPin.Low()
|
|
||||||
b.resetPin.Low()
|
|
||||||
|
|
||||||
b.resetPin.High()
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
b.resetPin.Low()
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
b.resetPin.High()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tx sends data to the display
|
|
||||||
func (d *Device) Tx(data []byte, isCommand bool) error {
|
|
||||||
return d.bus.tx(data, isCommand)
|
|
||||||
}
|
|
||||||
|
|
||||||
// tx sends data to the display (I2CBus implementation)
|
|
||||||
func (b *I2CBus) tx(data []byte, isCommand bool) error {
|
|
||||||
if isCommand {
|
|
||||||
return legacy.WriteRegister(b.wire, uint8(b.Address), 0x00, data)
|
|
||||||
} else {
|
|
||||||
return legacy.WriteRegister(b.wire, uint8(b.Address), 0x40, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tx sends data to the display (SPIBus implementation)
|
|
||||||
func (b *SPIBus) tx(data []byte, isCommand bool) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if isCommand {
|
|
||||||
b.csPin.High()
|
|
||||||
b.dcPin.Low()
|
|
||||||
b.csPin.Low()
|
|
||||||
|
|
||||||
err = b.wire.Tx(data, nil)
|
|
||||||
b.csPin.High()
|
|
||||||
} else {
|
|
||||||
b.csPin.High()
|
|
||||||
b.dcPin.High()
|
|
||||||
b.csPin.Low()
|
|
||||||
|
|
||||||
err = b.wire.Tx(data, nil)
|
|
||||||
b.csPin.High()
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the current size of the display.
|
// Size returns the current size of the display.
|
||||||
func (d *Device) Size() (w, h int16) {
|
func (d *Device) Size() (w, h int16) {
|
||||||
return d.width, d.height
|
return d.width, d.height
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package ssd1306
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type I2CBus struct {
|
||||||
|
wire drivers.I2C
|
||||||
|
address uint16
|
||||||
|
buffer []byte // buffer to avoid heap allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewI2C creates a new SSD1306 connection. The I2C wire must already be configured.
|
||||||
|
func NewI2C(bus drivers.I2C) *Device {
|
||||||
|
return &Device{
|
||||||
|
bus: &I2CBus{
|
||||||
|
wire: bus,
|
||||||
|
address: Address,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure address for the I2C bus and allocate the buffer
|
||||||
|
func (b *I2CBus) configure(address uint16, size int16) []byte {
|
||||||
|
if address != 0 {
|
||||||
|
b.address = address
|
||||||
|
}
|
||||||
|
b.buffer = make([]byte, size+2) // +1 for the mode and +1 for a command
|
||||||
|
return b.buffer[2:] // return the image buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// command sends a command to the display
|
||||||
|
func (b *I2CBus) command(cmd uint8) error {
|
||||||
|
b.buffer[0] = 0x00 // Command mode
|
||||||
|
b.buffer[1] = cmd
|
||||||
|
return b.wire.Tx(b.address, b.buffer[:2], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush sends the image to the display
|
||||||
|
func (b *I2CBus) flush() error {
|
||||||
|
b.buffer[1] = 0x40 // Data mode
|
||||||
|
return b.wire.Tx(b.address, b.buffer[1:], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx sends data to the display
|
||||||
|
func (b *I2CBus) tx(data []byte, isCommand bool) error {
|
||||||
|
if isCommand {
|
||||||
|
return b.command(data[0])
|
||||||
|
}
|
||||||
|
copy(b.buffer[2:], data)
|
||||||
|
return b.flush()
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package ssd1306
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SPIBus struct {
|
||||||
|
wire drivers.SPI
|
||||||
|
dcPin machine.Pin
|
||||||
|
resetPin machine.Pin
|
||||||
|
csPin machine.Pin
|
||||||
|
buffer []byte // buffer to avoid heap allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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})
|
||||||
|
return &Device{
|
||||||
|
bus: &SPIBus{
|
||||||
|
wire: bus,
|
||||||
|
dcPin: dcPin,
|
||||||
|
resetPin: resetPin,
|
||||||
|
csPin: csPin,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure pins with the SPI bus and allocate the buffer
|
||||||
|
func (b *SPIBus) configure(address uint16, size int16) []byte {
|
||||||
|
b.csPin.Low()
|
||||||
|
b.dcPin.Low()
|
||||||
|
b.resetPin.Low()
|
||||||
|
|
||||||
|
b.resetPin.High()
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
b.resetPin.Low()
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
b.resetPin.High()
|
||||||
|
|
||||||
|
b.buffer = make([]byte, size+1) // +1 for a command
|
||||||
|
return b.buffer[1:] // return the image buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// command sends a command to the display
|
||||||
|
func (b *SPIBus) command(cmd uint8) error {
|
||||||
|
b.buffer[0] = cmd
|
||||||
|
return b.tx(b.buffer[:1], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush sends the image to the display
|
||||||
|
func (b *SPIBus) flush() error {
|
||||||
|
return b.tx(b.buffer[1:], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx sends data to the display
|
||||||
|
func (b *SPIBus) tx(data []byte, isCommand bool) error {
|
||||||
|
b.csPin.High()
|
||||||
|
b.dcPin.Set(!isCommand)
|
||||||
|
b.csPin.Low()
|
||||||
|
err := b.wire.Tx(data, nil)
|
||||||
|
b.csPin.High()
|
||||||
|
return err
|
||||||
|
}
|
||||||
+9
-5
@@ -5,6 +5,7 @@ package ssd1331 // import "tinygo.org/x/drivers/ssd1331"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
@@ -18,9 +19,9 @@ type Rotation uint8
|
|||||||
// Device wraps an SPI connection.
|
// Device wraps an SPI connection.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
dcPin drivers.Pin
|
dcPin machine.Pin
|
||||||
resetPin drivers.Pin
|
resetPin machine.Pin
|
||||||
csPin drivers.Pin
|
csPin machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
batchLength int16
|
batchLength int16
|
||||||
@@ -34,8 +35,11 @@ type Config struct {
|
|||||||
Height int16
|
Height int16
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new SSD1331 connection. The SPI wire and pins must already be configured.
|
// New creates a new SSD1331 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin drivers.Pin) Device {
|
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})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
dcPin: dcPin,
|
dcPin: dcPin,
|
||||||
|
|||||||
+14
-6
@@ -6,6 +6,7 @@ package ssd1351 // import "tinygo.org/x/drivers/ssd1351"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -19,11 +20,11 @@ var (
|
|||||||
// Device wraps an SPI connection.
|
// Device wraps an SPI connection.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
dcPin drivers.Pin
|
dcPin machine.Pin
|
||||||
resetPin drivers.Pin
|
resetPin machine.Pin
|
||||||
csPin drivers.Pin
|
csPin machine.Pin
|
||||||
enPin drivers.Pin
|
enPin machine.Pin
|
||||||
rwPin drivers.Pin
|
rwPin machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
rowOffset int16
|
rowOffset int16
|
||||||
@@ -40,7 +41,7 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new SSD1351 connection. The SPI wire must already be configured.
|
// New creates a new SSD1351 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin, enPin, rwPin drivers.Pin) Device {
|
func New(bus drivers.SPI, resetPin, dcPin, csPin, enPin, rwPin machine.Pin) Device {
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
dcPin: dcPin,
|
dcPin: dcPin,
|
||||||
@@ -71,6 +72,13 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
d.bufferLength = d.height
|
d.bufferLength = d.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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})
|
||||||
|
|
||||||
// reset the device
|
// reset the device
|
||||||
d.resetPin.High()
|
d.resetPin.High()
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|||||||
+12
-7
@@ -5,6 +5,7 @@ package st7735 // import "tinygo.org/x/drivers/st7735"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
@@ -38,10 +39,10 @@ type Device = DeviceOf[pixel.RGB565BE]
|
|||||||
// formats.
|
// formats.
|
||||||
type DeviceOf[T Color] struct {
|
type DeviceOf[T Color] struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
dcPin drivers.Pin
|
dcPin machine.Pin
|
||||||
resetPin drivers.Pin
|
resetPin machine.Pin
|
||||||
csPin drivers.Pin
|
csPin machine.Pin
|
||||||
blPin drivers.Pin
|
blPin machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
columnOffset int16
|
columnOffset int16
|
||||||
@@ -64,13 +65,17 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ST7735 connection. The SPI wire must already be configured.
|
// New creates a new ST7735 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) Device {
|
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
||||||
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOf creates a new ST7735 connection with a particular pixel format. The SPI
|
// NewOf creates a new ST7735 connection with a particular pixel format. The SPI
|
||||||
// wire and pins must already be configured.
|
// wire must already be configured.
|
||||||
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) DeviceOf[T] {
|
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
return DeviceOf[T]{
|
return DeviceOf[T]{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
dcPin: dcPin,
|
dcPin: dcPin,
|
||||||
|
|||||||
+11
-7
@@ -46,10 +46,10 @@ type Device = DeviceOf[pixel.RGB565BE]
|
|||||||
// formats.
|
// formats.
|
||||||
type DeviceOf[T Color] struct {
|
type DeviceOf[T Color] struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
dcPin drivers.Pin
|
dcPin machine.Pin
|
||||||
resetPin drivers.Pin
|
resetPin machine.Pin
|
||||||
csPin drivers.Pin
|
csPin machine.Pin
|
||||||
blPin drivers.Pin
|
blPin machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
columnOffsetCfg int16
|
columnOffsetCfg int16
|
||||||
@@ -83,13 +83,17 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) Device {
|
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
||||||
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
||||||
// wire and pins must already be configured.
|
// wire must already be configured.
|
||||||
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) DeviceOf[T] {
|
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
return DeviceOf[T]{
|
return DeviceOf[T]{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
dcPin: dcPin,
|
dcPin: dcPin,
|
||||||
|
|||||||
+3
-2
@@ -6,6 +6,7 @@ package sx127x
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -21,7 +22,7 @@ const (
|
|||||||
// Device wraps an SPI connection to a SX127x device.
|
// Device wraps an SPI connection to a SX127x device.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
spi drivers.SPI // SPI bus for module communication
|
spi drivers.SPI // SPI bus for module communication
|
||||||
rstPin drivers.Pin // GPIO for reset
|
rstPin machine.Pin // GPIO for reset
|
||||||
radioEventChan chan lora.RadioEvent // Channel for Receiving events
|
radioEventChan chan lora.RadioEvent // Channel for Receiving events
|
||||||
loraConf lora.Config // Current Lora configuration
|
loraConf lora.Config // Current Lora configuration
|
||||||
controller RadioController // to manage interactions with the radio
|
controller RadioController // to manage interactions with the radio
|
||||||
@@ -42,7 +43,7 @@ func (d *Device) GetRadioEventChan() chan lora.RadioEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new SX127x connection. The SPI bus must already be configured.
|
// New creates a new SX127x connection. The SPI bus must already be configured.
|
||||||
func New(spi drivers.SPI, rstPin drivers.Pin) *Device {
|
func New(spi drivers.SPI, rstPin machine.Pin) *Device {
|
||||||
k := Device{
|
k := Device{
|
||||||
spi: spi,
|
spi: spi,
|
||||||
rstPin: rstPin,
|
rstPin: rstPin,
|
||||||
|
|||||||
+11
-7
@@ -8,6 +8,7 @@ package uc8151 // import "tinygo.org/x/drivers/uc8151"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -30,10 +31,10 @@ type Config struct {
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
buffer []uint8
|
buffer []uint8
|
||||||
@@ -47,9 +48,12 @@ type Device struct {
|
|||||||
|
|
||||||
type Speed uint8
|
type Speed uint8
|
||||||
|
|
||||||
// New returns a new uc8151 driver. Pass in a fully configured SPI bus and pins.
|
// New returns a new uc8151 driver. Pass in a fully configured SPI bus.
|
||||||
// busyPin should be set and input, the others as outputs.
|
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: csPin,
|
cs: csPin,
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@ package drivers
|
|||||||
|
|
||||||
// Version returns a user-readable string showing the version of the drivers package for support purposes.
|
// 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.
|
// Update this value before release of new version of software.
|
||||||
const Version = "0.32.0"
|
const Version = "0.33.0"
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"machine"
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -25,10 +23,10 @@ type Config struct {
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus *machine.SPI
|
bus *machine.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
|
|
||||||
buffer []uint8
|
buffer []uint8
|
||||||
rotation Rotation
|
rotation Rotation
|
||||||
@@ -81,7 +79,7 @@ var partialRefresh = [159]uint8{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new epd1in54 driver. Pass in a fully configured SPI bus.
|
// New returns a new epd1in54 driver. Pass in a fully configured SPI bus.
|
||||||
func New(bus *machine.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
func New(bus *machine.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
return Device{
|
return Device{
|
||||||
buffer: make([]uint8, (uint32(Width)*uint32(Height))/8),
|
buffer: make([]uint8, (uint32(Width)*uint32(Height))/8),
|
||||||
bus: bus,
|
bus: bus,
|
||||||
@@ -93,6 +91,11 @@ func New(bus *machine.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) LDirInit(cfg Config) {
|
func (d *Device) LDirInit(cfg Config) {
|
||||||
|
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.busy.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
|
|
||||||
d.bus.Configure(machine.SPIConfig{
|
d.bus.Configure(machine.SPIConfig{
|
||||||
Frequency: 2000000,
|
Frequency: 2000000,
|
||||||
Mode: 0,
|
Mode: 0,
|
||||||
@@ -147,6 +150,11 @@ func (d *Device) LDirInit(cfg Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) HDirInit(cfg Config) {
|
func (d *Device) HDirInit(cfg Config) {
|
||||||
|
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.busy.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
|
|
||||||
d.bus.Configure(machine.SPIConfig{
|
d.bus.Configure(machine.SPIConfig{
|
||||||
Frequency: 2000000,
|
Frequency: 2000000,
|
||||||
Mode: 0,
|
Mode: 0,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package epd2in13 // import "tinygo.org/x/drivers/waveshare-epd/epd2in13"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -20,10 +21,10 @@ type Config struct {
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
logicalWidth int16
|
logicalWidth int16
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
@@ -51,9 +52,12 @@ var lutPartialUpdate = [30]uint8{
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus and pins.
|
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
|
||||||
// Busy pin should input, the rest should be output.
|
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: csPin,
|
cs: csPin,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package epd2in13x // import "tinygo.org/x/drivers/waveshare-epd/epd2in13x"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -19,10 +20,10 @@ type Config struct {
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
buffer [][]uint8
|
buffer [][]uint8
|
||||||
@@ -31,9 +32,12 @@ type Device struct {
|
|||||||
|
|
||||||
type Color uint8
|
type Color uint8
|
||||||
|
|
||||||
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus and pins.
|
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
|
||||||
// Busy pin should input, the rest should be output.
|
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: csPin,
|
cs: csPin,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package epd2in66b
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -18,18 +19,18 @@ const (
|
|||||||
const Baudrate = 4_000_000 // 4 MHz
|
const Baudrate = 4_000_000 // 4 MHz
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ResetPin drivers.Pin
|
ResetPin machine.Pin
|
||||||
DataPin drivers.Pin
|
DataPin machine.Pin
|
||||||
ChipSelectPin drivers.Pin
|
ChipSelectPin machine.Pin
|
||||||
BusyPin drivers.Pin
|
BusyPin machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
|
|
||||||
blackBuffer []byte
|
blackBuffer []byte
|
||||||
redBuffer []byte
|
redBuffer []byte
|
||||||
@@ -49,14 +50,18 @@ func New(bus drivers.SPI) Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures the device. Note that pins should already
|
// Configure configures the device and its pins.
|
||||||
// be configured. Busy pin should be input, the rest should be output.
|
|
||||||
func (d *Device) Configure(c Config) error {
|
func (d *Device) Configure(c Config) error {
|
||||||
d.cs = c.ChipSelectPin
|
d.cs = c.ChipSelectPin
|
||||||
d.dc = c.DataPin
|
d.dc = c.DataPin
|
||||||
d.rst = c.ResetPin
|
d.rst = c.ResetPin
|
||||||
d.busy = c.BusyPin
|
d.busy = c.BusyPin
|
||||||
|
|
||||||
|
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.dc.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.rst.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
d.busy.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ package epd2in9 // import "tinygo.org/x/drivers/waveshare-epd/epd2in9"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -27,10 +28,10 @@ type Config struct {
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
logicalWidth int16
|
logicalWidth int16
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
@@ -59,9 +60,12 @@ var lutPartialUpdate = [30]uint8{
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new epd2in9 driver. Pass in a fully configured SPI bus and pins.
|
// New returns a new epd2in9 driver. Pass in a fully configured SPI bus.
|
||||||
// Busy pin should input, the rest should be output.
|
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: csPin,
|
cs: csPin,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ package epd4in2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -24,10 +25,10 @@ type Config struct {
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs drivers.Pin
|
cs machine.Pin
|
||||||
dc drivers.Pin
|
dc machine.Pin
|
||||||
rst drivers.Pin
|
rst machine.Pin
|
||||||
busy drivers.Pin
|
busy machine.Pin
|
||||||
logicalWidth int16
|
logicalWidth int16
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
@@ -38,9 +39,12 @@ type Device struct {
|
|||||||
|
|
||||||
type Rotation uint8
|
type Rotation uint8
|
||||||
|
|
||||||
// New returns a new epd4in2 driver. Pass in a fully configured SPI bus and pins.
|
// New returns a new epd4in2 driver. Pass in a fully configured SPI bus.
|
||||||
// Busy pin should input, the rest should be output.
|
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin drivers.Pin) Device {
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
return Device{
|
return Device{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
cs: csPin,
|
cs: csPin,
|
||||||
|
|||||||
@@ -931,6 +931,356 @@ void ws2812_writeByte125(char c, uint32_t *portSet, uint32_t *portClear, uint32_
|
|||||||
[portClear]"m"(*portClear));
|
[portClear]"m"(*portClear));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((always_inline))
|
||||||
|
void ws2812_writeByte150(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) {
|
||||||
|
// Timings:
|
||||||
|
// T0H: 53 - 55 cycles or 353.3ns - 366.7ns
|
||||||
|
// T1H: 158 - 160 cycles or 1053.3ns - 1066.7ns
|
||||||
|
// TLD: 173 - cycles or 1153.3ns -
|
||||||
|
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 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 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 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));
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((always_inline))
|
__attribute__((always_inline))
|
||||||
void ws2812_writeByte168(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) {
|
void ws2812_writeByte168(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) {
|
||||||
// Timings:
|
// Timings:
|
||||||
@@ -1832,6 +2182,16 @@ func (d Device) writeByte125(c byte) {
|
|||||||
interrupt.Restore(mask)
|
interrupt.Restore(mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d Device) writeByte150(c byte) {
|
||||||
|
portSet, maskSet := d.Pin.PortMaskSet()
|
||||||
|
portClear, maskClear := d.Pin.PortMaskClear()
|
||||||
|
|
||||||
|
mask := interrupt.Disable()
|
||||||
|
C.ws2812_writeByte150(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)
|
||||||
|
}
|
||||||
|
|
||||||
func (d Device) writeByte168(c byte) {
|
func (d Device) writeByte168(c byte) {
|
||||||
portSet, maskSet := d.Pin.PortMaskSet()
|
portSet, maskSet := d.Pin.PortMaskSet()
|
||||||
portClear, maskClear := d.Pin.PortMaskClear()
|
portClear, maskClear := d.Pin.PortMaskClear()
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips.
|
// Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips.
|
||||||
package ws2812 // import "tinygo.org/x/drivers/ws2812"
|
package ws2812 // import "tinygo.org/x/drivers/ws2812"
|
||||||
|
|
||||||
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 168 200
|
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 150 168 200
|
||||||
//go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320
|
//go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ func (d Device) WriteByte(c byte) error {
|
|||||||
case 125_000_000: // 125 MHz e.g. rp2040 originally
|
case 125_000_000: // 125 MHz e.g. rp2040 originally
|
||||||
d.writeByte125(c)
|
d.writeByte125(c)
|
||||||
return nil
|
return nil
|
||||||
|
case 150_000_000: // 150MHz, e.g. rp2350
|
||||||
|
d.writeByte150(c)
|
||||||
|
return nil
|
||||||
case 168_000_000: // 168MHz, e.g. stm32f405
|
case 168_000_000: // 168MHz, e.g. stm32f405
|
||||||
d.writeByte168(c)
|
d.writeByte168(c)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user