Compare commits

...

14 Commits

Author SHA1 Message Date
deadprogram 992c02c661 lora: add starting point for US915 settings
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-09-17 19:50:39 +02:00
fchiesadoc a9b36f8bd4 Mpu9150 (#596)
mpu9150: add mpu9150 driver
2023-08-27 11:38:33 +02:00
deadprogram 1e4545828f build: use latest tag of tinygo-dev container for running tests
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-12 10:08:28 +02:00
dependabot[bot] cfa5103969 build(deps): bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20210614182718-04defd469f4e to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/commits/v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-11 14:39:57 +02:00
Patricio Whittingslow a45227590e add Sandbox Electronics NDIR CO2 sensor driver (2) (#580)
add sandbox electronics NDIR CO2 sensor
2023-08-11 11:58:28 +02:00
Kenneth Bell 4f789fb556 ssd1306: improve bus error handling 2023-08-11 11:40:45 +02:00
Kenneth Bell 996f1b047f fix uses of legacy i2c WriteRegister calls 2023-08-08 11:16:50 +02:00
Ayke van Laethem eef03917ab bma42x: add new BMA421/BMA425 driver
I wrote this for the PineTime, and all available sensors (accelerometer,
step counter, temperature sensor) do work.

This commit also includes two "configuration files", that actually
appear to be firmware files to run on the accelerometer for special
features like step counting.
I'm not sure where they originally came for, and I don't know the
copyright status of them. However, Bosch has open-sourced the BMA423
driver which includes a similar binary blob and the InfiniTime and
Wasp-OS projects have been shipping these blobs without issues, so I
think it's reasonably safe to include these binary blobs directly in the
source.
2023-08-08 10:36:23 +02:00
soypat 31538f1b2f fix requested changes by @aykevl 2023-07-02 18:30:11 +02:00
soypat 64029612e0 add correct Tx implementation for mock I2C interfaces 2023-07-02 18:30:11 +02:00
soypat e6f82fad2e i2c iface refactor: Resolve 559 2023-07-02 18:30:11 +02:00
Ayke van Laethem e20c6d05f8 st7789: fix scrolling when rotated by 180°
This fixes https://github.com/tinygo-org/drivers/issues/573.
It doesn't handle 90° or 270°, I guess it needs a fix for 270° but I
haven't tested that so didn't include it in the patch.
2023-06-20 17:49:47 +02:00
Ayke van Laethem 9c29529cbb st7789: fix incorrect Rotation configuration
The rotation as configured using st7789.Config was rotated 180°: 0° was
configured as 180°, 90° was configured as 270°, etc. Presumably with the
original test display, the ribbon cable was seen as the top of the
screen while if you look at product photos it is usually at the bottom.
Example:
https://www.buydisplay.com/wide-angle-1-3-inch-240x240-color-ips-tft-display-st7789-controller
Only Adafruit seems to sell these displays upside down:
https://www.adafruit.com/product/3787

This patch fixes this mistake. It should be noted that this is backwards
incompatible: all code that uses a st7789 will have to be modified to
use the correct rotation instead of the previous incorrect rotation.

If this is too big of a change, we could just keep things as-is and
pretend that all displays are upside down.
2023-06-20 10:44:49 +02:00
Ayke van Laethem f6d399ec08 ili9341: st7789: fix SetScrollArea
The existing code was broken in a few ways:

  - It didn't use the correct operator precedence for the VSCRDEF VSA
    variable: it needed some extra parentheses to be correct.
  - It used the configured height instead of the actual display height
    for calculating VSA, which is incorrect. TFA+VSA+BFA must always be
    exactly 320, even if a lower value is configured.
  - If a lower than 320 pixel height is configured, the bottomFixedArea
    parameter applied to the whole 320 pixel screen height. Because this
    seems counter intuitive (and relies on properties of any given
    screen), I've changed it to work from the actual visible bottom of
    the screen (which may be smaller than 320 pixels).
    TODO: this doesn't take RowOffset into account, while it probably
    should.

I haven't fixed the st7735 implementation, because I didn't have example
code on hand that would easily work on a st7735 screen. This is left as
a TODO for the future.
2023-06-20 10:27:08 +02:00
64 changed files with 1580 additions and 308 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/tinygo-org/tinygo-dev
container: ghcr.io/tinygo-org/tinygo-dev:latest
steps:
- name: Work around CVE-2022-24765
# We're not on a multi-user machine, so this is safe.
+4 -3
View File
@@ -7,6 +7,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Error uint8
@@ -54,7 +55,7 @@ func (d *Device) Configure() (err error) {
// Connected returns whether sensor has been found.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), RegID, data)
legacy.ReadRegister(d.bus, uint8(d.Address), RegID, data)
return data[0]&0xF8 == 0xC8
}
@@ -81,11 +82,11 @@ func (d *Device) writeByte(reg uint8, data byte) {
}
func (d *Device) readByte(reg uint8) byte {
d.bus.ReadRegister(d.Address, reg, d.buf)
legacy.ReadRegister(d.bus, d.Address, reg, d.buf)
return d.buf[0]
}
func (d *Device) readUint16(reg uint8) uint16 {
d.bus.ReadRegister(d.Address, reg, d.buf)
legacy.ReadRegister(d.bus, d.Address, reg, d.buf)
return uint16(d.buf[0])<<8 | uint16(d.buf[1])
}
+13 -10
View File
@@ -5,7 +5,10 @@
// Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf
package adxl345 // import "tinygo.org/x/drivers/adxl345"
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Range uint8
type Rate uint8
@@ -68,21 +71,21 @@ func New(bus drivers.I2C) Device {
// Configure sets up the device for communication
func (d *Device) Configure() {
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
d.bus.WriteRegister(uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
}
// Halt stops the sensor, values will not updated
func (d *Device) Halt() {
d.powerCtl.measure = 0
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
}
// Restart makes reading the sensor working again after a halt
func (d *Device) Restart() {
d.powerCtl.measure = 1
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
}
// ReadAcceleration reads the current acceleration from the device and returns
@@ -103,7 +106,7 @@ func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
// from the adxl345.
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
data := []byte{0, 0, 0, 0, 0, 0}
d.bus.ReadRegister(uint8(d.Address), REG_DATAX0, data)
legacy.ReadRegister(d.bus, uint8(d.Address), REG_DATAX0, data)
x = readIntLE(data[0], data[1])
y = readIntLE(data[2], data[3])
@@ -119,20 +122,20 @@ func (d *Device) UseLowPower(power bool) {
} else {
d.bwRate.lowPower = 0
}
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
}
// SetRate change the current rate of the sensor
func (d *Device) SetRate(rate Rate) bool {
d.bwRate.rate = rate & 0x0F
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
return true
}
// SetRange change the current range of the sensor
func (d *Device) SetRange(sensorRange Range) bool {
d.dataFormat.sensorRange = sensorRange & 0x03
d.bus.WriteRegister(uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
return true
}
+17 -16
View File
@@ -8,6 +8,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a AMG88xx device.
@@ -48,7 +49,7 @@ func (d *Device) Configure(cfg Config) {
// ReadPixels returns the 64 values (8x8 grid) of the sensor converted to millicelsius
func (d *Device) ReadPixels(buffer *[64]int16) {
d.bus.ReadRegister(uint8(d.Address), PIXEL_OFFSET, d.data)
legacy.ReadRegister(d.bus, uint8(d.Address), PIXEL_OFFSET, d.data)
for i := 0; i < 64; i++ {
buffer[i] = int16((uint16(d.data[2*i+1]) << 8) | uint16(d.data[2*i]))
if (buffer[i] & (1 << 11)) > 0 { // temperature negative
@@ -61,17 +62,17 @@ func (d *Device) ReadPixels(buffer *[64]int16) {
// SetPCTL sets the PCTL
func (d *Device) SetPCTL(pctl uint8) {
d.bus.WriteRegister(uint8(d.Address), PCTL, []byte{pctl})
legacy.WriteRegister(d.bus, uint8(d.Address), PCTL, []byte{pctl})
}
// SetReset sets the reset value
func (d *Device) SetReset(rst uint8) {
d.bus.WriteRegister(uint8(d.Address), RST, []byte{rst})
legacy.WriteRegister(d.bus, uint8(d.Address), RST, []byte{rst})
}
// SetFrameRate configures the frame rate
func (d *Device) SetFrameRate(framerate uint8) {
d.bus.WriteRegister(uint8(d.Address), FPSC, []byte{framerate & 0x01})
legacy.WriteRegister(d.bus, uint8(d.Address), FPSC, []byte{framerate & 0x01})
}
// SetMovingAverageMode sets the moving average mode
@@ -80,7 +81,7 @@ func (d *Device) SetMovingAverageMode(mode bool) {
if mode {
value = 1
}
d.bus.WriteRegister(uint8(d.Address), AVE, []byte{value << 5})
legacy.WriteRegister(d.bus, uint8(d.Address), AVE, []byte{value << 5})
}
// SetInterruptLevels sets the interrupt levels
@@ -97,8 +98,8 @@ func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis
if high > 4095 {
high = 4095
}
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(high & 0xFF)})
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((high & 0xFF) >> 4)})
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(high & 0xFF)})
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((high & 0xFF) >> 4)})
low = low / PIXEL_TEMP_CONVERSION
if low < -4095 {
@@ -107,8 +108,8 @@ func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis
if low > 4095 {
low = 4095
}
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(low & 0xFF)})
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((low & 0xFF) >> 4)})
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(low & 0xFF)})
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((low & 0xFF) >> 4)})
hysteresis = hysteresis / PIXEL_TEMP_CONVERSION
if hysteresis < -4095 {
@@ -117,32 +118,32 @@ func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis
if hysteresis > 4095 {
hysteresis = 4095
}
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(hysteresis & 0xFF)})
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((hysteresis & 0xFF) >> 4)})
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(hysteresis & 0xFF)})
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((hysteresis & 0xFF) >> 4)})
}
// EnableInterrupt enables the interrupt pin on the device
func (d *Device) EnableInterrupt() {
d.interruptEnable = 1
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
}
// DisableInterrupt disables the interrupt pin on the device
func (d *Device) DisableInterrupt() {
d.interruptEnable = 0
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
}
// SetInterruptMode sets the interrupt mode
func (d *Device) SetInterruptMode(mode InterruptMode) {
d.interruptMode = mode
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
}
// GetInterrupt reads the state of the triggered interrupts
func (d *Device) GetInterrupt() []uint8 {
data := make([]uint8, 8)
d.bus.ReadRegister(uint8(d.Address), INT_OFFSET, data)
legacy.ReadRegister(d.bus, uint8(d.Address), INT_OFFSET, data)
return data
}
@@ -154,6 +155,6 @@ func (d *Device) ClearInterrupt() {
// ReadThermistor reads the onboard thermistor
func (d *Device) ReadThermistor() int16 {
data := make([]uint8, 2)
d.bus.ReadRegister(uint8(d.Address), TTHL, data)
legacy.ReadRegister(d.bus, uint8(d.Address), TTHL, data)
return (int16((uint16(data[1])<<8)|uint16(data[0])) * THERMISTOR_CONVERSION) / 10
}
+26 -25
View File
@@ -8,6 +8,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a APDS-9960 device.
@@ -68,7 +69,7 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
legacy.ReadRegister(d.bus, d.Address, APDS9960_ID_REG, data)
return data[0] == 0xAB
}
@@ -80,7 +81,7 @@ func (d *Device) GetMode() uint8 {
// DisableAll turns off the device and all functions
func (d *Device) DisableAll() {
d.enable(enableConfig{})
d.bus.WriteRegister(d.Address, APDS9960_GCONF4_REG, []byte{0x00})
legacy.WriteRegister(d.bus, d.Address, APDS9960_GCONF4_REG, []byte{0x00})
d.mode = MODE_NONE
d.gesture.detected = GESTURE_NONE
}
@@ -88,13 +89,13 @@ func (d *Device) DisableAll() {
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
// default: 16, 64
func (d *Device) SetProximityPulse(length, count uint8) {
d.bus.WriteRegister(d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
legacy.WriteRegister(d.bus, d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
}
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
// default: 16, 64
func (d *Device) SetGesturePulse(length, count uint8) {
d.bus.WriteRegister(d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
legacy.WriteRegister(d.bus, d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
}
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
@@ -103,14 +104,14 @@ func (d *Device) SetADCIntegrationCycles(cycles uint16) {
if cycles > 256 {
cycles = 256
}
d.bus.WriteRegister(d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
legacy.WriteRegister(d.bus, d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
}
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
// default: 1, 1, 4
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
d.bus.WriteRegister(d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
d.bus.WriteRegister(d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
legacy.WriteRegister(d.bus, d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
legacy.WriteRegister(d.bus, d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
}
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
@@ -127,7 +128,7 @@ func (d *Device) LEDBoost(percent uint16) {
case 300:
v = 3
}
d.bus.WriteRegister(d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
legacy.WriteRegister(d.bus, d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
}
// Setthreshold sets threshold (0~255) for detecting gestures
@@ -168,7 +169,7 @@ func (d *Device) ReadProximity() (proximity int32) {
return 0
}
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_PDATA_REG, data)
legacy.ReadRegister(d.bus, d.Address, APDS9960_PDATA_REG, data)
return 255 - int32(data[0])
}
@@ -195,14 +196,14 @@ func (d *Device) ReadColor() (r int32, g int32, b int32, clear int32) {
return
}
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
d.bus.ReadRegister(d.Address, APDS9960_CDATAL_REG, data[:1])
d.bus.ReadRegister(d.Address, APDS9960_CDATAH_REG, data[1:2])
d.bus.ReadRegister(d.Address, APDS9960_RDATAL_REG, data[2:3])
d.bus.ReadRegister(d.Address, APDS9960_RDATAH_REG, data[3:4])
d.bus.ReadRegister(d.Address, APDS9960_GDATAL_REG, data[4:5])
d.bus.ReadRegister(d.Address, APDS9960_GDATAH_REG, data[5:6])
d.bus.ReadRegister(d.Address, APDS9960_BDATAL_REG, data[6:7])
d.bus.ReadRegister(d.Address, APDS9960_BDATAH_REG, data[7:])
legacy.ReadRegister(d.bus, d.Address, APDS9960_CDATAL_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, APDS9960_CDATAH_REG, data[1:2])
legacy.ReadRegister(d.bus, d.Address, APDS9960_RDATAL_REG, data[2:3])
legacy.ReadRegister(d.bus, d.Address, APDS9960_RDATAH_REG, data[3:4])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GDATAL_REG, data[4:5])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GDATAH_REG, data[5:6])
legacy.ReadRegister(d.bus, d.Address, APDS9960_BDATAL_REG, data[6:7])
legacy.ReadRegister(d.bus, d.Address, APDS9960_BDATAH_REG, data[7:])
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
r = int32(uint16(data[3])<<8 | uint16(data[2]))
g = int32(uint16(data[5])<<8 | uint16(data[4]))
@@ -234,13 +235,13 @@ func (d *Device) GestureAvailable() bool {
data := []byte{0, 0, 0, 0}
// check GVALID
d.bus.ReadRegister(d.Address, APDS9960_GSTATUS_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GSTATUS_REG, data[:1])
if data[0]&0x01 == 0 {
return false
}
// get number of data sets available in FIFO
d.bus.ReadRegister(d.Address, APDS9960_GFLVL_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFLVL_REG, data[:1])
availableDataSets := data[0]
if availableDataSets == 0 {
return false
@@ -249,10 +250,10 @@ func (d *Device) GestureAvailable() bool {
// read up, down, left and right proximity data from FIFO
var dataSets [32][4]uint8
for i := uint8(0); i < availableDataSets; i++ {
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_U_REG, data[:1])
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_D_REG, data[1:2])
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_L_REG, data[2:3])
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_R_REG, data[3:4])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_U_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_D_REG, data[1:2])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_L_REG, data[2:3])
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_R_REG, data[3:4])
for j := uint8(0); j < 4; j++ {
dataSets[i][j] = data[j]
}
@@ -385,7 +386,7 @@ func (d *Device) enable(cfg enableConfig) {
}
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
d.bus.WriteRegister(d.Address, APDS9960_ENABLE_REG, data)
legacy.WriteRegister(d.bus, d.Address, APDS9960_ENABLE_REG, data)
if cfg.PON {
time.Sleep(time.Millisecond * 10)
@@ -394,7 +395,7 @@ func (d *Device) enable(cfg enableConfig) {
func (d *Device) readStatus(param string) bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_STATUS_REG, data)
legacy.ReadRegister(d.bus, d.Address, APDS9960_STATUS_REG, data)
switch param {
case "CPSAT":
+3 -2
View File
@@ -5,6 +5,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// registerAttributes is a bitfield of attributes for a register
@@ -94,7 +95,7 @@ func (r *i2cRegister) readShiftAndMask(bus drivers.I2C, deviceAddress uint8, shi
buf = buffer[:]
}
// Read the host register over I2C
err := bus.ReadRegister(deviceAddress, r.host.address, buf)
err := legacy.ReadRegister(bus, deviceAddress, r.host.address, buf)
if nil != err {
return 0, err
}
@@ -158,7 +159,7 @@ func (r *i2cRegister) write(bus drivers.I2C, deviceAddress uint8, value uint16)
}
// Write the register from the buffer over I2C
err := bus.WriteRegister(deviceAddress, r.host.address, buf)
err := legacy.WriteRegister(bus, deviceAddress, r.host.address, buf)
// after successful I2C write, cache this value if the host register (if also readable)
// Note we cache the entire buffer without applying shift/mask
if nil == err && r.host.attributes&reg_read != 0 {
+3 -2
View File
@@ -7,6 +7,7 @@ package axp192 // import "tinygo.org/x/drivers/axp192"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Error uint8
@@ -248,10 +249,10 @@ func (d *Device) SetLDOEnable(number uint8, state bool) {
}
func (d *Device) write1Byte(reg, data uint8) {
d.bus.WriteRegister(d.Address, reg, []byte{data})
legacy.WriteRegister(d.bus, d.Address, reg, []byte{data})
}
func (d *Device) read8bit(reg uint8) uint8 {
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
legacy.ReadRegister(d.bus, d.Address, reg, d.buf[:1])
return d.buf[0]
}
Binary file not shown.
Binary file not shown.
+352
View File
@@ -0,0 +1,352 @@
// Package bma42x provides a driver for the BMA421 and BMA425 accelerometer
// chips.
//
// Here is a reasonably good datasheet:
// https://datasheet.lcsc.com/lcsc/1912111437_Bosch-Sensortec-BMA425_C437656.pdf
//
// This driver was originally written for the PineTime, using the datasheet as a
// guide. There is an open source C driver provided by Bosch, but unfortunately
// it needs some small modifications to work with other chips (most importantly,
// the "config file").
// The InfiniTime and Wasp-OS drivers for this accelerometer have also been used
// to figure out some driver details (especially step counting).
package bma42x
import (
_ "embed"
"errors"
"reflect"
"time"
"unsafe"
"tinygo.org/x/drivers"
)
// Driver for BMA421 and BMA425:
// BMA421: https://files.pine64.org/doc/datasheet/pinetime/BST-BMA421-FL000.pdf
// BMA425: https://datasheet.lcsc.com/lcsc/1912111437_Bosch-Sensortec-BMA425_C437656.pdf
// This is the BMA421 firmware from the Wasp-OS project.
// It is identical to the so-called BMA423 firmware in InfiniTime, which I
// suspect to be actually a BMA421 firmware. I don't know where this firmware
// comes from or what the licensing status is.
// It has the FEATURES_IN command prepended, so that it can be written directly
// using I2C.Tx.
// Source: https://github.com/wasp-os/bma42x-upy/blob/master/BMA42X-Sensor-API/bma421.h
//
//go:embed bma421-config-waspos.bin
var bma421Firmware string
// Same as the BMA421 firmware, but for the BMA425.
// Source: https://github.com/wasp-os/bma42x-upy/blob/master/BMA42X-Sensor-API/bma425.h
//
//go:embed bma425-config-waspos.bin
var bma425Firmware string
var (
errUnknownDevice = errors.New("bma42x: unknown device")
errUnsupportedDevice = errors.New("bma42x: device not part of config")
errConfigMismatch = errors.New("bma42x: config mismatch")
errTimeout = errors.New("bma42x: timeout")
errInitFailed = errors.New("bma42x: failed to initialize")
)
const Address = 0x18 // BMA421/BMA425 address
type DeviceType uint8
const (
DeviceBMA421 DeviceType = 1 << iota
DeviceBMA425
AnyDevice = DeviceBMA421 | DeviceBMA425
noDevice DeviceType = 0
)
// Features to enable while configuring the accelerometer.
type Features uint8
const (
FeatureStepCounting = 1 << iota
)
type Config struct {
// Which devices to support (OR the device types together as needed).
Device DeviceType
// Which features to enable. With Features == 0, only the accelerometer will
// be enabled.
Features Features
}
type Device struct {
bus drivers.I2C
address uint8
accelData [6]byte
combinedTempSteps [5]uint8 // [0:3] steps, [4] temperature
dataBuf [2]byte
}
func NewI2C(i2c drivers.I2C, address uint8) *Device {
return &Device{
bus: i2c,
address: address,
}
}
func (d *Device) Connected() bool {
val, err := d.read1(_CHIP_ID)
return err == nil && identifyChip(val) != noDevice
}
func (d *Device) Configure(config Config) error {
if config.Device == 0 {
config.Device = AnyDevice
}
// Check chip ID, to check the connection and to determine which BMA42x
// device we're dealing with.
chipID, err := d.read1(_CHIP_ID)
if err != nil {
return err
}
// Determine which firmware (config file?) we'll be using.
// There is an extra check for the device before using the given firmware.
// This check will typically be optimized away if the given device is not
// configured, so that the firmware (which is 6kB in size!) won't be linked
// into the binary.
var firmware string
switch identifyChip(chipID) {
case DeviceBMA421:
if config.Device&DeviceBMA421 == 0 {
return errUnsupportedDevice
}
firmware = bma421Firmware
case DeviceBMA425:
if config.Device&DeviceBMA425 == 0 {
return errUnsupportedDevice
}
firmware = bma425Firmware
default:
return errUnknownDevice
}
// Reset the chip, to be able to initialize it properly.
// The datasheet says a delay is needed after a SoftReset, but it doesn't
// say how long this delay should be. The bma423 driver however uses a 200ms
// delay, so that's what we'll be using.
err = d.write1(_CMD, cmdSoftReset)
if err != nil {
return err
}
time.Sleep(200 * time.Millisecond)
// Disable power saving.
err = d.write1(_PWR_CONF, 0x00)
if err != nil {
return err
}
time.Sleep(450 * time.Microsecond)
// Start initialization (because the datasheet says so).
err = d.write1(_INIT_CTRL, 0x00)
if err != nil {
return err
}
// Write "config file" (actually a firmware, I think) to the chip.
// To do this, unsafely cast the string to a byte slice to avoid putting it
// in RAM. This is safe in this case because Tx won't write to the 'w'
// slice.
err = d.bus.Tx(uint16(d.address), unsafeStringToSlice(firmware), nil)
if err != nil {
return err
}
// Read the config data back.
// We don't do that, as it slows down configuration and it probably isn't
// _really_ necessary with a reasonably stable I2C bus.
if false {
data := make([]byte, len(firmware)-1)
err = d.readn(_FEATURES_IN, data)
if err != nil {
return err
}
for i, c := range data {
if firmware[i+1] != c {
return errConfigMismatch
}
}
}
// Enable sensors.
err = d.write1(_INIT_CTRL, 0x01)
if err != nil {
return err
}
// Wait until the device is initialized.
start := time.Now()
status := uint8(0) // busy
for status == 0 {
status, err = d.read1(_INTERNAL_STATUS)
if err != nil {
return err // I2C bus error.
}
if status > 1 {
// Expected either 0 ("not_init") or 1 ("init_ok").
return errInitFailed
}
if time.Since(start) >= 150*time.Millisecond {
// The datasheet says initialization should not take longer than
return errTimeout
}
// Don't bother the chip all the time while it's initializing.
time.Sleep(50 * time.Microsecond)
}
if config.Features&FeatureStepCounting != 0 {
// Enable step counter.
// TODO: support step counter parameters.
var buf [71]byte
buf[0] = _FEATURES_IN // prefix buf with the command
data := buf[1:]
err = d.readn(_FEATURES_IN, data)
if err != nil {
return err
}
data[0x3A+1] |= 0x10 // enable step counting by setting a magical bit
err = d.bus.Tx(uint16(d.address), buf[:], nil)
if err != nil {
return err
}
}
// Enable the accelerometer.
err = d.write1(_PWR_CTRL, 0x04)
if err != nil {
return err
}
// Configure accelerometer for low power usage:
// acc_perf_mode=0 (power saving enabled)
// acc_bwp=osr4_avg1 (no averaging)
// acc_odr=50Hz (50Hz sampling interval, enough for the step counter)
const accelConf = 0x00<<7 | 0x00<<4 | 0x07<<0
err = d.write1(_ACC_CONF, accelConf)
if err != nil {
return err
}
// Reduce current consumption.
// With power saving enabled (and the above ACC_CONF) the chip consumes only
// 14µA.
err = d.write1(_PWR_CONF, 0x03)
if err != nil {
return err
}
return nil
}
func (d *Device) Update(which drivers.Measurement) error {
// TODO: combine temperature and step counter into a single read.
if which&drivers.Temperature != 0 {
val, err := d.read1(_TEMPERATURE)
if err != nil {
return err
}
d.combinedTempSteps[4] = val
}
if which&drivers.Acceleration != 0 {
// The acceleration data is stored in DATA8 through DATA13 as 3 12-bit
// values.
err := d.readn(_DATA_8, d.accelData[:]) // ACC_X(LSB)
if err != nil {
return err
}
err = d.readn(_STEP_COUNTER_0, d.combinedTempSteps[:4])
if err != nil {
return err
}
}
return nil
}
// Temperature returns the last read temperature in celsius milli degrees (1°C
// is 1000).
func (d *Device) Temperature() int32 {
// The temperature value is a two's complement number (meaning: signed) in
// units of 1 kelvin, with 0 being 23°C.
return (int32(int8(d.combinedTempSteps[4])) + 23) * 1000
}
// Acceleration returns the last read acceleration in µg (micro-gravity).
// When one of the axes is pointing straight to Earth and the sensor is not
// moving the returned value will be around 1000000 or -1000000.
func (d *Device) Acceleration() (x, y, z int32) {
// Combine raw data from d.accelData (stored as 12-bit signed values) into a
// number (0..4095):
x = int32(d.accelData[0])>>4 | int32(d.accelData[1])<<4
y = int32(d.accelData[2])>>4 | int32(d.accelData[3])<<4
z = int32(d.accelData[4])>>4 | int32(d.accelData[5])<<4
// Sign extend this number to -2048..2047:
x = (x << 20) >> 20
y = (y << 20) >> 20
z = (z << 20) >> 20
// Scale from -512..511 to -1000_000..998_046.
// Or, at the maximum range (4g), from -2048..2047 to -2000_000..3998_046.
// The formula derived as follows (where 512 is the expected value at 1g):
// x = x * 1000_000 / 512
// x = x * (1000_000/64) / (512/64)
// x = x * 15625 / 8
x = x * 15625 / 8
y = y * 15625 / 8
z = z * 15625 / 8
return
}
// Steps returns the number of steps counted since the BMA42x sensor was
// initialized.
func (d *Device) Steps() (steps uint32) {
steps |= uint32(d.combinedTempSteps[0]) << 0
steps |= uint32(d.combinedTempSteps[1]) << 8
steps |= uint32(d.combinedTempSteps[2]) << 16
steps |= uint32(d.combinedTempSteps[3]) << 24
return
}
func (d *Device) read1(register uint8) (uint8, error) {
d.dataBuf[0] = register
err := d.bus.Tx(uint16(d.address), d.dataBuf[:1], d.dataBuf[1:2])
return d.dataBuf[1], err
}
func (d *Device) readn(register uint8, data []byte) error {
d.dataBuf[0] = register
return d.bus.Tx(uint16(d.address), d.dataBuf[:1], data)
}
func (d *Device) write1(register uint8, data uint8) error {
d.dataBuf[0] = register
d.dataBuf[1] = data
return d.bus.Tx(uint16(d.address), d.dataBuf[:2], nil)
}
func unsafeStringToSlice(s string) []byte {
// TODO: use unsafe.Slice(unsafe.StringData(...)) once we require Go 1.20.
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
return unsafe.Slice((*byte)(unsafe.Pointer(sh.Data)), len(s))
}
func identifyChip(chipID uint8) DeviceType {
switch chipID {
case 0x11:
return DeviceBMA421
case 0x13:
return DeviceBMA425
default:
return noDevice
}
}
+73
View File
@@ -0,0 +1,73 @@
package bma42x
const (
// I2C registers
_CHIP_ID = 0x00
_ERR_REG = 0x02
_STATUS = 0x03
_DATA_0 = 0x0A
_DATA_1 = 0x0B
_DATA_2 = 0x0C
_DATA_3 = 0x0D
_DATA_4 = 0x0E
_DATA_5 = 0x0F
_DATA_6 = 0x10
_DATA_7 = 0x11
_DATA_8 = 0x12
_DATA_9 = 0x13
_DATA_10 = 0x14
_DATA_11 = 0x15
_DATA_12 = 0x16
_DATA_13 = 0x17
_SENSORTIME_0 = 0x18
_SENSORTIME_1 = 0x19
_SENSORTIME_2 = 0x1A
_EVENT = 0x1B
_INT_STATUS_0 = 0x1C
_INT_STATUS_1 = 0x1D
_STEP_COUNTER_0 = 0x1E
_STEP_COUNTER_1 = 0x1F
_STEP_COUNTER_2 = 0x20
_STEP_COUNTER_3 = 0x21
_TEMPERATURE = 0x22
_FIFO_LENGTH_0 = 0x24
_FIFO_LENGTH_1 = 0x25
_FIFO_DATA = 0x26
_ACTIVITY_TYPE = 0x27
_INTERNAL_STATUS = 0x2A
_ACC_CONF = 0x40
_ACC_RANGE = 0x41
_AUX_CONF = 0x44
_FIFO_DOWNS = 0x45
_FIFO_WTM_0 = 0x46
_FIFO_WTM_1 = 0x47
_FIFO_CONFIG_0 = 0x48
_FIFO_CONFIG_1 = 0x49
_AUX_DEV_ID = 0x4B
_AUX_IF_CONF = 0x4C
_AUX_RD_ADDR = 0x4D
_AUX_WR_ADDR = 0x4E
_AUX_WR_DATA = 0x4F
_INT1_IO_CTRL = 0x53
_INT2_IO_CTRL = 0x54
_INT_LATCH = 0x55
_INT1_MAP = 0x56
_INT2_MAP = 0x57
_INT_MAP_DATA = 0x58
_INIT_CTRL = 0x59
_FEATURES_IN = 0x5E
_INTERNAL_ERROR = 0x5F
_NVM_CONF = 0x6A
_IF_CONF = 0x6B
_ACC_SELF_TEST = 0x6D
_NV_CONF = 0x70
_OFFSET_0 = 0x71
_OFFSET_1 = 0x72
_OFFSET_2 = 0x73
_PWR_CONF = 0x7C
_PWR_CTRL = 0x7D
_CMD = 0x7E
// Commands send to regCommand.
cmdSoftReset = 0xB6
)
+12 -11
View File
@@ -10,6 +10,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// calibrationCoefficients reads at startup and stores the calibration coefficients
@@ -98,19 +99,19 @@ func (d *Device) ConfigureWithSettings(config Config) {
}
var data [24]byte
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALIBRATION, data[:])
if err != nil {
return
}
var h1 [1]byte
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H1, h1[:])
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALIBRATION_H1, h1[:])
if err != nil {
return
}
var h2lsb [7]byte
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H2LSB, h2lsb[:])
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALIBRATION_H2LSB, h2lsb[:])
if err != nil {
return
}
@@ -137,12 +138,12 @@ func (d *Device) ConfigureWithSettings(config Config) {
d.Reset()
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{byte(d.Config.Period<<5) | byte(d.Config.IIR<<2)})
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{byte(d.Config.Humidity)})
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_CONFIG, []byte{byte(d.Config.Period<<5) | byte(d.Config.IIR<<2)})
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{byte(d.Config.Humidity)})
// Normal mode, start measuring now
if d.Config.Mode == ModeNormal {
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_MEAS_ADDR, []byte{
byte(d.Config.Temperature<<5) |
byte(d.Config.Pressure<<2) |
byte(d.Config.Mode)})
@@ -153,13 +154,13 @@ func (d *Device) ConfigureWithSettings(config Config) {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == CHIP_ID
}
// Reset the device
func (d *Device) Reset() {
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
legacy.WriteRegister(d.bus, uint8(d.Address), CMD_RESET, []byte{0xB6})
}
// SetMode can set the device to Sleep, Normal or Forced mode
@@ -170,7 +171,7 @@ func (d *Device) Reset() {
func (d *Device) SetMode(mode Mode) {
d.Config.Mode = mode
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_MEAS_ADDR, []byte{
byte(d.Config.Temperature<<5) |
byte(d.Config.Pressure<<2) |
byte(d.Config.Mode)})
@@ -252,7 +253,7 @@ func readIntLE(msb byte, lsb byte) int16 {
func (d *Device) readData() (data [8]byte, err error) {
if d.Config.Mode == ModeForced {
// Write the CTRL_MEAS register to trigger a measurement
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_MEAS_ADDR, []byte{
byte(d.Config.Temperature<<5) |
byte(d.Config.Pressure<<2) |
byte(d.Config.Mode)})
@@ -260,7 +261,7 @@ func (d *Device) readData() (data [8]byte, err error) {
time.Sleep(d.measurementDelay())
}
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_PRESSURE, data[:])
if err != nil {
println(err)
return
+7 -6
View File
@@ -10,6 +10,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// OversamplingMode is the oversampling ratio of the pressure measurement.
@@ -55,7 +56,7 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == CHIP_ID
}
@@ -63,7 +64,7 @@ func (d *Device) Connected() bool {
// read the calibration coefficients.
func (d *Device) Configure() {
data := make([]byte, 22)
err := d.bus.ReadRegister(uint8(d.Address), AC1_MSB, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), AC1_MSB, data)
if err != nil {
return
}
@@ -141,10 +142,10 @@ func (d *Device) ReadAltitude() (int32, error) {
// rawTemp returns the sensor's raw values of the temperature
func (d *Device) rawTemp() (int32, error) {
d.bus.WriteRegister(uint8(d.Address), REG_CTRL, []byte{CMD_TEMP})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL, []byte{CMD_TEMP})
time.Sleep(5 * time.Millisecond)
data := make([]byte, 2)
err := d.bus.ReadRegister(uint8(d.Address), REG_TEMP_MSB, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_TEMP_MSB, data)
if err != nil {
return 0, err
}
@@ -160,10 +161,10 @@ func (d *Device) calculateB5(rawTemp int32) int32 {
// rawPressure returns the sensor's raw values of the pressure
func (d *Device) rawPressure(mode OversamplingMode) (int32, error) {
d.bus.WriteRegister(uint8(d.Address), REG_CTRL, []byte{CMD_PRESSURE + byte(mode<<6)})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL, []byte{CMD_PRESSURE + byte(mode<<6)})
time.Sleep(pauseForReading(mode))
data := make([]byte, 3)
err := d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE_MSB, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_PRESSURE_MSB, data)
if err != nil {
return 0, err
}
+9 -8
View File
@@ -4,6 +4,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// OversamplingMode is the oversampling ratio of the temperature or pressure measurement.
@@ -64,14 +65,14 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := make([]byte, 1)
d.bus.ReadRegister(uint8(d.Address), REG_ID, data)
legacy.ReadRegister(d.bus, uint8(d.Address), REG_ID, data)
return data[0] == CHIP_ID
}
// Reset preforms complete power-on-reset procedure.
// It is required to call Configure afterwards.
func (d *Device) Reset() {
d.bus.WriteRegister(uint8(d.Address), REG_RESET, []byte{CMD_RESET})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_RESET, []byte{CMD_RESET})
}
// Configure sets up the device for communication and
@@ -85,15 +86,15 @@ func (d *Device) Configure(standby Standby, filter Filter, temp Oversampling, pr
// Write the configuration (standby, filter, spi 3 wire)
config := uint(d.Standby<<5) | uint(d.Filter<<2) | 0x00
d.bus.WriteRegister(uint8(d.Address), REG_CONFIG, []byte{byte(config)})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONFIG, []byte{byte(config)})
// Write the control (temperature oversampling, pressure oversampling,
config = uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(d.Mode)
d.bus.WriteRegister(uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
// Read Calibration data
data := make([]byte, 24)
err := d.bus.ReadRegister(uint8(d.Address), REG_CALI, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALI, data)
if err != nil {
return
}
@@ -207,18 +208,18 @@ func (d *Device) readData(register int, n int) ([]byte, error) {
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
if d.Mode != MODE_NORMAL {
config := uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(MODE_FORCED)
d.bus.WriteRegister(uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
}
// Check STATUS register, wait if data is not available yet
status := make([]byte, 1)
for d.bus.ReadRegister(uint8(d.Address), uint8(REG_STATUS), status[0:]); status[0] != 4 && status[0] != 0; d.bus.ReadRegister(uint8(d.Address), uint8(REG_STATUS), status[0:]) {
for legacy.ReadRegister(d.bus, uint8(d.Address), uint8(REG_STATUS), status[0:]); status[0] != 4 && status[0] != 0; legacy.ReadRegister(d.bus, uint8(d.Address), uint8(REG_STATUS), status[0:]) {
time.Sleep(time.Millisecond)
}
// Read the requested register
data := make([]byte, n)
err := d.bus.ReadRegister(uint8(d.Address), uint8(register), data[:])
err := legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
return data, err
}
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
var (
@@ -240,10 +241,10 @@ func (d *Device) configurationError() bool {
func (d *Device) readRegister(register byte, len int) (data []byte, err error) {
data = make([]byte, len)
err = d.bus.ReadRegister(d.Address, register, data)
err = legacy.ReadRegister(d.bus, d.Address, register, data)
return
}
func (d *Device) writeRegister(register byte, data byte) error {
return d.bus.WriteRegister(d.Address, register, []byte{data})
return legacy.WriteRegister(d.bus, d.Address, register, []byte{data})
}
+5 -4
View File
@@ -9,6 +9,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a DS1307 device.
@@ -44,7 +45,7 @@ func (d *Device) SetTime(t time.Time) error {
// ReadTime returns the date and time
func (d *Device) ReadTime() (time.Time, error) {
data := make([]byte, 8)
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
if err != nil {
return time.Time{}, err
}
@@ -105,7 +106,7 @@ func (d *Device) Read(data []uint8) (n int, err error) {
if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
return 0, errors.New("EOF")
}
err = d.bus.ReadRegister(d.Address, d.AddressSRAM, data)
err = legacy.ReadRegister(d.bus, d.Address, d.AddressSRAM, data)
if err != nil {
return 0, err
}
@@ -124,7 +125,7 @@ func (d *Device) SetOscillatorFrequency(sqw uint8) error {
// IsOscillatorRunning returns if the oscillator is running
func (d *Device) IsOscillatorRunning() bool {
data := []byte{0}
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
if err != nil {
return false
}
@@ -134,7 +135,7 @@ func (d *Device) IsOscillatorRunning() bool {
// SetOscillatorRunning starts/stops internal oscillator by toggling halt bit
func (d *Device) SetOscillatorRunning(running bool) error {
data := make([]byte, 3)
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
if err != nil {
return err
}
+10 -9
View File
@@ -8,6 +8,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type Mode uint8
@@ -37,7 +38,7 @@ func (d *Device) Configure() bool {
// IsTimeValid return true/false is the time in the device is valid
func (d *Device) IsTimeValid() bool {
data := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_STATUS, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return false
}
@@ -47,7 +48,7 @@ func (d *Device) IsTimeValid() bool {
// IsRunning returns if the oscillator is running
func (d *Device) IsRunning() bool {
data := []uint8{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CONTROL, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return false
}
@@ -57,7 +58,7 @@ func (d *Device) IsRunning() bool {
// SetRunning starts the internal oscillator
func (d *Device) SetRunning(isRunning bool) error {
data := []uint8{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CONTROL, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
@@ -66,7 +67,7 @@ func (d *Device) SetRunning(isRunning bool) error {
} else {
data[0] |= 1 << EOSC
}
err = d.bus.WriteRegister(uint8(d.Address), REG_CONTROL, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
@@ -86,12 +87,12 @@ func (d *Device) SetRunning(isRunning bool) error {
// instead of 2100-03-01.
func (d *Device) SetTime(dt time.Time) error {
data := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_STATUS, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
data[0] &^= 1 << OSF
err = d.bus.WriteRegister(uint8(d.Address), REG_STATUS, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
@@ -117,7 +118,7 @@ func (d *Device) SetTime(dt time.Time) error {
data[5] = uint8ToBCD(uint8(dt.Month()) | centuryFlag)
data[6] = uint8ToBCD(year)
err = d.bus.WriteRegister(uint8(d.Address), REG_TIMEDATE, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_TIMEDATE, data)
if err != nil {
return err
}
@@ -128,7 +129,7 @@ func (d *Device) SetTime(dt time.Time) error {
// ReadTime returns the date and time
func (d *Device) ReadTime() (dt time.Time, err error) {
data := make([]uint8, 7)
err = d.bus.ReadRegister(uint8(d.Address), REG_TIMEDATE, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_TIMEDATE, data)
if err != nil {
return
}
@@ -150,7 +151,7 @@ func (d *Device) ReadTime() (dt time.Time, err error) {
// ReadTemperature returns the temperature in millicelsius (mC)
func (d *Device) ReadTemperature() (int32, error) {
data := make([]uint8, 2)
err := d.bus.ReadRegister(uint8(d.Address), REG_TEMP, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_TEMP, data)
if err != nil {
return 0, err
}
+54
View File
@@ -0,0 +1,54 @@
package main
// Smoke test for the BMA421/BMA425 sensors.
// Warning: this code has _not been tested_. It's only here as a smoke test.
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/bma42x"
)
func main() {
time.Sleep(5 * time.Second)
i2cBus := machine.I2C1
i2cBus.Configure(machine.I2CConfig{
Frequency: 400 * machine.KHz,
SDA: machine.SDA_PIN,
SCL: machine.SCL_PIN,
})
sensor := bma42x.NewI2C(i2cBus, bma42x.Address)
err := sensor.Configure(bma42x.Config{
Device: bma42x.DeviceBMA421 | bma42x.DeviceBMA425,
Features: bma42x.FeatureStepCounting,
})
if err != nil {
println("could not configure BMA421/BMA425:", err)
return
}
if !sensor.Connected() {
println("BMA42x not connected")
return
}
for {
time.Sleep(time.Second)
err := sensor.Update(drivers.Acceleration | drivers.Temperature)
if err != nil {
println("Error reading sensor", err)
continue
}
fmt.Printf("Temperature: %.2f °C\n", float32(sensor.Temperature())/1000)
accelX, accelY, accelZ := sensor.Acceleration()
fmt.Printf("Acceleration: %.2fg %.2fg %.2fg\n", float32(accelX)/1e6, float32(accelY)/1e6, float32(accelZ)/1e6)
}
}
+22
View File
@@ -0,0 +1,22 @@
// Connects to an MPU9150 I2C accelerometer/gyroscope.
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/mpu9150"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
accel := mpu9150.New(machine.I2C0)
accel.Configure()
for {
x, y, z := accel.ReadAcceleration(mpu9150.ACCEL_XOUT_H)
println(x, y, z)
time.Sleep(time.Millisecond * 100)
}
}
+41
View File
@@ -0,0 +1,41 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/ndir"
)
var (
ndirBus = machine.I2C0
)
func main() {
err := ndirBus.Configure(machine.I2CConfig{
Frequency: 100_000,
})
if err != nil {
panic("i2c config fail:" + err.Error())
}
// Set the address based on how the resistors are soldered.
// True means the left and middle pads are joined.
ndirAddr := ndir.Addr(true, false)
dev := ndir.NewDevI2C(ndirBus, ndirAddr)
err = dev.Init()
if err != nil {
panic("ndir init fail:" + err.Error())
}
// Datasheet tells us to wait 12 seconds before reading from the sensor.
time.Sleep(12 * time.Second)
for {
time.Sleep(time.Second)
err := dev.Update(drivers.AllMeasurements)
if err != nil {
println(err.Error())
continue
}
println("PPM:", dev.PPMCO2())
}
}
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/touch"
)
@@ -98,10 +99,10 @@ func (d *Device) Touched() bool {
}
func (d *Device) write1Byte(reg, data uint8) {
d.bus.WriteRegister(d.Address, reg, []byte{data})
legacy.WriteRegister(d.bus, d.Address, reg, []byte{data})
}
func (d *Device) read8bit(reg uint8) uint8 {
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
legacy.ReadRegister(d.bus, d.Address, reg, d.buf[:1])
return d.buf[0]
}
+2 -2
View File
@@ -6,7 +6,7 @@ require (
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/frankban/quicktest v1.10.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
golang.org/x/net v0.7.0
tinygo.org/x/tinyfont v0.3.0
tinygo.org/x/tinyterm v0.1.0
)
)
+27 -3
View File
@@ -15,15 +15,39 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/sago35/go-bdf v0.0.0-20200313142241-6c17821c91c4/go.mod h1:rOebXGuMLsXhZAC6mF/TjxONsm45498ZyzVhel++6KM=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
@@ -35,4 +59,4 @@ tinygo.org/x/tinyfont v0.3.0 h1:HIRLQoI3oc+2CMhPcfv+Ig88EcTImE/5npjqOnMD4lM=
tinygo.org/x/tinyfont v0.3.0/go.mod h1:+TV5q0KpwSGRWnN+ITijsIhrWYJkoUCp9MYELjKpAXk=
tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20=
tinygo.org/x/tinyterm v0.1.0 h1:80i+j+KWoxCFa/Xfp6pWbh79x+8zUdMXC1vaKj2QhkY=
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=
+25 -24
View File
@@ -8,6 +8,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a HTS221 device.
@@ -32,7 +33,7 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, HTS221_WHO_AM_I_REG, data)
legacy.ReadRegister(d.bus, d.Address, HTS221_WHO_AM_I_REG, data)
return data[0] == 0xBC
}
@@ -42,7 +43,7 @@ func (d *Device) Power(status bool) {
if status {
data[0] = 0x84
}
d.bus.WriteRegister(d.Address, HTS221_CTRL1_REG, data)
legacy.WriteRegister(d.bus, d.Address, HTS221_CTRL1_REG, data)
}
// ReadHumidity returns the relative humidity in percent * 100.
@@ -55,8 +56,8 @@ func (d *Device) ReadHumidity() (humidity int32, err error) {
// read data and calibrate
data := []byte{0, 0}
d.bus.ReadRegister(d.Address, HTS221_HUMID_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, HTS221_HUMID_OUT_REG+1, data[1:])
legacy.ReadRegister(d.bus, d.Address, HTS221_HUMID_OUT_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, HTS221_HUMID_OUT_REG+1, data[1:])
hValue := readInt(data[1], data[0])
hValueCalib := float32(hValue)*d.humiditySlope + d.humidityZero
@@ -73,8 +74,8 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
// read data and calibrate
data := []byte{0, 0}
d.bus.ReadRegister(d.Address, HTS221_TEMP_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, HTS221_TEMP_OUT_REG+1, data[1:])
legacy.ReadRegister(d.bus, d.Address, HTS221_TEMP_OUT_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, HTS221_TEMP_OUT_REG+1, data[1:])
tValue := readInt(data[1], data[0])
tValueCalib := float32(tValue)*d.temperatureSlope + d.temperatureZero
@@ -91,7 +92,7 @@ func (d *Device) Resolution(h uint8, t uint8) {
if t > 7 {
t = 3 // default
}
d.bus.WriteRegister(d.Address, HTS221_AV_CONF_REG, []byte{h<<3 | t})
legacy.WriteRegister(d.bus, d.Address, HTS221_AV_CONF_REG, []byte{h<<3 | t})
}
// private functions
@@ -104,19 +105,19 @@ func (d *Device) calibration() {
h0t0Out, h1t0Out := []byte{0, 0}, []byte{0, 0}
t0Out, t1Out := []byte{0, 0}, []byte{0, 0}
d.bus.ReadRegister(d.Address, HTS221_H0_rH_x2_REG, h0rH)
d.bus.ReadRegister(d.Address, HTS221_H1_rH_x2_REG, h1rH)
d.bus.ReadRegister(d.Address, HTS221_T0_degC_x8_REG, t0degC)
d.bus.ReadRegister(d.Address, HTS221_T1_degC_x8_REG, t1degC)
d.bus.ReadRegister(d.Address, HTS221_T1_T0_MSB_REG, t1t0msb)
d.bus.ReadRegister(d.Address, HTS221_H0_T0_OUT_REG, h0t0Out[:1])
d.bus.ReadRegister(d.Address, HTS221_H0_T0_OUT_REG+1, h0t0Out[1:])
d.bus.ReadRegister(d.Address, HTS221_H1_T0_OUT_REG, h1t0Out[:1])
d.bus.ReadRegister(d.Address, HTS221_H1_T0_OUT_REG+1, h1t0Out[1:])
d.bus.ReadRegister(d.Address, HTS221_T0_OUT_REG, t0Out[:1])
d.bus.ReadRegister(d.Address, HTS221_T0_OUT_REG+1, t0Out[1:])
d.bus.ReadRegister(d.Address, HTS221_T1_OUT_REG, t1Out[:1])
d.bus.ReadRegister(d.Address, HTS221_T1_OUT_REG+1, t1Out[1:])
legacy.ReadRegister(d.bus, d.Address, HTS221_H0_rH_x2_REG, h0rH)
legacy.ReadRegister(d.bus, d.Address, HTS221_H1_rH_x2_REG, h1rH)
legacy.ReadRegister(d.bus, d.Address, HTS221_T0_degC_x8_REG, t0degC)
legacy.ReadRegister(d.bus, d.Address, HTS221_T1_degC_x8_REG, t1degC)
legacy.ReadRegister(d.bus, d.Address, HTS221_T1_T0_MSB_REG, t1t0msb)
legacy.ReadRegister(d.bus, d.Address, HTS221_H0_T0_OUT_REG, h0t0Out[:1])
legacy.ReadRegister(d.bus, d.Address, HTS221_H0_T0_OUT_REG+1, h0t0Out[1:])
legacy.ReadRegister(d.bus, d.Address, HTS221_H1_T0_OUT_REG, h1t0Out[:1])
legacy.ReadRegister(d.bus, d.Address, HTS221_H1_T0_OUT_REG+1, h1t0Out[1:])
legacy.ReadRegister(d.bus, d.Address, HTS221_T0_OUT_REG, t0Out[:1])
legacy.ReadRegister(d.bus, d.Address, HTS221_T0_OUT_REG+1, t0Out[1:])
legacy.ReadRegister(d.bus, d.Address, HTS221_T1_OUT_REG, t1Out[:1])
legacy.ReadRegister(d.bus, d.Address, HTS221_T1_OUT_REG+1, t1Out[1:])
h0rH_v := float32(h0rH[0]) / 2.0
h1rH_v := float32(h1rH[0]) / 2.0
@@ -138,7 +139,7 @@ func (d *Device) waitForOneShot(filter uint8) error {
data := []byte{0}
// check if the device is on
d.bus.ReadRegister(d.Address, HTS221_CTRL1_REG, data)
legacy.ReadRegister(d.bus, d.Address, HTS221_CTRL1_REG, data)
if data[0]&0x80 == 0 {
return errors.New("device is off, unable to query")
}
@@ -146,19 +147,19 @@ func (d *Device) waitForOneShot(filter uint8) error {
// wait until one shot (one conversion) is ready to go
data[0] = 1
for {
d.bus.ReadRegister(d.Address, HTS221_CTRL2_REG, data)
legacy.ReadRegister(d.bus, d.Address, HTS221_CTRL2_REG, data)
if data[0]&0x01 == 0 {
break
}
}
// trigger one shot
d.bus.WriteRegister(d.Address, HTS221_CTRL2_REG, []byte{0x01})
legacy.WriteRegister(d.bus, d.Address, HTS221_CTRL2_REG, []byte{0x01})
// wait until conversion completed
data[0] = 0
for {
d.bus.ReadRegister(d.Address, HTS221_STATUS_REG, data)
legacy.ReadRegister(d.bus, d.Address, HTS221_STATUS_REG, data)
if data[0]&filter == filter {
break
}
+10 -2
View File
@@ -3,7 +3,15 @@ package drivers
// I2C represents an I2C bus. It is notably implemented by the
// machine.I2C type.
type I2C interface {
ReadRegister(addr uint8, r uint8, buf []byte) error
WriteRegister(addr uint8, r uint8, buf []byte) error
// Tx performs a [I²C] transaction with address addr.
// Most I2C peripherals have some sort of register mapping scheme to allow
// users to interact with them:
//
// bus.Tx(addr, []byte{reg}, buf) // Reads register reg into buf.
// bus.Tx(addr, append([]byte{reg}, buf...), nil) // Writes buf into register reg.
//
// The semantics of most I2C transactions require that the w write buffer be non-empty.
//
// [I²C]: https://en.wikipedia.org/wiki/I%C2%B2C
Tx(addr uint16, w, r []byte) error
}
+8 -2
View File
@@ -320,10 +320,16 @@ func (d *Device) SetRotation(rotation drivers.Rotation) error {
// SetScrollArea sets an area to scroll with fixed top/bottom or left/right parts of the display
// Rotation affects scroll direction
func (d *Device) SetScrollArea(topFixedArea, bottomFixedArea int16) {
if d.height < 320 {
// The screen doesn't use the full 320 pixel height.
// Enlarge the bottom fixed area to fill the 320 pixel height, so that
// bottomFixedArea starts from the visible bottom of the screen.
bottomFixedArea += 320 - d.height
}
cmdBuf[0] = uint8(topFixedArea >> 8)
cmdBuf[1] = uint8(topFixedArea)
cmdBuf[2] = uint8(d.height - topFixedArea - bottomFixedArea>>8)
cmdBuf[3] = uint8(d.height - topFixedArea - bottomFixedArea)
cmdBuf[2] = uint8((320 - topFixedArea - bottomFixedArea) >> 8)
cmdBuf[3] = uint8(320 - topFixedArea - bottomFixedArea)
cmdBuf[4] = uint8(bottomFixedArea >> 8)
cmdBuf[5] = uint8(bottomFixedArea)
d.sendCommand(VSCRDEF, cmdBuf[:6])
+6 -3
View File
@@ -1,6 +1,9 @@
package ina260
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to an INA260 device.
type Device struct {
@@ -97,7 +100,7 @@ func (d *Device) Power() int32 {
// Read a register
func (d *Device) ReadRegister(reg uint8) uint16 {
data := []byte{0, 0}
d.bus.ReadRegister(uint8(d.Address), reg, data)
legacy.ReadRegister(d.bus, uint8(d.Address), reg, data)
return (uint16(data[0]) << 8) | uint16(data[1])
}
@@ -107,5 +110,5 @@ func (d *Device) WriteRegister(reg uint8, v uint16) {
data[0] = byte(v >> 8)
data[1] = byte(v & 0xff)
d.bus.WriteRegister(uint8(d.Address), reg, data)
legacy.WriteRegister(d.bus, uint8(d.Address), reg, data)
}
+14
View File
@@ -0,0 +1,14 @@
package legacy
import "tinygo.org/x/drivers"
func ReadRegister(bus drivers.I2C, addr uint8, reg uint8, data []byte) error {
return bus.Tx(uint16(addr), []byte{reg}, data)
}
func WriteRegister(bus drivers.I2C, addr uint8, reg uint8, data []byte) error {
buf := make([]uint8, len(data)+1)
buf[0] = reg
copy(buf[1:], data)
return bus.Tx(uint16(addr), buf, nil)
}
+6 -5
View File
@@ -20,6 +20,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device implements TinyGo driver for Lumissil IS31FL3731 matrix LED driver
@@ -92,7 +93,7 @@ func (d *Device) Configure() (err error) {
func (d *Device) selectCommand(command uint8) (err error) {
if command != d.selectedCommand {
d.selectedCommand = command
return d.bus.WriteRegister(d.Address, COMMAND, []byte{command})
return legacy.WriteRegister(d.bus, d.Address, COMMAND, []byte{command})
}
return nil
@@ -105,7 +106,7 @@ func (d *Device) writeFunctionRegister(operation uint8, data []byte) (err error)
return err
}
return d.bus.WriteRegister(d.Address, operation, data)
return legacy.WriteRegister(d.bus, d.Address, operation, data)
}
// enableLEDs enables only LEDs that are soldered on the set board. Enabled
@@ -119,7 +120,7 @@ func (d *Device) enableLEDs() (err error) {
// Enable every LED (16 columns x 9 rows)
for i := uint8(0); i < 16; i++ {
err = d.bus.WriteRegister(d.Address, i, []byte{0xFF})
err = legacy.WriteRegister(d.bus, d.Address, i, []byte{0xFF})
if err != nil {
return err
}
@@ -136,7 +137,7 @@ func (d *Device) setPixelPWD(frame, n, value uint8) (err error) {
return err
}
return d.bus.WriteRegister(d.Address, LED_PWM_OFFSET+n, []byte{value})
return legacy.WriteRegister(d.bus, d.Address, LED_PWM_OFFSET+n, []byte{value})
}
// SetActiveFrame sets frame to display with LEDs
@@ -165,7 +166,7 @@ func (d *Device) Fill(frame, value uint8) (err error) {
}
for i := uint8(0); i < 6; i++ {
err = d.bus.WriteRegister(d.Address, LED_PWM_OFFSET+i*24, data)
err = legacy.WriteRegister(d.bus, d.Address, LED_PWM_OFFSET+i*24, data)
if err != nil {
return err
}
+4 -3
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// DeviceAdafruitCharlieWing15x7 implements TinyGo driver for Lumissil
@@ -47,20 +48,20 @@ func (d *DeviceAdafruitCharlieWing15x7) enableLEDs() (err error) {
// Enable left half
for i := uint8(0); i < 16; i += 2 {
err = d.bus.WriteRegister(d.Address, i, []byte{0b11111110})
err = legacy.WriteRegister(d.bus, d.Address, i, []byte{0b11111110})
if err != nil {
return err
}
}
// Enable right half
for i := uint8(3); i < 16; i += 2 {
err = d.bus.WriteRegister(d.Address, i, []byte{0b01111111})
err = legacy.WriteRegister(d.bus, d.Address, i, []byte{0b01111111})
if err != nil {
return err
}
}
// Disable invisible column on the right side
err = d.bus.WriteRegister(d.Address, 1, []byte{0b00000000})
err = legacy.WriteRegister(d.bus, d.Address, 1, []byte{0b00000000})
if err != nil {
return err
}
+6 -5
View File
@@ -5,6 +5,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
const (
@@ -87,15 +88,15 @@ func (d *DevI2C) Configure(cfg Config) error {
}
func (d *DevI2C) Update() error {
err := d.bus.ReadRegister(d.addr, OUT_X_L, d.databuf[:2])
err := legacy.ReadRegister(d.bus, d.addr, OUT_X_L, d.databuf[:2])
if err != nil {
return err
}
err = d.bus.ReadRegister(d.addr, OUT_Y_L, d.databuf[2:4])
err = legacy.ReadRegister(d.bus, d.addr, OUT_Y_L, d.databuf[2:4])
if err != nil {
return err
}
err = d.bus.ReadRegister(d.addr, OUT_Z_L, d.databuf[4:6])
err = legacy.ReadRegister(d.bus, d.addr, OUT_Z_L, d.databuf[4:6])
if err != nil {
return err
}
@@ -131,11 +132,11 @@ func (d *DevI2C) AngularVelocity() (x, y, z int32) {
// func (d DevI2C) Update(measurement)
func (d DevI2C) read8(reg uint8) (byte, error) {
err := d.bus.ReadRegister(d.addr, reg, d.buf[:1])
err := legacy.ReadRegister(d.bus, d.addr, reg, d.buf[:1])
return d.buf[0], err
}
func (d DevI2C) write8(reg uint8, val byte) error {
d.buf[0] = val
return d.bus.WriteRegister(d.addr, reg, d.buf[:1])
return legacy.WriteRegister(d.bus, d.addr, reg, d.buf[:1])
}
+9 -8
View File
@@ -9,6 +9,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a LIS2MDL device.
@@ -38,7 +39,7 @@ func New(bus drivers.I2C) Device {
// Connected returns whether LIS2MDL sensor has been found.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x40
}
@@ -66,25 +67,25 @@ func (d *Device) Configure(cfg Configuration) {
// reset
cmd[0] = byte(1 << 5)
d.bus.WriteRegister(uint8(d.Address), CFG_REG_A, cmd)
legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd)
time.Sleep(100 * time.Millisecond)
// reboot
cmd[0] = byte(1 << 6)
d.bus.WriteRegister(uint8(d.Address), CFG_REG_A, cmd)
legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd)
time.Sleep(100 * time.Millisecond)
// bdu
cmd[0] = byte(1 << 4)
d.bus.WriteRegister(uint8(d.Address), CFG_REG_C, cmd)
legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_C, cmd)
// Temperature compensation is on for magnetic sensor (0x80)
cmd[0] = byte(0x80)
d.bus.WriteRegister(uint8(d.Address), CFG_REG_A, cmd)
legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd)
// speed
cmd[0] = byte(0x80 | d.DataRate)
d.bus.WriteRegister(uint8(d.Address), CFG_REG_A, cmd)
legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd)
}
// ReadMagneticField reads the current magnetic field from the device and returns
@@ -93,11 +94,11 @@ func (d *Device) ReadMagneticField() (x int32, y int32, z int32) {
// turn back on read mode, even though it is supposed to be continuous?
cmd := []byte{0}
cmd[0] = byte(0x80 | d.PowerMode<<4 | d.DataRate<<2 | d.SystemMode)
d.bus.WriteRegister(uint8(d.Address), CFG_REG_A, cmd)
legacy.WriteRegister(d.bus, uint8(d.Address), CFG_REG_A, cmd)
time.Sleep(10 * time.Millisecond)
data := make([]byte, 6)
d.bus.ReadRegister(uint8(d.Address), OUTX_L_REG, data)
legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_REG, data)
x = int32(int16((uint16(data[0]) << 8) | uint16(data[1])))
y = int32(int16((uint16(data[2]) << 8) | uint16(data[3])))
+13 -10
View File
@@ -3,7 +3,10 @@
// Datasheet: https://www.st.com/resource/en/datasheet/lis3dh.pdf
package lis3dh // import "tinygo.org/x/drivers/lis3dh"
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a LIS3DH device.
type Device struct {
@@ -22,13 +25,13 @@ func New(bus drivers.I2C) Device {
// Configure sets up the device for communication
func (d *Device) Configure() {
// enable all axes, normal mode
d.bus.WriteRegister(uint8(d.Address), REG_CTRL1, []byte{0x07})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL1, []byte{0x07})
// 400Hz rate
d.SetDataRate(DATARATE_400_HZ)
// High res & BDU enabled
d.bus.WriteRegister(uint8(d.Address), REG_CTRL4, []byte{0x88})
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL4, []byte{0x88})
// get current range
d.r = d.ReadRange()
@@ -38,7 +41,7 @@ func (d *Device) Configure() {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
err := legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
if err != nil {
return false
}
@@ -48,27 +51,27 @@ func (d *Device) Connected() bool {
// SetDataRate sets the speed of data collected by the LIS3DH.
func (d *Device) SetDataRate(rate DataRate) {
ctl1 := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CTRL1, ctl1)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CTRL1, ctl1)
if err != nil {
println(err.Error())
}
// mask off bits
ctl1[0] &^= 0xf0
ctl1[0] |= (byte(rate) << 4)
d.bus.WriteRegister(uint8(d.Address), REG_CTRL1, ctl1)
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL1, ctl1)
}
// SetRange sets the G range for LIS3DH.
func (d *Device) SetRange(r Range) {
ctl := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CTRL4, ctl)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CTRL4, ctl)
if err != nil {
println(err.Error())
}
// mask off bits
ctl[0] &^= 0x30
ctl[0] |= (byte(r) << 4)
d.bus.WriteRegister(uint8(d.Address), REG_CTRL4, ctl)
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL4, ctl)
// store the new range
d.r = r
@@ -77,7 +80,7 @@ func (d *Device) SetRange(r Range) {
// ReadRange returns the current G range for LIS3DH.
func (d *Device) ReadRange() (r Range) {
ctl := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CTRL4, ctl)
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CTRL4, ctl)
if err != nil {
println(err.Error())
}
@@ -111,7 +114,7 @@ func (d *Device) ReadAcceleration() (int32, int32, int32, error) {
// ReadRawAcceleration returns the raw x, y and z axis from the LIS3DH
func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
d.bus.WriteRegister(uint8(d.Address), REG_OUT_X_L|0x80, nil)
legacy.WriteRegister(d.bus, uint8(d.Address), REG_OUT_X_L|0x80, nil)
data := []byte{0, 0, 0, 0, 0, 0}
d.bus.Tx(d.Address, nil, data)
+1
View File
@@ -80,6 +80,7 @@ const (
const (
MHz_868_1 = 868100000
MHz_868_5 = 868500000
MHz_902_3 = 902300000
MHz_916_8 = 916800000
MHz_923_3 = 923300000
)
+51
View File
@@ -0,0 +1,51 @@
package region
import "tinygo.org/x/drivers/lora"
const (
US915_DEFAULT_PREAMBLE_LEN = 8
US915_DEFAULT_TX_POWER_DBM = 20
)
type RegionSettingsUS915 struct {
joinRequestChannel *Channel
joinAcceptChannel *Channel
uplinkChannel *Channel
}
// see https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/#us902-928-ism-band
func US915() *RegionSettingsUS915 {
return &RegionSettingsUS915{
joinRequestChannel: &Channel{lora.MHz_902_3,
lora.Bandwidth_125_0,
lora.SpreadingFactor10,
lora.CodingRate4_5,
US915_DEFAULT_PREAMBLE_LEN,
US915_DEFAULT_TX_POWER_DBM},
joinAcceptChannel: &Channel{lora.MHz_923_3,
lora.Bandwidth_500_0,
lora.SpreadingFactor7,
lora.CodingRate4_5,
US915_DEFAULT_PREAMBLE_LEN,
US915_DEFAULT_TX_POWER_DBM},
uplinkChannel: &Channel{lora.MHz_902_3,
lora.Bandwidth_125_0,
lora.SpreadingFactor7,
lora.CodingRate4_5,
US915_DEFAULT_PREAMBLE_LEN,
US915_DEFAULT_TX_POWER_DBM},
}
}
func (r *RegionSettingsUS915) JoinRequestChannel() *Channel {
return r.joinRequestChannel
}
func (r *RegionSettingsUS915) JoinAcceptChannel() *Channel {
return r.joinAcceptChannel
}
func (r *RegionSettingsUS915) UplinkChannel() *Channel {
return r.uplinkChannel
}
+9 -8
View File
@@ -5,6 +5,7 @@ package lps22hb
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a HTS221 device.
@@ -27,9 +28,9 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
// read data
data := []byte{0, 0, 0}
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG+1, data[1:2])
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG+2, data[2:])
legacy.ReadRegister(d.bus, d.Address, LPS22HB_PRESS_OUT_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, LPS22HB_PRESS_OUT_REG+1, data[1:2])
legacy.ReadRegister(d.bus, d.Address, LPS22HB_PRESS_OUT_REG+2, data[2:])
pValue := float32(uint32(data[2])<<16|uint32(data[1])<<8|uint32(data[0])) / 4096.0
return int32(pValue * 1000), nil
@@ -39,7 +40,7 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, LPS22HB_WHO_AM_I_REG, data)
legacy.ReadRegister(d.bus, d.Address, LPS22HB_WHO_AM_I_REG, data)
return data[0] == 0xB1
}
@@ -49,8 +50,8 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
// read data
data := []byte{0, 0}
d.bus.ReadRegister(d.Address, LPS22HB_TEMP_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, LPS22HB_TEMP_OUT_REG+1, data[1:])
legacy.ReadRegister(d.bus, d.Address, LPS22HB_TEMP_OUT_REG, data[:1])
legacy.ReadRegister(d.bus, d.Address, LPS22HB_TEMP_OUT_REG+1, data[1:])
tValue := float32(int16(uint16(data[1])<<8|uint16(data[0]))) / 100.0
return int32(tValue * 1000), nil
@@ -61,12 +62,12 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
// wait and trigger one shot in block update
func (d *Device) waitForOneShot() {
// trigger one shot
d.bus.WriteRegister(d.Address, LPS22HB_CTRL2_REG, []byte{0x01})
legacy.WriteRegister(d.bus, d.Address, LPS22HB_CTRL2_REG, []byte{0x01})
// wait until one shot is cleared
data := []byte{1}
for {
d.bus.ReadRegister(d.Address, LPS22HB_CTRL2_REG, data)
legacy.ReadRegister(d.bus, d.Address, LPS22HB_CTRL2_REG, data)
if data[0]&0x01 == 0 {
break
}
+2 -2
View File
@@ -2,10 +2,10 @@
package lps22hb
import "tinygo.org/x/drivers"
import "tinygo.org/x/drivers/internal/legacy"
// Configure sets up the LPS22HB device for communication.
func (d *Device) Configure() {
// set to block update mode
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
legacy.WriteRegister(d.bus, d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
}
+3 -1
View File
@@ -5,6 +5,8 @@ package lps22hb
import (
"machine"
"time"
"tinygo.org/x/drivers/internal/legacy"
)
// Configure sets up the LPS22HB device for communication.
@@ -18,5 +20,5 @@ func (d *Device) Configure() {
time.Sleep(10 * time.Millisecond)
// set to block update mode
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
legacy.WriteRegister(d.bus, d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
}
+11 -10
View File
@@ -9,6 +9,7 @@ import (
"math"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a LSM303AGR device.
@@ -52,8 +53,8 @@ func New(bus drivers.I2C) *Device {
// It does two "who am I" requests and checks the responses.
func (d *Device) Connected() bool {
data1, data2 := []byte{0}, []byte{0}
d.bus.ReadRegister(uint8(d.AccelAddress), ACCEL_WHO_AM_I, data1)
d.bus.ReadRegister(uint8(d.MagAddress), MAG_WHO_AM_I, data2)
legacy.ReadRegister(d.bus, uint8(d.AccelAddress), ACCEL_WHO_AM_I, data1)
legacy.ReadRegister(d.bus, uint8(d.MagAddress), MAG_WHO_AM_I, data2)
return data1[0] == 0x33 && data2[0] == 0x40
}
@@ -104,26 +105,26 @@ func (d *Device) Configure(cfg Configuration) (err error) {
data := d.buf[:1]
data[0] = byte(d.AccelDataRate<<4 | d.AccelPowerMode | 0x07)
err = d.bus.WriteRegister(uint8(d.AccelAddress), ACCEL_CTRL_REG1_A, data)
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 = d.bus.WriteRegister(uint8(d.AccelAddress), ACCEL_CTRL_REG4_A, data)
err = legacy.WriteRegister(d.bus, uint8(d.AccelAddress), ACCEL_CTRL_REG4_A, data)
if err != nil {
return
}
data[0] = byte(0xC0)
err = d.bus.WriteRegister(uint8(d.AccelAddress), TEMP_CFG_REG_A, data)
err = legacy.WriteRegister(d.bus, uint8(d.AccelAddress), TEMP_CFG_REG_A, 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 = d.bus.WriteRegister(uint8(d.MagAddress), MAG_MR_REG_M, data)
err = legacy.WriteRegister(d.bus, uint8(d.MagAddress), MAG_MR_REG_M, data)
if err != nil {
return
}
@@ -137,7 +138,7 @@ func (d *Device) Configure(cfg Configuration) (err error) {
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.AccelAddress), ACCEL_OUT_AUTO_INC, data)
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), ACCEL_OUT_AUTO_INC, data)
if err != nil {
return
}
@@ -183,14 +184,14 @@ 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 = d.bus.WriteRegister(uint8(d.MagAddress), MAG_MR_REG_M, cmd)
err = legacy.WriteRegister(d.bus, uint8(d.MagAddress), MAG_MR_REG_M, cmd)
if err != nil {
return
}
}
data := d.buf[0:6]
d.bus.ReadRegister(uint8(d.MagAddress), MAG_OUT_AUTO_INC, data)
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]))))
@@ -219,7 +220,7 @@ func (d *Device) ReadCompass() (h int32, err error) {
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_TEMP_AUTO_INC, data)
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_TEMP_AUTO_INC, data)
if err != nil {
return
}
+13 -12
View File
@@ -8,6 +8,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -95,7 +96,7 @@ func (d *Device) Configure(cfg Configuration) (err error) {
if cfg.IsPedometer { // CONFIGURE AS PEDOMETER
// Configure accelerometer: 2G + 26Hz
data[0] = uint8(ACCEL_2G) | uint8(ACCEL_SR_26)
err = d.bus.WriteRegister(uint8(d.Address), CTRL1_XL, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
if err != nil {
return
}
@@ -105,40 +106,40 @@ func (d *Device) Configure(cfg Configuration) (err error) {
if cfg.ResetStepCounter {
data[0] |= 0x02
}
err = d.bus.WriteRegister(uint8(d.Address), CTRL10_C, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL10_C, data)
if err != nil {
return
}
// Enable pedometer
data[0] = 0x40
err = d.bus.WriteRegister(uint8(d.Address), TAP_CFG, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), TAP_CFG, data)
if err != nil {
return
}
} else { // NORMAL USE
// Configure accelerometer
data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate) | uint8(d.accelBandWidth)
err = d.bus.WriteRegister(uint8(d.Address), CTRL1_XL, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
if err != nil {
return
}
// Set ODR bit
err = d.bus.ReadRegister(uint8(d.Address), CTRL4_C, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
data[0] |= BW_SCAL_ODR_ENABLED
err = d.bus.WriteRegister(uint8(d.Address), CTRL4_C, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
// Configure gyroscope
data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL2_G, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
if err != nil {
return
}
@@ -151,7 +152,7 @@ func (d *Device) Configure(cfg Configuration) (err error) {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := d.buf[:1]
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x69
}
@@ -161,7 +162,7 @@ func (d *Device) Connected() bool {
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_XL, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_XL, data)
if err != nil {
return
}
@@ -186,7 +187,7 @@ func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_G, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
if err != nil {
return
}
@@ -210,7 +211,7 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.Address), OUT_TEMP_L, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
if err != nil {
return
}
@@ -223,7 +224,7 @@ func (d *Device) ReadTemperature() (t int32, err error) {
// ReadSteps returns the steps of the pedometer
func (d *Device) ReadSteps() (s int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.Address), STEP_COUNTER_L, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), STEP_COUNTER_L, data)
if err != nil {
return
}
+9 -8
View File
@@ -8,6 +8,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -87,26 +88,26 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Configure accelerometer
data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL1_XL, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
if err != nil {
return
}
// Set ODR bit
err = d.bus.ReadRegister(uint8(d.Address), CTRL4_C, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
data[0] |= BW_SCAL_ODR_ENABLED
err = d.bus.WriteRegister(uint8(d.Address), CTRL4_C, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
// Configure gyroscope
data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL2_G, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
if err != nil {
return
}
@@ -118,7 +119,7 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := d.buf[:1]
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x6A
}
@@ -128,7 +129,7 @@ func (d *Device) Connected() bool {
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_XL, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_XL, data)
if err != nil {
return
}
@@ -153,7 +154,7 @@ func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_G, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
if err != nil {
return
}
@@ -177,7 +178,7 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.Address), OUT_TEMP_L, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
if err != nil {
return
}
+7 -6
View File
@@ -8,6 +8,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -78,13 +79,13 @@ func (d *Device) Configure(cfg Configuration) (err error) {
data := d.buf[:1]
// Configure accelerometer
data[0] = uint8(cfg.AccelRange) | uint8(cfg.AccelSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL1_XL, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
if err != nil {
return
}
// Configure gyroscope
data[0] = uint8(cfg.GyroRange) | uint8(cfg.GyroSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL2_G, data)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
if err != nil {
return
}
@@ -96,7 +97,7 @@ func (d *Device) Configure(cfg Configuration) (err error) {
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := d.buf[:1]
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x6C
}
@@ -106,7 +107,7 @@ func (d *Device) Connected() bool {
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_A, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_A, data)
if err != nil {
return
}
@@ -122,7 +123,7 @@ func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_G, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
if err != nil {
return
}
@@ -135,7 +136,7 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.Address), OUT_TEMP_L, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
if err != nil {
return
}
+13 -12
View File
@@ -7,6 +7,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -61,8 +62,8 @@ func New(bus drivers.I2C) *Device {
// but "who am I" responses have unexpected values.
func (d *Device) Connected() bool {
data1, data2 := d.buf[:1], d.buf[1:2]
d.bus.ReadRegister(d.AccelAddress, WHO_AM_I, data1)
d.bus.ReadRegister(d.MagAddress, WHO_AM_I_M, data2)
legacy.ReadRegister(d.bus, d.AccelAddress, WHO_AM_I, data1)
legacy.ReadRegister(d.bus, d.MagAddress, WHO_AM_I_M, data2)
return data1[0] == 0x68 && data2[0] == 0x3D
}
@@ -72,7 +73,7 @@ func (d *Device) Connected() bool {
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_X_L_XL, data)
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_X_L_XL, data)
if err != nil {
return
}
@@ -88,7 +89,7 @@ func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_X_L_G, data)
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_X_L_G, data)
if err != nil {
return
}
@@ -102,7 +103,7 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// it in nT (nanotesla). 1 G (gauss) = 100_000 nT (nanotesla).
func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.MagAddress), OUT_X_L_M, data)
err = legacy.ReadRegister(d.bus, uint8(d.MagAddress), OUT_X_L_M, data)
if err != nil {
return
}
@@ -115,7 +116,7 @@ func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in Celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_TEMP_L, data)
err = legacy.ReadRegister(d.bus, uint8(d.AccelAddress), OUT_TEMP_L, data)
if err != nil {
return
}
@@ -171,7 +172,7 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Configure accelerometer
// Sample rate & measurement range
data[0] = uint8(cfg.AccelSampleRate)<<5 | uint8(cfg.AccelRange)<<3
err = d.bus.WriteRegister(d.AccelAddress, CTRL_REG6_XL, data)
err = legacy.WriteRegister(d.bus, d.AccelAddress, CTRL_REG6_XL, data)
if err != nil {
return
}
@@ -179,7 +180,7 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Configure gyroscope
// Sample rate & measurement range
data[0] = uint8(cfg.GyroSampleRate)<<5 | uint8(cfg.GyroRange)<<3
err = d.bus.WriteRegister(d.AccelAddress, CTRL_REG1_G, data)
err = legacy.WriteRegister(d.bus, d.AccelAddress, CTRL_REG1_G, data)
if err != nil {
return
}
@@ -190,14 +191,14 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// High-performance mode XY axis
// Sample rate
data[0] = 0b10000000 | 0b01000000 | uint8(cfg.MagSampleRate)<<2
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG1_M, data)
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG1_M, data)
if err != nil {
return
}
// Measurement range
data[0] = uint8(cfg.MagRange) << 5
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG2_M, data)
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG2_M, data)
if err != nil {
return
}
@@ -205,14 +206,14 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Continuous-conversion mode
// https://electronics.stackexchange.com/questions/237397/continuous-conversion-vs-single-conversion-mode
data[0] = 0b00000000
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG3_M, data)
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG3_M, data)
if err != nil {
return
}
// High-performance mode Z axis
data[0] = 0b00001000
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG4_M, data)
err = legacy.WriteRegister(d.bus, d.MagAddress, CTRL_REG4_M, data)
if err != nil {
return
}
+9 -6
View File
@@ -4,7 +4,10 @@
// Datasheet: https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf
package mag3110 // import "tinygo.org/x/drivers/mag3110"
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a MAG3110 device.
type Device struct {
@@ -24,22 +27,22 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0xC4
}
// Configure sets up the device for communication.
func (d Device) Configure() {
d.bus.WriteRegister(uint8(d.Address), CTRL_REG2, []uint8{0x80}) // Power down when not used
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_REG2, []uint8{0x80}) // Power down when not used
}
// ReadMagnetic reads the vectors of the magnetic field of the device and
// returns it.
func (d Device) ReadMagnetic() (x int16, y int16, z int16) {
d.bus.WriteRegister(uint8(d.Address), CTRL_REG1, []uint8{0x1a}) // Request a measurement
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_REG1, []uint8{0x1a}) // Request a measurement
data := make([]byte, 6)
d.bus.ReadRegister(uint8(d.Address), OUT_X_MSB, data)
legacy.ReadRegister(d.bus, uint8(d.Address), OUT_X_MSB, data)
x = int16((uint16(data[0]) << 8) | uint16(data[1]))
y = int16((uint16(data[2]) << 8) | uint16(data[3]))
z = int16((uint16(data[4]) << 8) | uint16(data[5]))
@@ -50,6 +53,6 @@ func (d Device) ReadMagnetic() (x int16, y int16, z int16) {
// celsius milli degrees (°C/1000).
func (d Device) ReadTemperature() (int32, error) {
data := make([]byte, 1)
d.bus.ReadRegister(uint8(d.Address), DIE_TEMP, data)
legacy.ReadRegister(d.bus, uint8(d.Address), DIE_TEMP, data)
return int32(data[0]) * 1000, nil
}
+7 -11
View File
@@ -8,6 +8,9 @@ package mcp23017
import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
const (
@@ -75,19 +78,12 @@ const (
// address pins).
var ErrInvalidHWAddress = errors.New("invalid hardware address")
// I2C represents an I2C bus. It is notably implemented by the
// machine.I2C type.
type I2C interface {
ReadRegister(addr uint8, r uint8, buf []byte) error
WriteRegister(addr uint8, r uint8, buf []byte) error
}
// New returns a new MCP23017 device at the given I2C address
// on the given bus.
// It returns ErrInvalidHWAddress if the address isn't possible for the device.
//
// By default all pins are configured as inputs.
func NewI2C(bus I2C, address uint8) (*Device, error) {
func NewI2C(bus drivers.I2C, address uint8) (*Device, error) {
if address&hwAddressMask != hwAddress {
return nil, ErrInvalidHWAddress
}
@@ -115,7 +111,7 @@ type Device struct {
// bus holds the reference the I2C bus that the device lives on.
// It's an interface so that we can write tests for it.
bus I2C
bus drivers.I2C
addr uint8
// pins caches the most recent pin values that have been set.
// This enables us to change individual pin values without
@@ -259,7 +255,7 @@ func (d *Device) writeRegisterAB(r register, val Pins) error {
// and the fact that registers alternate between A and B
// to write both ports in a single operation.
buf := [2]byte{uint8(val), uint8(val >> 8)}
return d.bus.WriteRegister(d.addr, uint8(r&^portB), buf[:])
return legacy.WriteRegister(d.bus, d.addr, uint8(r&^portB), buf[:])
}
func (d *Device) readRegisterAB(r register) (Pins, error) {
@@ -267,7 +263,7 @@ func (d *Device) readRegisterAB(r register) (Pins, error) {
// and the fact that registers alternate between A and B
// to read both ports in a single operation.
var buf [2]byte
if err := d.bus.ReadRegister(d.addr, uint8(r), buf[:]); err != nil {
if err := legacy.ReadRegister(d.bus, d.addr, uint8(r), buf[:]); err != nil {
return Pins(0), err
}
return Pins(buf[0]) | (Pins(buf[1]) << 8), nil
+3 -1
View File
@@ -1,5 +1,7 @@
package mcp23017
import "tinygo.org/x/drivers"
// All is a convenience value that represents all pins high (or all mask bits one).
var All = PinSlice{0xffff}
@@ -12,7 +14,7 @@ type Devices []*Device
// NewI2CDevices returns a Devices slice holding the Device values
// for all the given addresses on the given bus.
// When more than one bus is in use, create the slice yourself.
func NewI2CDevices(bus I2C, addrs ...uint8) (Devices, error) {
func NewI2CDevices(bus drivers.I2C, addrs ...uint8) (Devices, error) {
devs := make(Devices, len(addrs))
for i, addr := range addrs {
dev, err := NewI2C(bus, addr)
+9 -6
View File
@@ -5,7 +5,10 @@
// https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf
package mma8653 // import "tinygo.org/x/drivers/mma8653"
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a MMA8653 device.
type Device struct {
@@ -26,27 +29,27 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x5A
}
// Configure sets up the device for communication.
func (d *Device) Configure(speed DataRate, sensitivity Sensitivity) error {
// Set mode to STANDBY to be able to change the sensitivity.
err := d.bus.WriteRegister(uint8(d.Address), CTRL_REG1, []uint8{0})
err := legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_REG1, []uint8{0})
if err != nil {
return err
}
// Set sensitivity (2G, 4G, 8G).
err = d.bus.WriteRegister(uint8(d.Address), XYZ_DATA_CFG, []uint8{uint8(sensitivity)})
err = legacy.WriteRegister(d.bus, uint8(d.Address), XYZ_DATA_CFG, []uint8{uint8(sensitivity)})
if err != nil {
return err
}
d.sensitivity = sensitivity
// Set mode to ACTIVE and set the data rate.
err = d.bus.WriteRegister(uint8(d.Address), CTRL_REG1, []uint8{(uint8(speed) << 3) | 1})
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_REG1, []uint8{(uint8(speed) << 3) | 1})
if err != nil {
return err
}
@@ -59,7 +62,7 @@ func (d *Device) Configure(speed DataRate, sensitivity Sensitivity) error {
// -1000000.
func (d Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
data := make([]byte, 6)
err = d.bus.ReadRegister(uint8(d.Address), OUT_X_MSB, data)
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_X_MSB, data)
shift := uint32(8)
switch d.sensitivity {
case Sensitivity4G:
+10 -7
View File
@@ -6,7 +6,10 @@
// https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
package mpu6050 // import "tinygo.org/x/drivers/mpu6050"
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a MPU6050 device.
type Device struct {
@@ -26,7 +29,7 @@ func New(bus drivers.I2C) Device {
// It does a "who am I" request and checks the response.
func (d Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x68
}
@@ -41,7 +44,7 @@ func (d Device) Configure() error {
// -1000000.
func (d Device) ReadAcceleration() (x int32, y int32, z int32) {
data := make([]byte, 6)
d.bus.ReadRegister(uint8(d.Address), ACCEL_XOUT_H, data)
legacy.ReadRegister(d.bus, uint8(d.Address), ACCEL_XOUT_H, data)
// Now do two things:
// 1. merge the two values to a 16-bit number (and cast to a 32-bit integer)
// 2. scale the value to bring it in the -1000000..1000000 range.
@@ -62,7 +65,7 @@ func (d Device) ReadAcceleration() (x int32, y int32, z int32) {
// you would get a value close to 360000000.
func (d Device) ReadRotation() (x int32, y int32, z int32) {
data := make([]byte, 6)
d.bus.ReadRegister(uint8(d.Address), GYRO_XOUT_H, data)
legacy.ReadRegister(d.bus, uint8(d.Address), GYRO_XOUT_H, data)
// First the value is converted from a pair of bytes to a signed 16-bit
// value and then to a signed 32-bit value to avoid integer overflow.
// Then the value is scaled to µ°/s (micro-degrees per second).
@@ -81,15 +84,15 @@ func (d Device) ReadRotation() (x int32, y int32, z int32) {
// SetClockSource allows the user to configure the clock source.
func (d Device) SetClockSource(source uint8) error {
return d.bus.WriteRegister(uint8(d.Address), PWR_MGMT_1, []uint8{source})
return legacy.WriteRegister(d.bus, uint8(d.Address), PWR_MGMT_1, []uint8{source})
}
// SetFullScaleGyroRange allows the user to configure the scale range for the gyroscope.
func (d Device) SetFullScaleGyroRange(rng uint8) error {
return d.bus.WriteRegister(uint8(d.Address), GYRO_CONFIG, []uint8{rng})
return legacy.WriteRegister(d.bus, uint8(d.Address), GYRO_CONFIG, []uint8{rng})
}
// SetFullScaleAccelRange allows the user to configure the scale range for the accelerometer.
func (d Device) SetFullScaleAccelRange(rng uint8) error {
return d.bus.WriteRegister(uint8(d.Address), ACCEL_CONFIG, []uint8{rng})
return legacy.WriteRegister(d.bus, uint8(d.Address), ACCEL_CONFIG, []uint8{rng})
}
+99
View File
@@ -0,0 +1,99 @@
// Package mpu9150 provides a driver for the MPU9150 accelerometer and gyroscope
// made by InvenSense.
//
// Datasheets:
// https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-9150-Datasheet.pdf
// https://inertialelements.com/documents/resources_page/MPU9150-register-manual.pdf
package mpu9150
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps an I2C connection to a MPU9150 device.
type Device struct {
bus drivers.I2C
Address uint16
}
// New creates a new MPU9150 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, Address}
}
// Connected returns whether a MPU9150 has been found.
// It does a "who am I" request and checks the response.
func (d Device) Connected() bool {
data := []byte{0}
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x68 // 4.32 Register 117 Who Am I (MPU-9150 Register Map and Descriptions)
}
// Configure sets up the device for communication.
func (d Device) Configure() error {
return d.SetClockSource(CLOCK_INTERNAL)
}
// 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(accel_axis byte) (x int32, y int32, z int32) {
data := make([]byte, 6)
legacy.ReadRegister(d.bus, uint8(d.Address), accel_axis, data)
// Now do two things:
// 1. merge the two values to a 16-bit number (and cast to a 32-bit integer)
// 2. scale the value to bring it in the -1000000..1000000 range.
// This is done with a trick. What we do here is essentially multiply by
// 1000000 and divide by 16384 to get the original scale, but to avoid
// overflow we do it at 1/64 of the value:
// 1000000 / 64 = 15625
// 16384 / 64 = 256
x = int32(int16((uint16(data[0])<<8)|uint16(data[1]))) * 15625 / 256
y = int32(int16((uint16(data[2])<<8)|uint16(data[3]))) * 15625 / 256
z = int32(int16((uint16(data[4])<<8)|uint16(data[5]))) * 15625 / 256
return
}
// ReadRotation reads the current rotation from the device and returns it in
// µ°/s (micro-degrees/sec). This means that if you were to do a complete
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d Device) ReadRotation(gyro_axis byte) (x int32, y int32, z int32) {
data := make([]byte, 6)
legacy.ReadRegister(d.bus, uint8(d.Address), gyro_axis, data)
// First the value is converted from a pair of bytes to a signed 16-bit
// value and then to a signed 32-bit value to avoid integer overflow.
// Then the value is scaled to µ°/s (micro-degrees per second).
// This is done in the following steps:
// 1. Multiply by 250 * 1000_000
// 2. Divide by 32768
// The following calculation (x * 15625 / 2048 * 1000) is essentially the
// same but avoids overflow. First both operations are divided by 16 leading
// to multiply by 15625000 and divide by 2048, and then part of the multiply
// is done after the divide instead of before.
x = int32(int16((uint16(data[0])<<8)|uint16(data[1]))) * 15625 / 2048 * 1000
y = int32(int16((uint16(data[2])<<8)|uint16(data[3]))) * 15625 / 2048 * 1000
z = int32(int16((uint16(data[4])<<8)|uint16(data[5]))) * 15625 / 2048 * 1000
return
}
// SetClockSource allows the user to configure the clock source.
func (d Device) SetClockSource(source uint8) error {
return legacy.WriteRegister(d.bus, uint8(d.Address), PWR_MGMT_1, []uint8{source})
}
// SetFullScaleGyroRange allows the user to configure the scale range for the gyroscope.
func (d Device) SetFullScaleGyroRange(rng uint8) error {
return legacy.WriteRegister(d.bus, uint8(d.Address), GYRO_CONFIG, []uint8{rng})
}
// SetFullScaleAccelRange allows the user to configure the scale range for the accelerometer.
func (d Device) SetFullScaleAccelRange(rng uint8) error {
return legacy.WriteRegister(d.bus, uint8(d.Address), ACCEL_CONFIG, []uint8{rng})
}
+131
View File
@@ -0,0 +1,131 @@
package mpu9150
// Constants/addresses used for I2C.
// The I2C address which this device listens to.
const Address = 0x68
// Registers. Names, addresses and comments copied from the datasheet.
const (
// Self test registers
SELF_TEST_X = 0x0D
SELF_TEST_Y = 0x0E
SELF_TEST_Z = 0x0F
SELF_TEST_A = 0x10
SMPLRT_DIV = 0x19 // Sample rate divider
CONFIG = 0x1A // Configuration
GYRO_CONFIG = 0x1B // Gyroscope configuration
ACCEL_CONFIG = 0x1C // Accelerometer configuration
FIFO_EN = 0x23 // FIFO enable
// I2C pass-through configuration
I2C_MST_CTRL = 0x24
I2C_SLV0_ADDR = 0x25
I2C_SLV0_REG = 0x26
I2C_SLV0_CTRL = 0x27
I2C_SLV1_ADDR = 0x28
I2C_SLV1_REG = 0x29
I2C_SLV1_CTRL = 0x2A
I2C_SLV2_ADDR = 0x2B
I2C_SLV2_REG = 0x2C
I2C_SLV2_CTRL = 0x2D
I2C_SLV3_ADDR = 0x2E
I2C_SLV3_REG = 0x2F
I2C_SLV3_CTRL = 0x30
I2C_SLV4_ADDR = 0x31
I2C_SLV4_REG = 0x32
I2C_SLV4_DO = 0x33
I2C_SLV4_CTRL = 0x34
I2C_SLV4_DI = 0x35
I2C_MST_STATUS = 0x36
// Interrupt configuration
INT_PIN_CFG = 0x37 // Interrupt pin/bypass enable configuration
INT_ENABLE = 0x38 // Interrupt enable
INT_STATUS = 0x3A // Interrupt status
// Accelerometer measurements
ACCEL_XOUT_H = 0x3B
ACCEL_XOUT_L = 0x3C
ACCEL_YOUT_H = 0x3D
ACCEL_YOUT_L = 0x3E
ACCEL_ZOUT_H = 0x3F
ACCEL_ZOUT_L = 0x40
// Temperature measurement
TEMP_OUT_H = 0x41
TEMP_OUT_L = 0x42
// Gyroscope measurements
GYRO_XOUT_H = 0x43
GYRO_XOUT_L = 0x44
GYRO_YOUT_H = 0x45
GYRO_YOUT_L = 0x46
GYRO_ZOUT_H = 0x47
GYRO_ZOUT_L = 0x48
// External sensor data
EXT_SENS_DATA_00 = 0x49
EXT_SENS_DATA_01 = 0x4A
EXT_SENS_DATA_02 = 0x4B
EXT_SENS_DATA_03 = 0x4C
EXT_SENS_DATA_04 = 0x4D
EXT_SENS_DATA_05 = 0x4E
EXT_SENS_DATA_06 = 0x4F
EXT_SENS_DATA_07 = 0x50
EXT_SENS_DATA_08 = 0x51
EXT_SENS_DATA_09 = 0x52
EXT_SENS_DATA_10 = 0x53
EXT_SENS_DATA_11 = 0x54
EXT_SENS_DATA_12 = 0x55
EXT_SENS_DATA_13 = 0x56
EXT_SENS_DATA_14 = 0x57
EXT_SENS_DATA_15 = 0x58
EXT_SENS_DATA_16 = 0x59
EXT_SENS_DATA_17 = 0x5A
EXT_SENS_DATA_18 = 0x5B
EXT_SENS_DATA_19 = 0x5C
EXT_SENS_DATA_20 = 0x5D
EXT_SENS_DATA_21 = 0x5E
EXT_SENS_DATA_22 = 0x5F
EXT_SENS_DATA_23 = 0x60
// I2C peripheral data out
I2C_SLV0_DO = 0x63
I2C_SLV1_DO = 0x64
I2C_SLV2_DO = 0x65
I2C_SLV3_DO = 0x66
I2C_MST_DELAY_CTRL = 0x67
SIGNAL_PATH_RESET = 0x68
USER_CTRL = 0x6A // User control
PWR_MGMT_1 = 0x6B // Power Management 1
PWR_MGMT_2 = 0x6C // Power Management 2
FIFO_COUNTH = 0x72 // FIFO count registers (high bits)
FIFO_COUNTL = 0x73 // FIFO count registers (low bits)
FIFO_R_W = 0x74 // FIFO read/write
WHO_AM_I = 0x75 // Who am I
// Clock settings (4.28 Register 107 Power Management 1)
CLOCK_INTERNAL = 0x00
CLOCK_PLL_XGYRO = 0x01
CLOCK_PLL_YGYRO = 0x02
CLOCK_PLL_ZGYRO = 0x03
CLOCK_PLL_EXTERNAL_32_768_KZ = 0x04
CLOCK_PLL_EXTERNAL_19_2_MHZ = 0x05
CLOCK_RESERVED = 0x06
CLOCK_STOP = 0x07
// Gyroscope settings (4.4 Register 27 Gyroscope Configuration)
FS_RANGE_250 = 0x00
FS_RANGE_500 = 0x01
FS_RANGE_1000 = 0x02
FS_RANGE_2000 = 0x03
// Accelerometer settings (4.5 Register 28 Accelerometer Configuration)
AFS_RANGE_2G = 0x00
AFS_RANGE_4G = 0x01
AFS_RANGE_8G = 0x02
AFS_RANGE_16G = 0x03
)
+288
View File
@@ -0,0 +1,288 @@
package ndir
import (
"errors"
"fmt"
"runtime"
"time"
"tinygo.org/x/drivers"
)
// Addr returns the I2C address given the solder pad configuration on the Sandbox Electronics i2c/uart converter.
// When the resistor is connected between the left and middle pads the bit is said to be set
// and a0 or a1 should be passed in as true.
func Addr(a0, a1 bool) uint8 {
return 0b1001000 | b2u8(a0) | b2u8(a1)<<2
}
func b2u8(b bool) uint8 {
if b {
return 1
}
return 0
}
// See https://github.com/SandboxElectronics/NDIR/blob/master/NDIR_I2C/NDIR_I2C.cpp
// General Registers
const (
addrRHR = 0x00
addrTHR = 0x00
addrIER = 0x01
addrFCR = 0x02
addrIIR = 0x02
addrLCR = 0x03
addrMCR = 0x04
addrLSR = 0x05
addrMSR = 0x06
addrSPR = 0x07
addrTCR = 0x06
addrTLR = 0x07
addrTXLVL = 0x08
addrRXLVL = 0x09
addrIODIR = 0x0A
addrIOSTATE = 0x0B
addrIOINTENA = 0x0C
addrIOCONTROL = 0x0E // This addr fails on write of 0x08?
addrEFCR = 0x0F
)
// Special registers
const (
addrDLL = 0x00
addrDLH = 1
)
const (
shortTxCooldown = time.Millisecond
longTxCooldown = 10 * time.Millisecond
rxTimeout = 100 * time.Millisecond
)
var (
cmd_readCO2 = [...]byte{0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}
cmd_measure = [...]byte{0xFF, 0x01, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63}
cmd_calibrateZero = [...]byte{0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78}
cmd_enableAutoCalibration = [...]byte{0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6}
cmd_disableAutoCalibration = [...]byte{0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86}
)
// DevI2C is a handle to a MH-Z16 NDIR CO2 Sensor using the I2C interface.
type DevI2C struct {
bus drivers.I2C
addr uint8
nextAvail time.Time
initTime time.Time
lastMeasurement int32
}
// NewDevI2C returns a new NDIR device ready for use. It performs no I/O.
func NewDevI2C(bus drivers.I2C, addr uint8) *DevI2C {
return &DevI2C{
bus: bus,
addr: addr,
lastMeasurement: -1,
}
}
// PPM returns the CO2 parts per million read in the last Update call.
func (d *DevI2C) PPMCO2() int32 {
return d.lastMeasurement
}
var errInitWait = errors.New("ndir: must wait 12 seconds after init before reading concentration")
// Update reads the CO2 concentration from the NDIR and stores it ready for the
// PPM() method.
func (d *DevI2C) Update(which drivers.Measurement) (err error) {
if which&drivers.Concentration == 0 {
return nil // NDIR only measures concentration, so nothing to do here.
}
if time.Since(d.initTime) < 12*time.Second {
// Wait 12 seconds before performing first read.
return nil
}
err = d.writeRegister(addrFCR, 0x07)
if err != nil {
return err
}
err = d.send(cmd_measure[:])
if err != nil {
return fmt.Errorf("sending cmd_measure: %w", err)
}
time.Sleep(11 * time.Millisecond)
var buf [9]byte
buf, err = d.receive()
if err != nil {
return fmt.Errorf("receiving during measure: %w", err)
}
if buf[0] != 0xff && buf[1] != 0x9c {
return fmt.Errorf("buffer rx bad values: %q", string(buf[:]))
}
var sum uint16
for i := 0; i < len(buf); i++ {
sum += uint16(buf[i])
}
mod := sum % 256
if mod != 0xff {
return fmt.Errorf("ndir checksum modulus got %#x, expected 0xff", mod)
}
ppm := uint32(buf[2])<<24 | uint32(buf[3])<<16 | uint32(buf[4])<<8 | uint32(buf[5])
d.lastMeasurement = int32(ppm)
return nil
}
func (d *DevI2C) Init() (err error) {
// AddrIOCONTROL write is always NACKed so ignore
// error here.
d.writeRegister(addrIOCONTROL, 0x08)
err = d.writeRegister(addrFCR, 0x07)
if err != nil {
return err
}
err = d.writeRegister(addrLCR, 0x83)
if err != nil {
return err
}
err = d.writeRegister(addrDLL, 0x60)
if err != nil {
return err
}
err = d.writeRegister(addrDLH, 0x00)
if err != nil {
return err
}
err = d.writeRegister(addrLCR, 0x03)
if err != nil {
return err
}
d.initTime = time.Now()
return nil
}
// CalibrateZero calibrates the NDIR to around 412ppm.
func (d *DevI2C) CalibrateZero() error {
return d.enactCommand(cmd_calibrateZero[:])
}
// SetAutoCalibration can enable or disable the NDIR's auto calibration mode.
func (d *DevI2C) SetAutoCalibration(enable bool) (err error) {
if enable {
err = d.enactCommand(cmd_enableAutoCalibration[:])
} else {
err = d.enactCommand(cmd_disableAutoCalibration[:])
}
return err
}
func (d *DevI2C) send(cmd []byte) error {
txlvl, err := d.ReadRegister(addrTXLVL)
if err != nil {
return err
}
if int(txlvl) < len(cmd) {
return fmt.Errorf("txlvl=%d less than length of command %d", txlvl, len(cmd))
}
return d.tx(append([]byte{addrTHR}, cmd...), nil)
}
func (d *DevI2C) receive() (cmd [9]byte, err error) {
start := time.Now()
n := uint8(9)
for n > 0 {
if time.Since(start) > rxTimeout {
return [9]byte{}, errors.New("NDIR rx timeout")
}
rxlvl, err := d.ReadRegister(addrRXLVL)
if err != nil {
return [9]byte{}, err
}
if rxlvl > n {
rxlvl = n
}
ptr := 9 - n
err = d.tx([]byte{addrRHR << 3}, cmd[ptr:ptr+rxlvl])
n -= rxlvl
if err != nil {
return [9]byte{}, err
}
}
return cmd, nil
}
func (d *DevI2C) enactCommand(cmd []byte) error {
if len(cmd) > 31 {
return errors.New("ndir: command too long")
}
// Most commands always start with the same FCR write here.
err := d.writeRegister(addrFCR, 0x07)
if err != nil {
return err
}
time.Sleep(longTxCooldown)
// C++ send method begins here.
got, err := d.ReadRegister(addrTXLVL)
if err != nil {
return err
}
if got < uint8(len(cmd)) {
return fmt.Errorf("ndir: txlevel=%d too low for command of length %d", got, len(cmd))
}
var buf [32]byte
buf[0] = addrTHR
n := 1 + copy(buf[1:], cmd)
err = d.tx(buf[:n], nil)
if err != nil {
return err
}
d.nextAvail.Add(longTxCooldown) // add some extra time.
return nil
}
func (d *DevI2C) writeRegister(addr, val uint8) (err error) {
return d.WriteRegisters(addr, []byte{val})
}
func (d *DevI2C) WriteRegisters(addr uint8, vals []byte) (err error) {
var buf [32]byte
if len(vals) > 31 {
return errors.New("can only write up to 31 bytes")
}
buf[0] = addr << 3
n := copy(buf[1:], vals)
err = d.tx(buf[:n+1], nil)
if err != nil {
err = fmt.Errorf("NDIR write %#x (%d) to %#x: %w", buf[1], len(vals), buf[0], err)
}
return err
}
func (d *DevI2C) ReadRegister(addr uint8) (uint8, error) {
var buf [2]byte
buf[0] = addr << 3
err := d.tx(buf[:1], buf[1:2])
if err != nil {
err = fmt.Errorf("NDIR read from %#x: %w", buf[0], err)
}
return buf[1], err
}
func (d *DevI2C) tx(w, r []byte) error {
wait := time.Until(d.nextAvail)
if wait > 0 {
// Try yielding process first, maybe there's a short time to wait and a schedule call is enough delay.
runtime.Gosched()
wait = time.Until(d.nextAvail)
if wait > 0 {
// If yielding did not work then perform sleep
time.Sleep(wait)
}
}
err := d.bus.Tx(uint16(d.addr), w, r)
d.nextAvail = time.Now().Add(shortTxCooldown)
return err
}
+4 -2
View File
@@ -1,9 +1,11 @@
package pca9685
import "tinygo.org/x/drivers/internal/legacy"
func (d *Dev) readReg(reg uint8, data []byte) error {
return d.bus.ReadRegister(d.addr, reg, data)
return legacy.ReadRegister(d.bus, d.addr, reg, data)
}
func (d *Dev) writeReg(reg uint8, data []byte) error {
return d.bus.WriteRegister(d.addr, reg, data)
return legacy.WriteRegister(d.bus, d.addr, reg, data)
}
+6 -3
View File
@@ -5,7 +5,10 @@
// https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf
package qmi8656c
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps the I2C connection to the QMIC8658 sensor
type Device struct {
@@ -179,12 +182,12 @@ func (d *Device) ReadTemperature() (int32, error) {
// Convenience method to read the register and avoid repetition.
func (d *Device) ReadRegister(reg uint8, buf []byte) error {
return d.bus.ReadRegister(uint8(d.Address), reg, buf)
return legacy.ReadRegister(d.bus, uint8(d.Address), reg, buf)
}
// Convenience method to write the register and avoid repetition.
func (d *Device) WriteRegister(reg uint8, v uint16) error {
data := []byte{byte(v)}
err := d.bus.WriteRegister(uint8(d.Address), reg, data)
err := legacy.WriteRegister(d.bus, uint8(d.Address), reg, data)
return err
}
+2
View File
@@ -16,6 +16,8 @@ const (
MagneticField
Luminosity
Time
// Gas or liquid concentration, usually measured in ppm (parts per million).
Concentration
// Add Measurements above AllMeasurements.
// AllMeasurements is the OR of all Measurement values. It ensures all measurements are done.
+7 -1
View File
@@ -4,6 +4,7 @@
# avoid a race condition between writing the output and reading the result to
# get an md5sum).
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adt7410/main.go
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adxl345/main.go
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/amg88xx
@@ -13,6 +14,7 @@ tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bh1750/main.go
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/blinkm/main.go
tinygo build -size short -o ./build/test.hex -target=pinetime ./examples/bma42x/main.go
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmi160/main.go
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp180/main.go
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp280/main.go
@@ -126,4 +128,8 @@ tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/d
tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/lora/lorawan/atcmd/
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/as560x/main.go
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu6886/main.go
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ttp229/main.go
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ttp229/main.go
tinygo build -size short -o ./build/test.hex -target=pico ./examples/ndir/main_ndir.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ndir/main_ndir.go
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ndir/main_ndir.go
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/main.go
+25 -17
View File
@@ -10,6 +10,7 @@ import (
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device wraps I2C or SPI connection.
@@ -44,9 +45,9 @@ type SPIBus struct {
}
type Buser interface {
configure()
tx(data []byte, isCommand bool)
setAddress(address uint16)
configure() error
tx(data []byte, isCommand bool) error
setAddress(address uint16) error
}
type VccMode uint8
@@ -192,8 +193,7 @@ func (d *Device) Display() error {
d.Command(uint8(d.height/8) - 1)
}
d.Tx(d.buffer, false)
return nil
return d.Tx(d.buffer, false)
}
// SetPixel enables or disables a pixel in the buffer
@@ -243,21 +243,23 @@ func (d *Device) Command(command uint8) {
}
// setAddress sets the address to the I2C bus
func (b *I2CBus) setAddress(address uint16) {
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) {
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() {}
func (b *I2CBus) configure() error { return nil }
// configure configures some pins with the SPI bus
func (b *SPIBus) configure() {
func (b *SPIBus) configure() error {
b.csPin.Low()
b.dcPin.Low()
b.resetPin.Low()
@@ -267,31 +269,35 @@ func (b *SPIBus) configure() {
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) {
d.bus.tx(data, isCommand)
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) {
func (b *I2CBus) tx(data []byte, isCommand bool) error {
if isCommand {
b.wire.WriteRegister(uint8(b.Address), 0x00, data)
return legacy.WriteRegister(b.wire, uint8(b.Address), 0x00, data)
} else {
b.wire.WriteRegister(uint8(b.Address), 0x40, data)
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) {
func (b *SPIBus) tx(data []byte, isCommand bool) error {
var err error
if isCommand {
b.csPin.High()
time.Sleep(1 * time.Millisecond)
b.dcPin.Low()
b.csPin.Low()
b.wire.Tx(data, nil)
err = b.wire.Tx(data, nil)
b.csPin.High()
} else {
b.csPin.High()
@@ -299,9 +305,11 @@ func (b *SPIBus) tx(data []byte, isCommand bool) {
b.dcPin.High()
b.csPin.Low()
b.wire.Tx(data, nil)
err = b.wire.Tx(data, nil)
b.csPin.High()
}
return err
}
// Size returns the current size of the display.
+2
View File
@@ -235,6 +235,8 @@ func (d *Device) setWindow(x, y, w, h int16) {
// SetScrollWindow sets an area to scroll with fixed top and bottom parts of the display
func (d *Device) SetScrollArea(topFixedArea, bottomFixedArea int16) {
// TODO: this code is broken, see the st7789 and ili9341 implementations for
// how to do this correctly.
d.Command(VSCRDEF)
d.Tx([]uint8{
uint8(topFixedArea >> 8), uint8(topFixedArea),
+28 -10
View File
@@ -474,20 +474,20 @@ func (d *Device) setRotation(rotation Rotation) error {
madctl := uint8(0)
switch rotation % 4 {
case drivers.Rotation0:
madctl = MADCTL_MX | MADCTL_MY
d.rowOffset = d.rowOffsetCfg
d.columnOffset = d.columnOffsetCfg
case drivers.Rotation90:
madctl = MADCTL_MY | MADCTL_MV
d.rowOffset = d.columnOffsetCfg
d.columnOffset = d.rowOffsetCfg
case drivers.Rotation180:
d.rowOffset = 0
d.columnOffset = 0
case drivers.Rotation270:
case drivers.Rotation90:
madctl = MADCTL_MX | MADCTL_MV
d.rowOffset = 0
d.columnOffset = 0
case drivers.Rotation180:
madctl = MADCTL_MX | MADCTL_MY
d.rowOffset = d.rowOffsetCfg
d.columnOffset = d.columnOffsetCfg
case drivers.Rotation270:
madctl = MADCTL_MY | MADCTL_MV
d.rowOffset = d.columnOffsetCfg
d.columnOffset = d.rowOffsetCfg
}
if d.isBGR {
madctl |= MADCTL_BGR
@@ -554,9 +554,22 @@ func (d *Device) IsBGR(bgr bool) {
// SetScrollArea sets an area to scroll with fixed top and bottom parts of the display.
func (d *Device) SetScrollArea(topFixedArea, bottomFixedArea int16) {
if d.height < 320 {
// The screen doesn't use the full 320 pixel height.
// Enlarge the bottom fixed area to fill the 320 pixel height, so that
// bottomFixedArea starts from the visible bottom of the screen.
topFixedArea += d.rowOffset
bottomFixedArea += (320 - d.height) - d.rowOffset
}
if d.rotation == drivers.Rotation180 {
// The screen is rotated by 180°, so we have to switch the top and
// bottom fixed area.
topFixedArea, bottomFixedArea = bottomFixedArea, topFixedArea
}
verticalScrollArea := 320 - topFixedArea - bottomFixedArea
copy(d.buf[:6], []uint8{
uint8(topFixedArea >> 8), uint8(topFixedArea),
uint8(d.height - topFixedArea - bottomFixedArea>>8), uint8(d.height - topFixedArea - bottomFixedArea),
uint8(verticalScrollArea >> 8), uint8(verticalScrollArea),
uint8(bottomFixedArea >> 8), uint8(bottomFixedArea)})
d.startWrite()
d.sendCommand(VSCRDEF, d.buf[:6])
@@ -565,6 +578,11 @@ func (d *Device) SetScrollArea(topFixedArea, bottomFixedArea int16) {
// SetScroll sets the vertical scroll address of the display.
func (d *Device) SetScroll(line int16) {
if d.rotation == drivers.Rotation180 {
// The screen is rotated by 180°, so we have to invert the scroll line
// (taking care of the RowOffset).
line = (319 - d.rowOffset) - line
}
d.buf[0] = uint8(line >> 8)
d.buf[1] = uint8(line)
d.startWrite()
+2 -2
View File
@@ -5,10 +5,10 @@ const MaxRegisters = 255
type I2CDevice interface {
// ReadRegister implements I2C.ReadRegister.
ReadRegister(r uint8, buf []byte) error
readRegister(r uint8, buf []byte) error
// WriteRegister implements I2C.WriteRegister.
WriteRegister(r uint8, buf []byte) error
writeRegister(r uint8, buf []byte) error
// Tx implements I2C.Tx
Tx(w, r []byte) error
+14 -4
View File
@@ -33,7 +33,7 @@ func (d *I2CDevice16) Addr() uint8 {
}
// ReadRegister implements I2C.ReadRegister.
func (d *I2CDevice16) ReadRegister(r uint8, buf []byte) error {
func (d *I2CDevice16) readRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
@@ -54,7 +54,7 @@ func (d *I2CDevice16) ReadRegister(r uint8, buf []byte) error {
}
// WriteRegister implements I2C.WriteRegister.
func (d *I2CDevice16) WriteRegister(r uint8, buf []byte) error {
func (d *I2CDevice16) writeRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
@@ -75,6 +75,16 @@ func (d *I2CDevice16) WriteRegister(r uint8, buf []byte) error {
// Tx implements I2C.Tx.
func (bus *I2CDevice16) Tx(w, r []byte) error {
// TODO: implement this
return nil
switch len(w) {
case 0:
bus.c.Fatalf("i2c mock: need a write byte")
return nil
case 1:
return bus.readRegister(w[0], r)
default:
if len(r) > 0 || len(w) == 1 {
bus.c.Fatalf("i2c mock: unsupported lengths in Tx(%d, %d)", len(w), len(r))
}
return bus.writeRegister(w[0], w[1:])
}
}
+17 -4
View File
@@ -34,17 +34,20 @@ func (d *I2CDevice8) Addr() uint8 {
}
// ReadRegister implements I2C.ReadRegister.
func (d *I2CDevice8) ReadRegister(r uint8, buf []byte) error {
func (d *I2CDevice8) readRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
if len(buf) == 0 {
d.c.Fatalf("no register buffer to read into")
}
d.assertRegisterRange(r, buf)
copy(buf, d.Registers[r:])
return nil
}
// WriteRegister implements I2C.WriteRegister.
func (d *I2CDevice8) WriteRegister(r uint8, buf []byte) error {
func (d *I2CDevice8) writeRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
@@ -55,8 +58,18 @@ func (d *I2CDevice8) WriteRegister(r uint8, buf []byte) error {
// Tx implements I2C.Tx.
func (bus *I2CDevice8) Tx(w, r []byte) error {
// TODO: implement this
return nil
switch len(w) {
case 0:
bus.c.Fatalf("i2c mock: need a write byte")
return nil
case 1:
return bus.readRegister(w[0], r)
default:
if len(r) > 0 || len(w) == 1 {
bus.c.Fatalf("i2c mock: unsupported lengths in Tx(%d, %d)", len(w), len(r))
}
return bus.writeRegister(w[0], w[1:])
}
}
// assertRegisterRange asserts that reading or writing the given
+2 -2
View File
@@ -50,7 +50,7 @@ func (d *I2CDeviceCmd) Addr() uint8 {
}
// ReadRegister implements I2C.ReadRegister.
func (d *I2CDeviceCmd) ReadRegister(r uint8, buf []byte) error {
func (d *I2CDeviceCmd) readRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
@@ -59,7 +59,7 @@ func (d *I2CDeviceCmd) ReadRegister(r uint8, buf []byte) error {
}
// WriteRegister implements I2C.WriteRegister.
func (d *I2CDeviceCmd) WriteRegister(r uint8, buf []byte) error {
func (d *I2CDeviceCmd) writeRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
+2 -2
View File
@@ -38,12 +38,12 @@ func (bus *I2CBus) NewDevice(addr uint8) *I2CDevice8 {
// ReadRegister implements I2C.ReadRegister.
func (bus *I2CBus) ReadRegister(addr uint8, r uint8, buf []byte) error {
return bus.FindDevice(addr).ReadRegister(r, buf)
return bus.FindDevice(addr).readRegister(r, buf)
}
// WriteRegister implements I2C.WriteRegister.
func (bus *I2CBus) WriteRegister(addr uint8, r uint8, buf []byte) error {
return bus.FindDevice(addr).WriteRegister(r, buf)
return bus.FindDevice(addr).writeRegister(r, buf)
}
// Tx implements I2C.Tx.
+6 -3
View File
@@ -4,7 +4,10 @@
package tmp102 // import "tinygo.org/x/drivers/tmp102"
import "tinygo.org/x/drivers"
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// Device holds the already configured I2C bus and the address of the sensor.
type Device struct {
@@ -36,7 +39,7 @@ func (d *Device) Configure(cfg Config) {
// Connected checks if the config register can be read and that the configuration is correct.
func (d *Device) Connected() bool {
configData := make([]byte, 2)
err := d.bus.ReadRegister(d.address, RegConfiguration, configData)
err := legacy.ReadRegister(d.bus, d.address, RegConfiguration, configData)
// Check the reset configuration values.
if err != nil || configData[0] != 0x60 || configData[1] != 0xA0 {
return false
@@ -50,7 +53,7 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
tmpData := make([]byte, 2)
err = d.bus.ReadRegister(d.address, RegTemperature, tmpData)
err = legacy.ReadRegister(d.bus, d.address, RegTemperature, tmpData)
if err != nil {
return