mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2413eb86e0 | |||
| c7555a1469 | |||
| 3fca96e0ef | |||
| c7981f72ec | |||
| 5df157230f | |||
| bcb291992c | |||
| 7b710e3a48 | |||
| dcfd9c066d | |||
| 955b3a56e8 | |||
| 21b8d953f4 | |||
| d1b917b835 |
@@ -1,3 +1,23 @@
|
||||
0.7.0
|
||||
---
|
||||
- **new devices**
|
||||
- veml6070: add Vishay UV light sensor
|
||||
- **enhancements**
|
||||
- lis3dh: example uses I2C1 so requires config to specify pins since they are not default
|
||||
- ssd1331: make SPI TX faster
|
||||
- st7735: make SPI Tx faster
|
||||
- **docs**
|
||||
- complete missing GoDocs for main and sub-packages
|
||||
- **core**
|
||||
- add Version string for support purposes
|
||||
- **examples**
|
||||
- Change all espat driver examples to use Arduino Nano33 IoT by default
|
||||
|
||||
0.6.0
|
||||
---
|
||||
- **new devices**
|
||||
- Support software SPI for APA102 (Itsy Bitsy M0 on-board "Dotstar" LED as example)
|
||||
|
||||
0.5.0
|
||||
---
|
||||
- **new devices**
|
||||
|
||||
@@ -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=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/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
|
||||
@@ -19,9 +20,9 @@ smoke-test:
|
||||
tinygo build -size short -o ./build/test.elf -target=bluepill ./examples/ds1307/time/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/ds3231/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/easystepper/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/espat/espconsole/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/espat/esphub/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/espat/espstation/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=arduino-nano33 ./examples/espat/espconsole/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=arduino-nano33 ./examples/espat/esphub/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=arduino-nano33 ./examples/espat/espstation/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=feather-m0 ./examples/gps/i2c/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=feather-m0 ./examples/gps/uart/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/hd44780/customchar/main.go
|
||||
@@ -49,5 +50,6 @@ smoke-test:
|
||||
tinygo build -size short -o ./build/test.elf -target=trinket-m0 ./examples/bme280/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/microphone/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/buzzer/main.go
|
||||
tinygo build -size short -o ./build/test.elf -target=trinket-m0 ./examples/veml6070/main.go
|
||||
|
||||
test: clean fmt-check smoke-test
|
||||
|
||||
@@ -82,6 +82,7 @@ func main() {
|
||||
| [ST7735 TFT color display](https://www.crystalfontz.com/controllers/Sitronix/ST7735R/319/) | SPI |
|
||||
| [ST7789 TFT color display](https://cdn-shop.adafruit.com/product-files/3787/3787_tft_QT154H2201__________20190228182902.pdf) | SPI |
|
||||
| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC |
|
||||
| [VEML6070 UV light sensor](https://www.vishay.com/docs/84277/veml6070.pdf) | I2C |
|
||||
| [VL53L1X time-of-flight distance sensor](https://www.st.com/resource/en/datasheet/vl53l1x.pdf) | I2C |
|
||||
| [Waveshare 2.13" e-paper display](https://www.waveshare.com/w/upload/e/e6/2.13inch_e-Paper_Datasheet.pdf) | SPI |
|
||||
| [Waveshare 2.13" (B & C) e-paper display](https://www.waveshare.com/w/upload/d/d3/2.13inch-e-paper-b-Specification.pdf) | SPI |
|
||||
|
||||
+15
-2
@@ -21,15 +21,28 @@ const (
|
||||
|
||||
// Device wraps APA102 SPI LEDs.
|
||||
type Device struct {
|
||||
bus machine.SPI
|
||||
bus SPI
|
||||
Order int
|
||||
}
|
||||
|
||||
// The SPI interface specifies the minimum functionality that a bus
|
||||
// implementation needs to provide for use by the APA102 driver. Hardware
|
||||
// SPI from the TinyGo "machine" package implements this already.
|
||||
type SPI interface {
|
||||
Tx(w, r []byte) error
|
||||
}
|
||||
|
||||
// New returns a new APA102 driver. Pass in a fully configured SPI bus.
|
||||
func New(b machine.SPI) Device {
|
||||
func New(b SPI) Device {
|
||||
return Device{bus: b, Order: BGR}
|
||||
}
|
||||
|
||||
// NewSoftwareSPI returns a new APA102 driver that will use a software based
|
||||
// implementation of the SPI protocol.
|
||||
func NewSoftwareSPI(sckPin, mosiPin machine.Pin, delay uint32) Device {
|
||||
return New(&bbSPI{SCK: sckPin, MOSI: mosiPin, Delay: delay})
|
||||
}
|
||||
|
||||
// WriteColors writes the given RGBA color slice out using the APA102 protocol.
|
||||
// The A value (Alpha channel) is used for brightness, set to 0xff (255) for maximum.
|
||||
func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package apa102
|
||||
|
||||
import "machine"
|
||||
|
||||
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
|
||||
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
|
||||
// Note: making this unexported for now because it is probable not suitable
|
||||
// most purposes other than the APA102 package. It might be desirable to make
|
||||
// this more generic and include it in the TinyGo "machine" package instead.
|
||||
type bbSPI struct {
|
||||
SCK machine.Pin
|
||||
MOSI machine.Pin
|
||||
Delay uint32
|
||||
}
|
||||
|
||||
// Configure sets up the SCK and MOSI pins as outputs and sets them low
|
||||
func (s *bbSPI) Configure() {
|
||||
s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
s.MOSI.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
s.SCK.Low()
|
||||
s.MOSI.Low()
|
||||
if s.Delay == 0 {
|
||||
s.Delay = 1
|
||||
}
|
||||
}
|
||||
|
||||
// Tx matches signature of machine.SPI.Tx() and is used to send multiple bytes.
|
||||
// The r slice is ignored and no error will ever be returned.
|
||||
func (s *bbSPI) Tx(w []byte, r []byte) error {
|
||||
s.Configure()
|
||||
for _, b := range w {
|
||||
s.Transfer(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// delay represents a quarter of the clock cycle
|
||||
func (s *bbSPI) delay() {
|
||||
for i := uint32(0); i < s.Delay; {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer is used to send a single byte.
|
||||
func (s *bbSPI) Transfer(b byte) {
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
|
||||
// half clock cycle high to start
|
||||
s.SCK.High()
|
||||
s.delay()
|
||||
|
||||
// write the value to MOSI (MSB first)
|
||||
if b&(1<<(7-i)) == 0 {
|
||||
s.MOSI.Low()
|
||||
} else {
|
||||
s.MOSI.High()
|
||||
}
|
||||
s.delay()
|
||||
|
||||
// half clock cycle low
|
||||
s.SCK.Low()
|
||||
s.delay()
|
||||
|
||||
// for actual SPI would try to read the MISO value here
|
||||
s.delay()
|
||||
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
// Package drivers provides a collection of hardware drivers for devices that
|
||||
// can be used together with TinyGo (https://tinygo.org).
|
||||
// Package drivers provides a collection of hardware drivers for TinyGo (https://tinygo.org)
|
||||
// for devices such as sensors and displays.
|
||||
//
|
||||
// Here is an example in TinyGo that uses the BMP180 digital barometer:
|
||||
//
|
||||
@@ -9,7 +9,7 @@
|
||||
// "time"
|
||||
// "machine"
|
||||
//
|
||||
// "github.com/tinygo-org/drivers/bmp180"
|
||||
// "tinygo.org/x/drivers/bmp180"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Simple driver to rotate a 4-wire stepper motor
|
||||
// Package easystepper provides a simple driver to rotate a 4-wire stepper motor.
|
||||
package easystepper // import "tinygo.org/x/drivers/easystepper"
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package mqtt is intended to provide compatible interfaces with the
|
||||
// Paho mqtt library.
|
||||
package mqtt
|
||||
|
||||
import (
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// This example demostrates how to control the "Dotstar" (APA102) LED included
|
||||
// on the Adafruit Itsy Bitsy M0 board. It implements a "rainbow effect" based
|
||||
// on the following example:
|
||||
// https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/master/CircuitPython_Essentials/CircuitPython_Internal_RGB_LED_rainbow.py
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apa102"
|
||||
)
|
||||
|
||||
var (
|
||||
apa apa102.Device
|
||||
|
||||
led = machine.PWM{machine.LED}
|
||||
leds = make([]color.RGBA, 1)
|
||||
wheel = &Wheel{Brightness: 0x10}
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
// APA102 on Itsy Bitsy is connected to pins that require a software-based
|
||||
// SPI implementation.
|
||||
apa = apa102.NewSoftwareSPI(machine.PA00, machine.PA01, 1)
|
||||
|
||||
// Configure the regular on-board LED for PWM fading
|
||||
machine.InitPWM()
|
||||
led.Configure()
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll fade the on-board LED in a goroutine to show/ensure that the APA102
|
||||
// works fine with the scheduler enabled. Comment this out to test this code
|
||||
// with the scheduler disabled.
|
||||
go func() {
|
||||
for i, brightening := uint8(0), false; ; i++ {
|
||||
if i == 0 {
|
||||
brightening = !brightening
|
||||
continue
|
||||
}
|
||||
var brightness uint16 = uint16(i) << 8
|
||||
if !brightening {
|
||||
brightness = 0xFFFF - brightness
|
||||
}
|
||||
led.Set(brightness)
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// Use the "wheel" function from Adafruit's example to cycle the APA102
|
||||
for {
|
||||
leds[0] = wheel.Next()
|
||||
apa.WriteColors(leds)
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Wheel is a port of Adafruit's Circuit Python example referenced above.
|
||||
type Wheel struct {
|
||||
Brightness uint8
|
||||
pos uint8
|
||||
}
|
||||
|
||||
// Next increments the internal state of the color and returns the new RGBA
|
||||
func (w *Wheel) Next() (c color.RGBA) {
|
||||
pos := w.pos
|
||||
if w.pos < 85 {
|
||||
c = color.RGBA{R: 0xFF - pos*3, G: pos * 3, B: 0x0, A: w.Brightness}
|
||||
} else if w.pos < 170 {
|
||||
pos -= 85
|
||||
c = color.RGBA{R: 0x0, G: 0xFF - pos*3, B: pos * 3, A: w.Brightness}
|
||||
} else {
|
||||
pos -= 170
|
||||
c = color.RGBA{R: pos * 3, G: 0x0, B: 0xFF - pos*3, A: w.Brightness}
|
||||
}
|
||||
w.pos++
|
||||
return
|
||||
}
|
||||
@@ -23,11 +23,12 @@ const actAsAP = false
|
||||
const ssid = "YOURSSID"
|
||||
const pass = "YOURPASS"
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
tx = machine.D10
|
||||
rx = machine.D11
|
||||
uart = machine.UART2
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
console = machine.UART0
|
||||
|
||||
|
||||
@@ -21,11 +21,12 @@ const actAsAP = false
|
||||
const ssid = "YOURSSID"
|
||||
const pass = "YOURPASS"
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
tx = machine.D10
|
||||
rx = machine.D11
|
||||
uart = machine.UART2
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
adaptor *espat.Device
|
||||
)
|
||||
|
||||
@@ -21,11 +21,12 @@ const pass = "YOURPASS"
|
||||
// IP address of the listener aka "hub". Replace with your own info.
|
||||
const hubIP = "0.0.0.0"
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
tx = machine.D10
|
||||
rx = machine.D11
|
||||
uart = machine.UART2
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
adaptor *espat.Device
|
||||
)
|
||||
|
||||
@@ -28,11 +28,12 @@ const pass = "YOURPASS"
|
||||
//const server = "tcp://test.mosquitto.org:1883"
|
||||
const server = "ssl://test.mosquitto.org:8883"
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
tx = machine.D10
|
||||
rx = machine.D11
|
||||
uart = machine.UART2
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
console = machine.UART0
|
||||
|
||||
|
||||
@@ -21,9 +21,10 @@ const pass = "YOURPASS"
|
||||
// IP address of the server aka "hub". Replace with your own info.
|
||||
const serverIP = "0.0.0.0"
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
uart = machine.UART2
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
var i2c = machine.I2C1
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{})
|
||||
i2c.Configure(machine.I2CConfig{SCL: machine.SCL1_PIN, SDA: machine.SDA1_PIN})
|
||||
|
||||
accel := lis3dh.New(i2c)
|
||||
accel.Address = lis3dh.Address1 // address on the Circuit Playground Express
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/veml6070"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
sensor := veml6070.New(machine.I2C0)
|
||||
|
||||
if !sensor.Configure() {
|
||||
println("VEML6070 could not be configured")
|
||||
return
|
||||
}
|
||||
|
||||
println("VEML6070 configured")
|
||||
|
||||
for {
|
||||
intensity, _ := sensor.ReadUVALightIntensity()
|
||||
println("UVA light intensity:", float32(intensity)/1000.0, "W/(m*m)")
|
||||
|
||||
switch sensor.GetEstimatedRiskLevel(intensity) {
|
||||
case veml6070.UVI_RISK_LOW:
|
||||
println("UV risk level: low")
|
||||
case veml6070.UVI_RISK_MODERATE:
|
||||
println("UV risk level: moderate")
|
||||
case veml6070.UVI_RISK_HIGH:
|
||||
println("UV risk level: high")
|
||||
case veml6070.UVI_RISK_VERY_HIGH:
|
||||
println("UV risk level: very high")
|
||||
case veml6070.UVI_RISK_EXTREME:
|
||||
println("UV risk level: extreme")
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
+3
-16
@@ -34,7 +34,7 @@ type Config struct {
|
||||
Height int16
|
||||
}
|
||||
|
||||
// New creates a new ST7735 connection. The SPI wire must already be configured.
|
||||
// New creates a new SSD1331 connection. The SPI wire must already be configured.
|
||||
func New(bus machine.SPI, resetPin, dcPin, csPin machine.Pin) Device {
|
||||
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
@@ -250,21 +250,8 @@ func (d *Device) Data(data uint8) {
|
||||
|
||||
// Tx sends data to the display
|
||||
func (d *Device) Tx(data []byte, isCommand bool) {
|
||||
if isCommand {
|
||||
d.csPin.High()
|
||||
d.dcPin.Low()
|
||||
d.csPin.Low()
|
||||
|
||||
d.bus.Tx(data, nil)
|
||||
d.csPin.High()
|
||||
} else {
|
||||
d.csPin.High()
|
||||
d.dcPin.High()
|
||||
d.csPin.Low()
|
||||
|
||||
d.bus.Tx(data, nil)
|
||||
d.csPin.High()
|
||||
}
|
||||
d.dcPin.Set(!isCommand)
|
||||
d.bus.Tx(data, nil)
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
|
||||
+2
-15
@@ -383,21 +383,8 @@ func (d *Device) Data(data uint8) {
|
||||
|
||||
// Tx sends data to the display
|
||||
func (d *Device) Tx(data []byte, isCommand bool) {
|
||||
if isCommand {
|
||||
d.csPin.High()
|
||||
d.dcPin.Low()
|
||||
d.csPin.Low()
|
||||
|
||||
d.bus.Tx(data, nil)
|
||||
d.csPin.High()
|
||||
} else {
|
||||
d.csPin.High()
|
||||
d.dcPin.High()
|
||||
d.csPin.Low()
|
||||
|
||||
d.bus.Tx(data, nil)
|
||||
d.csPin.High()
|
||||
}
|
||||
d.dcPin.Set(!isCommand)
|
||||
d.bus.Tx(data, nil)
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package veml6070
|
||||
|
||||
// I2C addresses and other constants
|
||||
|
||||
const (
|
||||
ADDR_L = 0x38 // 7bit address of the VEML6070 (write, read)
|
||||
ADDR_H = 0x39 // 7bit address of the VEML6070 (read)
|
||||
)
|
||||
|
||||
// Some possible values for resistance value (in ohm) of VEML6070 calibration resistor
|
||||
const (
|
||||
RSET_240K = 240000
|
||||
RSET_270K = 270000
|
||||
RSET_300K = 300000
|
||||
RSET_600K = 600000
|
||||
)
|
||||
|
||||
// Possible values for integration time of VEML6070
|
||||
// (internally represents the config register bit mask)
|
||||
const (
|
||||
IT_HALF = 0x00
|
||||
IT_1 = 0x04
|
||||
IT_2 = 0x08
|
||||
IT_4 = 0x0C
|
||||
)
|
||||
|
||||
// Possible values for UVI (UV index) risk level estimations - the VEML6070 can
|
||||
// only estimate UVI risk levels since it can only sense UVA rays but the vendor
|
||||
// tried to come up with some coarse thresholds, from application notes
|
||||
const (
|
||||
UVI_RISK_LOW = iota
|
||||
UVI_RISK_MODERATE
|
||||
UVI_RISK_HIGH
|
||||
UVI_RISK_VERY_HIGH
|
||||
UVI_RISK_EXTREME
|
||||
)
|
||||
|
||||
// Scale factor in milliseconds / ohm to determine refresh time
|
||||
// (aka sampling time) without IT_FACTOR for any given RSET, from datasheet.
|
||||
// Note: 100.0 milliseconds are applicable for RSET=240 kOhm and IT_FACTOR=1
|
||||
const RSET_TO_REFRESHTIME_SCALE = 100.0 / RSET_240K
|
||||
|
||||
// The refresh time in milliseconds for which NORMALIZED_UVA_SENSITIVITY
|
||||
// is applicable to a step count
|
||||
const NORMALIZED_REFRESHTIME = 100.0
|
||||
|
||||
// The UVA sensitivity in mW/(m*m)/step which is applicable to a step count
|
||||
// normalized to the NORMALIZED_REFRESHTIME, from datasheet for RSET=240 kOhm
|
||||
// and IT_FACTOR=1
|
||||
const NORMALIZED_UVA_SENSITIVITY = 50.0
|
||||
|
||||
// Config register
|
||||
|
||||
// Possible values for shutdown
|
||||
const (
|
||||
CONFIG_SD_DISABLE = 0x00
|
||||
CONFIG_SD_ENABLE = 0x01
|
||||
)
|
||||
|
||||
// Enable / disable
|
||||
const (
|
||||
CONFIG_DEFAULTS = 0x02
|
||||
CONFIG_ENABLE = CONFIG_SD_DISABLE | CONFIG_DEFAULTS
|
||||
CONFIG_DISABLE = CONFIG_SD_ENABLE | CONFIG_DEFAULTS
|
||||
)
|
||||
@@ -0,0 +1,140 @@
|
||||
// Package veml6070 provides a driver for the VEML6070 digital UV light sensor
|
||||
// by Vishay.
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.vishay.com/docs/84277/veml6070.pdf
|
||||
// Application Notes:
|
||||
// https://www.vishay.com/docs/84310/designingveml6070.pdf
|
||||
//
|
||||
package veml6070 // import "tinygo.org/x/drivers/veml6070"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a VEML6070 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
AddressLow uint16
|
||||
AddressHigh uint16
|
||||
RSET uint32
|
||||
IT uint8
|
||||
}
|
||||
|
||||
// New creates a new VEML6070 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not initialize the device.
|
||||
// You must call Configure() first in order to use the device itself.
|
||||
func New(bus machine.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
AddressLow: ADDR_L,
|
||||
AddressHigh: ADDR_H,
|
||||
RSET: RSET_240K,
|
||||
// Note: default to maximum to get as much precision as possible since
|
||||
// raw data values larger than 16 bit can hardly occur with RSET below
|
||||
// 300 kOhm in real world applications. Power saving due to shorter
|
||||
// sampling time might be a reason to reduce this.
|
||||
IT: IT_4,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication
|
||||
func (d *Device) Configure() bool {
|
||||
// save power by shutdown as early as possible, also serves as presence test
|
||||
if err := d.disable(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUVALightIntensity returns the UVA light intensity (irradiance)
|
||||
// in milli Watt per square meter (mW/(m*m))
|
||||
func (d *Device) ReadUVALightIntensity() (uint32, error) {
|
||||
var err2 error
|
||||
|
||||
if err := d.enable(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// wait two times the refresh time to allow completion of a previous cycle
|
||||
// with old settings (worst case)
|
||||
time.Sleep(time.Duration(d.getRefreshTime()) * 2 * time.Millisecond)
|
||||
|
||||
msb, err2 := d.readData(d.AddressHigh)
|
||||
if err2 != nil {
|
||||
return 0, err2
|
||||
}
|
||||
|
||||
lsb, err2 := d.readData(d.AddressLow)
|
||||
if err2 != nil {
|
||||
return 0, err2
|
||||
}
|
||||
|
||||
if err := d.disable(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
rawData := (uint32(msb) << 8) | uint32(lsb)
|
||||
|
||||
// normalize raw data (step count sampled in d.getRefreshTime()) into the
|
||||
// linearly scaled normalized data (step count sampled in 100ms) for which
|
||||
// we know the UVA sensitivity
|
||||
normalizedData := float32(rawData) * NORMALIZED_REFRESHTIME / d.getRefreshTime()
|
||||
|
||||
// now we can calculate the absolute UVA power detected combining normalized
|
||||
// data with known UVA sensitivity for this data, from datasheet
|
||||
intensity := normalizedData * NORMALIZED_UVA_SENSITIVITY // mW/(m*m)
|
||||
|
||||
return uint32(intensity + 0.5), nil
|
||||
}
|
||||
|
||||
// GetEstimatedRiskLevel returns estimated risk level from comparing UVA light
|
||||
// intensity values in mW/(m*m) with thresholds calculated from application notes
|
||||
func (d *Device) GetEstimatedRiskLevel(intensity uint32) uint8 {
|
||||
if intensity <= 24888 {
|
||||
return UVI_RISK_LOW
|
||||
} else if intensity <= 49800 {
|
||||
return UVI_RISK_MODERATE
|
||||
} else if intensity <= 66400 {
|
||||
return UVI_RISK_HIGH
|
||||
} else if intensity <= 91288 {
|
||||
return UVI_RISK_VERY_HIGH
|
||||
} else {
|
||||
return UVI_RISK_EXTREME
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) disable() error {
|
||||
return d.bus.Tx(uint16(d.AddressLow), []byte{CONFIG_DISABLE}, nil)
|
||||
}
|
||||
|
||||
func (d *Device) enable() error {
|
||||
return d.bus.Tx(uint16(d.AddressLow), []byte{CONFIG_ENABLE | d.IT}, nil)
|
||||
}
|
||||
|
||||
func (d *Device) readData(address uint16) (byte, error) {
|
||||
data := []byte{0}
|
||||
err := machine.I2C0.Tx(address, []byte{}, data)
|
||||
return data[0], err
|
||||
}
|
||||
|
||||
// getRefreshTime returns the refresh time (aka sample time) in milliseconds
|
||||
func (d *Device) getRefreshTime() float32 {
|
||||
var it float32
|
||||
switch d.IT {
|
||||
case IT_HALF:
|
||||
it = 0.5
|
||||
case IT_1:
|
||||
it = 1
|
||||
case IT_2:
|
||||
it = 2
|
||||
case IT_4:
|
||||
it = 4
|
||||
}
|
||||
return float32(d.RSET) * RSET_TO_REFRESHTIME_SCALE * it
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package drivers
|
||||
|
||||
// Version returns a user-readable string showing the version of the drivers package for support purposes.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.7.0"
|
||||
Reference in New Issue
Block a user