mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-02 05:57:47 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4f6fbcb52 | |||
| 7487c6b3a2 | |||
| d1553458f5 | |||
| 79d3609f76 | |||
| 00a9b9db77 | |||
| f68388702d |
@@ -1,3 +1,11 @@
|
||||
0.2.0
|
||||
---
|
||||
- **new devices**
|
||||
- AT24C32/64 2-wire serial EEPROM
|
||||
- BME280 humidity/pressure sensor
|
||||
- **bugfixes**
|
||||
- ws2812: better support for nrf52832
|
||||
|
||||
0.1.0
|
||||
---
|
||||
- **first release**
|
||||
|
||||
@@ -11,6 +11,7 @@ smoke-test:
|
||||
@mkdir -p build
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/adxl345/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/apa102/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/at24cx/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/bh1750/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/blinkm/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/bmp180/main.go
|
||||
@@ -41,5 +42,6 @@ smoke-test:
|
||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/waveshare-epd/epd2in13/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/waveshare-epd/epd2in13x/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/ws2812/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=trinket-m0 ./examples/bme280/main.go
|
||||
|
||||
test: clean fmt-check smoke-test
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# TinyGo Drivers
|
||||
|
||||
[](https://godoc.org/github.com/tinygo-org/drivers) [](https://circleci.com/gh/tinygo-org/drivers/tree/dev)
|
||||
[](https://godoc.org/tinygo.org/x/drivers) [](https://circleci.com/gh/tinygo-org/drivers/tree/dev)
|
||||
|
||||
|
||||
This package provides a collection of hardware drivers for devices that can be used together with [TinyGo](https://tinygo.org).
|
||||
@@ -56,8 +56,10 @@ func main() {
|
||||
|----------|-------------|
|
||||
| [ADXL345 accelerometer](http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf) | I2C |
|
||||
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
|
||||
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
|
||||
| [BH1750 ambient light sensor](https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf) | I2C |
|
||||
| [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C |
|
||||
| [BME280 humidity/pressure sensor](https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf) | I2C |
|
||||
| [BMP180 barometer](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) | I2C |
|
||||
| [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C |
|
||||
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Package at24cx provides a driver for the AT24C32/64/128/256/512 2-wire serial EEPROM
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf
|
||||
package at24cx // import "tinygo.org/x/drivers/at24cx"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a DS3231 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
Address uint16
|
||||
pageSize uint16
|
||||
currentRAMAddress uint16
|
||||
startRAMAddress uint16
|
||||
endRAMAddress uint16
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
PageSize uint16
|
||||
StartRAMAddress uint16
|
||||
EndRAMAddress uint16
|
||||
}
|
||||
|
||||
// New creates a new AT24C32/64 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication
|
||||
func (d *Device) Configure(cfg Config) {
|
||||
if cfg.PageSize == 0 {
|
||||
d.pageSize = 32
|
||||
} else {
|
||||
d.pageSize = cfg.PageSize
|
||||
}
|
||||
if cfg.EndRAMAddress == 0 {
|
||||
d.endRAMAddress = 4096
|
||||
} else {
|
||||
d.endRAMAddress = cfg.EndRAMAddress
|
||||
}
|
||||
d.startRAMAddress = cfg.StartRAMAddress
|
||||
}
|
||||
|
||||
// WriteByte writes a byte at the specified address
|
||||
func (d *Device) WriteByte(eepromAddress uint16, value uint8) error {
|
||||
address := []uint8{
|
||||
uint8((eepromAddress >> 8) & 0xFF),
|
||||
uint8(eepromAddress & 0xFF),
|
||||
value,
|
||||
}
|
||||
return d.bus.Tx(d.Address, address, nil)
|
||||
}
|
||||
|
||||
// ReadByte reads the byte at the specified address
|
||||
func (d *Device) ReadByte(eepromAddress uint16) (uint8, error) {
|
||||
address := []uint8{
|
||||
uint8(eepromAddress >> 8),
|
||||
uint8(eepromAddress & 0xFF),
|
||||
}
|
||||
data := make([]uint8, 1)
|
||||
err := d.bus.Tx(d.Address, address, data)
|
||||
return data[0], err
|
||||
}
|
||||
|
||||
// WriteAt writes a byte array at the specified address
|
||||
func (d *Device) WriteAt(data []byte, offset int64) (n int, err error) {
|
||||
return d.writeAt(data, uint16(offset))
|
||||
}
|
||||
|
||||
// writeAt writes a byte array at the specified address
|
||||
func (d *Device) writeAt(data []byte, offset uint16) (n int, err error) {
|
||||
values := make([]uint8, 32)
|
||||
dataLeft := uint16(len(data))
|
||||
d.currentRAMAddress = offset
|
||||
offset = 0
|
||||
var offsetPage uint16
|
||||
var chunkLength uint16
|
||||
for dataLeft > 0 {
|
||||
offsetPage = d.currentRAMAddress % d.pageSize
|
||||
if dataLeft < 30 { // The 32K/64K EEPROM is capable of 32-byte page writes and we're using 2 for the address
|
||||
chunkLength = dataLeft
|
||||
} else {
|
||||
chunkLength = 30
|
||||
}
|
||||
if (d.pageSize - offsetPage) < chunkLength {
|
||||
chunkLength = d.pageSize - offsetPage
|
||||
}
|
||||
for i := uint16(0); i < chunkLength; i++ {
|
||||
values[2+i] = data[offset+i]
|
||||
}
|
||||
values[0] = uint8(d.currentRAMAddress >> 8)
|
||||
values[1] = uint8(d.currentRAMAddress & 0xFF)
|
||||
err := d.bus.Tx(d.Address, values[:chunkLength+2], nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dataLeft -= chunkLength
|
||||
offset += chunkLength
|
||||
if d.endRAMAddress-chunkLength < d.currentRAMAddress {
|
||||
d.currentRAMAddress = d.startRAMAddress + (d.currentRAMAddress+uint16(len(data)))%d.endRAMAddress
|
||||
} else {
|
||||
d.currentRAMAddress += chunkLength
|
||||
}
|
||||
time.Sleep(2 * time.Millisecond) // writing again too soon will block the device
|
||||
}
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// ReadAt reads the bytes at the specified address
|
||||
func (d *Device) ReadAt(data []byte, offset int64) (n int, err error) {
|
||||
return d.readAt(data, uint16(offset))
|
||||
}
|
||||
|
||||
// readAt reads the bytes at the specified address
|
||||
func (d *Device) readAt(data []byte, offset uint16) (n int, err error) {
|
||||
address := []uint8{
|
||||
uint8((offset >> 8) & 0xFF),
|
||||
uint8(offset & 0xFF),
|
||||
}
|
||||
err = d.bus.Tx(d.Address, address, data)
|
||||
|
||||
if d.endRAMAddress-uint16(len(data)) < offset {
|
||||
d.currentRAMAddress = d.startRAMAddress + (offset+uint16(len(data)))%d.endRAMAddress
|
||||
} else {
|
||||
d.currentRAMAddress = offset + uint16(len(data))
|
||||
}
|
||||
return len(data), err
|
||||
}
|
||||
|
||||
// Seek sets the offset for the next Read or Write on SRAM to offset, interpreted
|
||||
// according to whence: 0 means relative to the origin of the SRAM, 1 means
|
||||
// relative to the current offset, and 2 means relative to the end.
|
||||
// returns new offset and error, if any
|
||||
func (d *Device) Seek(offset int64, whence int) (int64, error) {
|
||||
w := uint16(0)
|
||||
switch whence {
|
||||
case 0:
|
||||
w = d.startRAMAddress
|
||||
case 1:
|
||||
w = d.currentRAMAddress
|
||||
case 2:
|
||||
w = d.endRAMAddress
|
||||
default:
|
||||
return 0, errors.New("invalid whence")
|
||||
}
|
||||
d.currentRAMAddress = w + uint16(offset)
|
||||
return int64(d.currentRAMAddress), nil
|
||||
}
|
||||
|
||||
// Write writes len(data) bytes to SRAM
|
||||
// returns number of bytes written and error, if any
|
||||
func (d *Device) Write(data []byte) (n int, err error) {
|
||||
return d.writeAt(data, d.currentRAMAddress)
|
||||
}
|
||||
|
||||
// Read reads len(data) from SRAM
|
||||
// returns number of bytes written and error, if any
|
||||
func (d *Device) Read(data []uint8) (n int, err error) {
|
||||
return d.readAt(data, d.currentRAMAddress)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package at24cx
|
||||
|
||||
// The I2C address which this device listens to.
|
||||
const Address = 0x57
|
||||
@@ -0,0 +1,257 @@
|
||||
// Package bme280 provides a driver for the BME280 digital combined
|
||||
// humidity and pressure sensor by Bosch.
|
||||
//
|
||||
// Datasheet:
|
||||
// https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
|
||||
//
|
||||
package bme280
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"math"
|
||||
)
|
||||
|
||||
// calibrationCoefficients reads at startup and stores the calibration coefficients
|
||||
type calibrationCoefficients struct {
|
||||
t1 uint16
|
||||
t2 int16
|
||||
t3 int16
|
||||
p1 uint16
|
||||
p2 int16
|
||||
p3 int16
|
||||
p4 int16
|
||||
p5 int16
|
||||
p6 int16
|
||||
p7 int16
|
||||
p8 int16
|
||||
p9 int16
|
||||
h1 uint8
|
||||
h2 int16
|
||||
h3 uint8
|
||||
h4 int16
|
||||
h5 int16
|
||||
h6 int8
|
||||
}
|
||||
|
||||
// Device wraps an I2C connection to a BME280 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
Address uint16
|
||||
calibrationCoefficients calibrationCoefficients
|
||||
}
|
||||
|
||||
// New creates a new BME280 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication and
|
||||
// read the calibration coefficientes.
|
||||
func (d *Device) Configure() {
|
||||
|
||||
var data [24]byte
|
||||
err := d.bus.ReadRegister(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[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var h2lsb [7]byte
|
||||
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H2LSB, h2lsb[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.calibrationCoefficients.t1 = readUintLE(data[0], data[1])
|
||||
d.calibrationCoefficients.t2 = readIntLE(data[2], data[3])
|
||||
d.calibrationCoefficients.t3 = readIntLE(data[4], data[5])
|
||||
d.calibrationCoefficients.p1 = readUintLE(data[6], data[7])
|
||||
d.calibrationCoefficients.p2 = readIntLE(data[8], data[9])
|
||||
d.calibrationCoefficients.p3 = readIntLE(data[10], data[11])
|
||||
d.calibrationCoefficients.p4 = readIntLE(data[12], data[13])
|
||||
d.calibrationCoefficients.p5 = readIntLE(data[14], data[15])
|
||||
d.calibrationCoefficients.p6 = readIntLE(data[16], data[17])
|
||||
d.calibrationCoefficients.p7 = readIntLE(data[18], data[19])
|
||||
d.calibrationCoefficients.p8 = readIntLE(data[20], data[21])
|
||||
d.calibrationCoefficients.p9 = readIntLE(data[22], data[23])
|
||||
|
||||
d.calibrationCoefficients.h1 = h1[0]
|
||||
d.calibrationCoefficients.h2 = readIntLE(h2lsb[0], h2lsb[1])
|
||||
d.calibrationCoefficients.h3 = h2lsb[2]
|
||||
d.calibrationCoefficients.h6 = int8(h2lsb[6])
|
||||
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
|
||||
d.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
|
||||
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{0x3f})
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{0xB7})
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{0x00})
|
||||
|
||||
}
|
||||
|
||||
// Connected returns whether a BME280 has been found.
|
||||
// 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)
|
||||
return data[0] == CHIP_ID
|
||||
}
|
||||
|
||||
// Reset the device
|
||||
func (d *Device) Reset() {
|
||||
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (ºC/1000)
|
||||
func (d *Device) ReadTemperature() (int32, error) {
|
||||
data, err := d.readData()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
temp, _ := d.calculateTemp(data)
|
||||
return temp, nil
|
||||
}
|
||||
|
||||
// ReadPressure returns the pressure in milli pascals mPa
|
||||
func (d *Device) ReadPressure() (int32, error) {
|
||||
data, err := d.readData()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, tFine := d.calculateTemp(data)
|
||||
pressure := d.calculatePressure(data, tFine)
|
||||
return pressure, nil
|
||||
}
|
||||
|
||||
// ReadHumidity returns the relative humidity in hundredths of a percent
|
||||
func (d *Device) ReadHumidity() (int32, error) {
|
||||
data, err := d.readData()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, tFine := d.calculateTemp(data)
|
||||
humidity := d.calculateHumidity(data, tFine)
|
||||
return humidity, nil
|
||||
}
|
||||
|
||||
// ReadAltitude returns the current altitude in meters based on the
|
||||
// current barometric pressure and estimated pressure at sea level.
|
||||
// Calculation is based on code from Adafruit BME280 library
|
||||
// https://github.com/adafruit/Adafruit_BME280_Library
|
||||
func (d *Device) ReadAltitude() (alt int32, err error) {
|
||||
mPa, _ := d.ReadPressure()
|
||||
atmP := float32(mPa) / 100000
|
||||
alt = int32(44330.0 * (1.0 - math.Pow(float64(atmP/SEALEVEL_PRESSURE), 0.1903)))
|
||||
return
|
||||
}
|
||||
|
||||
// convert2Bytes converts two bytes to int32
|
||||
func convert2Bytes(msb byte, lsb byte) int32 {
|
||||
return int32(readUint(msb, lsb))
|
||||
}
|
||||
|
||||
// convert3Bytes converts three bytes to int32
|
||||
func convert3Bytes(msb byte, b1 byte, lsb byte) int32 {
|
||||
return int32(((((uint32(msb) << 8) | uint32(b1)) << 8) | uint32(lsb)) >> 4)
|
||||
}
|
||||
|
||||
// readUint converts two bytes to uint16
|
||||
func readUint(msb byte, lsb byte) uint16 {
|
||||
return (uint16(msb) << 8) | uint16(lsb)
|
||||
}
|
||||
|
||||
// readUintLE converts two little endian bytes to uint16
|
||||
func readUintLE(msb byte, lsb byte) uint16 {
|
||||
temp := readUint(msb, lsb)
|
||||
return (temp >> 8) | (temp << 8)
|
||||
}
|
||||
|
||||
// readIntLE converts two little endian bytes to int16
|
||||
func readIntLE(msb byte, lsb byte) int16 {
|
||||
return int16(readUintLE(msb, lsb))
|
||||
}
|
||||
|
||||
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
|
||||
// resulting in an slice with 8 bytes 0-2 = pressure / 3-5 = temperature / 6-7 = humidity
|
||||
func (d *Device) readData() (data [8]byte, err error) {
|
||||
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
|
||||
if err != nil {
|
||||
println(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// calculateTemp uses the data slice and applies calibrations values on it to convert the value to milli degrees
|
||||
// it also calculates the variable tFine which is used by the pressure and humidity calculation
|
||||
func (d *Device) calculateTemp(data [8]byte) (int32, int32) {
|
||||
|
||||
rawTemp := convert3Bytes(data[3], data[4], data[5])
|
||||
|
||||
var1 := (((rawTemp >> 3) - (int32(d.calibrationCoefficients.t1) << 1)) * int32(d.calibrationCoefficients.t2)) >> 11
|
||||
var2 := (((((rawTemp >> 4) - int32(d.calibrationCoefficients.t1)) * ((rawTemp >> 4) - int32(d.calibrationCoefficients.t1))) >> 12) * int32(d.calibrationCoefficients.t3)) >> 14
|
||||
|
||||
tFine := var1 + var2
|
||||
T := (tFine*5 + 128) >> 8
|
||||
return (10 * T), tFine
|
||||
}
|
||||
|
||||
// calculatePressure uses the data slice and applies calibrations values on it to convert the value to milli pascals mPa
|
||||
func (d *Device) calculatePressure(data [8]byte, tFine int32) int32 {
|
||||
|
||||
rawPressure := convert3Bytes(data[0], data[1], data[2])
|
||||
|
||||
var1 := int64(tFine) - 128000
|
||||
var2 := var1 * var1 * int64(d.calibrationCoefficients.p6)
|
||||
var2 = var2 + ((var1 * int64(d.calibrationCoefficients.p5)) << 17)
|
||||
var2 = var2 + (int64(d.calibrationCoefficients.p4) << 35)
|
||||
var1 = ((var1 * var1 * int64(d.calibrationCoefficients.p3)) >> 8) + ((var1 * int64(d.calibrationCoefficients.p2)) << 12)
|
||||
var1 = ((int64(1) << 47) + var1) * int64(d.calibrationCoefficients.p1) >> 33
|
||||
|
||||
if var1 == 0 {
|
||||
return 0 // avoid exception caused by division by zero
|
||||
}
|
||||
p := int64(1048576 - rawPressure)
|
||||
p = (((p << 31) - var2) * 3125) / var1
|
||||
var1 = (int64(d.calibrationCoefficients.p9) * (p >> 13) * (p >> 13)) >> 25
|
||||
var2 = (int64(d.calibrationCoefficients.p8) * p) >> 19
|
||||
|
||||
p = ((p + var1 + var2) >> 8) + (int64(d.calibrationCoefficients.p7) << 4)
|
||||
p = (p / 256)
|
||||
return int32(1000 * p)
|
||||
}
|
||||
|
||||
// calculateHumidity uses the data slice and applies calibrations values on it to convert the value to relative humidity in hundredths of a percent
|
||||
func (d *Device) calculateHumidity(data [8]byte, tFine int32) int32 {
|
||||
|
||||
rawHumidity := convert2Bytes(data[6], data[7])
|
||||
|
||||
h := float32(tFine) - 76800
|
||||
|
||||
if h == 0 {
|
||||
println("invalid value")
|
||||
}
|
||||
|
||||
var1 := float32(rawHumidity) - (float32(d.calibrationCoefficients.h4)*64.0 +
|
||||
(float32(d.calibrationCoefficients.h5) / 16384.0 * h))
|
||||
|
||||
var2 := float32(d.calibrationCoefficients.h2) / 65536.0 *
|
||||
(1.0 + float32(d.calibrationCoefficients.h6)/67108864.0*h*
|
||||
(1.0+float32(d.calibrationCoefficients.h3)/67108864.0*h))
|
||||
|
||||
h = var1 * var2
|
||||
h = h * (1 - float32(d.calibrationCoefficients.h1)*h/524288)
|
||||
return int32(100 * h)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package bme280
|
||||
|
||||
// Constants/addresses used for I2C.
|
||||
|
||||
// The I2C address which this device listens to.
|
||||
const Address = 0x76
|
||||
|
||||
// Registers. Names, addresses and comments copied from the datasheet.
|
||||
const (
|
||||
CTRL_MEAS_ADDR = 0xF4
|
||||
CTRL_HUMIDITY_ADDR = 0xF2
|
||||
CTRL_CONFIG = 0xF5
|
||||
REG_PRESSURE = 0xF7
|
||||
REG_CALIBRATION = 0x88
|
||||
REG_CALIBRATION_H1 = 0xA1
|
||||
REG_CALIBRATION_H2LSB = 0xE1
|
||||
CMD_RESET = 0xE0
|
||||
|
||||
WHO_AM_I = 0xD0
|
||||
CHIP_ID = 0x60
|
||||
)
|
||||
|
||||
const (
|
||||
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
||||
)
|
||||
@@ -0,0 +1,122 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/at24cx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
eeprom := at24cx.New(machine.I2C0)
|
||||
eeprom.Configure(at24cx.Config{})
|
||||
|
||||
values := make([]uint8, 100)
|
||||
for i := uint16(0); i < 100; i++ {
|
||||
values[i] = uint8(65 + i%26)
|
||||
}
|
||||
_, err := eeprom.WriteAt(values, 0)
|
||||
if err != nil {
|
||||
println("There was an error in WriteAt:", err)
|
||||
return
|
||||
}
|
||||
|
||||
for i := uint16(0); i < 26; i++ {
|
||||
err = eeprom.WriteByte(100+i, uint8(90-i))
|
||||
if err != nil {
|
||||
println("There was an error in WriteByte:", i, err)
|
||||
return
|
||||
}
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}
|
||||
|
||||
println("\n\r\n\rRead 26 bytes one by one from address 0")
|
||||
println("Expected: ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
print("Real: ")
|
||||
for i := uint16(0); i < 26; i++ {
|
||||
char, err := eeprom.ReadByte(i)
|
||||
print(string(char))
|
||||
if err != nil {
|
||||
println("There was an error in ReadByte:", i, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
println("")
|
||||
|
||||
println("\n\r\n\rRead 100 bytes from address 26")
|
||||
println("Expected: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVZYXWVUTSRQPONMLKJIHGFEDCBA")
|
||||
print("Real: ")
|
||||
data := make([]byte, 100)
|
||||
_, err = eeprom.ReadAt(data, 26)
|
||||
if err != nil {
|
||||
println("There was an error in ReadAt:", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
print(string(data[i]))
|
||||
}
|
||||
println("")
|
||||
|
||||
// Move to the beginning of memory
|
||||
eeprom.Seek(0, 0)
|
||||
_, err = eeprom.Write([]uint8{88, 88, 88})
|
||||
if err != nil {
|
||||
println("There was an error in Write:", err)
|
||||
return
|
||||
}
|
||||
|
||||
println("\n\r\n\rRead 3 bytes")
|
||||
println("Expected: DEF")
|
||||
print("Real: ")
|
||||
data = make([]byte, 3)
|
||||
_, err = eeprom.Read(data)
|
||||
if err != nil {
|
||||
println("There was an error in Read:", err)
|
||||
return
|
||||
}
|
||||
for _, char := range data {
|
||||
print(string(char))
|
||||
}
|
||||
println("")
|
||||
|
||||
println("\n\r\n\rRead another 3 bytes (from the beginning this time)")
|
||||
eeprom.Seek(-6, 1)
|
||||
println("Expected: XXX")
|
||||
print("Real: ")
|
||||
data = make([]byte, 3)
|
||||
_, err = eeprom.Read(data)
|
||||
if err != nil {
|
||||
println("There was an error in Read:", err)
|
||||
return
|
||||
}
|
||||
for _, char := range data {
|
||||
print(string(char))
|
||||
}
|
||||
println("")
|
||||
|
||||
// Move to the end of memory
|
||||
eeprom.Seek(-4, 2)
|
||||
_, err = eeprom.Write([]uint8{89, 90, 89, 90})
|
||||
if err != nil {
|
||||
println("There was an error in Write:", err)
|
||||
return
|
||||
}
|
||||
|
||||
println("\n\r\n\rRead the last 4 bytes of the memory and the 3 of the beginning")
|
||||
eeprom.Seek(-4, 1)
|
||||
println("Expected: YZYZXXX")
|
||||
print("Real: ")
|
||||
data = make([]byte, 7)
|
||||
_, err = eeprom.Read(data)
|
||||
if err != nil {
|
||||
println("There was an error in Read:", err)
|
||||
return
|
||||
}
|
||||
for _, char := range data {
|
||||
print(string(char))
|
||||
}
|
||||
println("")
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/bme280"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
sensor := bme280.New(machine.I2C0)
|
||||
sensor.Configure()
|
||||
|
||||
connected := sensor.Connected()
|
||||
if !connected {
|
||||
println("BME280 not detected")
|
||||
}
|
||||
println("BME280 detected")
|
||||
|
||||
for {
|
||||
temp, _ := sensor.ReadTemperature()
|
||||
println("Temperature:", strconv.FormatFloat(float64(temp)/1000, 'f', 2, 64), "ºC")
|
||||
press, _ := sensor.ReadPressure()
|
||||
println("Pressure:", strconv.FormatFloat(float64(press)/100000, 'f', 2, 64), "hPa")
|
||||
hum, _ := sensor.ReadHumidity()
|
||||
println("Humidity:", strconv.FormatFloat(float64(hum)/100, 'f', 2, 64), "%")
|
||||
alt, _ := sensor.ReadAltitude()
|
||||
println("Altitude:", alt, "m")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,12 @@ func (d Device) WriteByte(c byte) error {
|
||||
|
||||
// See:
|
||||
// https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
|
||||
// T0H: 14-16 cycles or 218.75ns - 250.00ns
|
||||
// T0H: 17-19 cycles or 265.63ns - 296.88ns
|
||||
// T0L: 54-56 cycles or 843.75ns - 875.00ns
|
||||
// +: 68-72 cycles or 1062.50ns - 1125.00ns
|
||||
// T1H: 36-38 cycles or 562.50ns - 593.75ns
|
||||
// +: 71-75 cycles or 1109.38ns - 1171.88ns
|
||||
// T1H: 39-41 cycles or 609.38ns - 640.63ns
|
||||
// T1L: 30-32 cycles or 468.75ns - 500.0ns
|
||||
// +: 66-70 cycles or 1031.25ns - 1093.75ns
|
||||
// +: 69-73 cycles or 1078.13ns - 1140.63ns
|
||||
// A branch is treated here as 1-3 cycles, because apparently it might get
|
||||
// speculated. This is more of a guess than hard fact, because the only docs
|
||||
// by ARM that state this are now considered superseded (by what?).
|
||||
@@ -41,6 +41,9 @@ func (d Device) WriteByte(c byte) error {
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bcs.n skip_store @ [1-3]
|
||||
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
|
||||
skip_store:
|
||||
|
||||
Reference in New Issue
Block a user