mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-09-10 00:29:30 +00:00
veml6070: add Vishay UV light sensor
This commit is contained in:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user