mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-03 06:27:47 +00:00
5cb360a4bf
* add honeywell pressure sensor * apply @aykevl suggestions
192 lines
6.5 KiB
Go
192 lines
6.5 KiB
Go
package honeyhsc
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
|
|
"tinygo.org/x/drivers"
|
|
)
|
|
|
|
var (
|
|
errSensorMissing = errors.New("hsc: not connected")
|
|
errDiagnostic = errors.New("hsc: diagnostic error")
|
|
)
|
|
|
|
const (
|
|
measuremask = drivers.Pressure | drivers.Temperature
|
|
statusMask = 0b1100_0000
|
|
statusOffset = 6
|
|
)
|
|
|
|
// DevI2C is the TruStability® High Accuracy Silicon Ceramic (HSC) Series is a piezoresistive silicon pressure sensor offering a ratiometric
|
|
// analog or digital output for reading pressure over the specified full scale pressure span and temperature range.
|
|
type DevI2C struct {
|
|
bus drivers.I2C
|
|
dev
|
|
addr uint8
|
|
buf [6]byte
|
|
}
|
|
|
|
// NewDevI2C creates and returns a new DevI2C that communicates with an HSC device over the provided I2C bus.
|
|
// Parameters:
|
|
// - bus: the I2C bus to use.
|
|
// - addr: the 7-bit I2C address of the sensor.
|
|
// - outMin, outMax: raw output code range (counts) corresponding to the pressure span. Depends on sensor model.
|
|
// - pMin, pMax: pressure range endpoints in millipascals (mPa). Depends on sensor model.
|
|
//
|
|
// The returned DevI2C will use these calibration parameters to convert raw bridge counts to pressure.
|
|
func NewDevI2C(bus drivers.I2C, addr, outMin, outMax uint16, pMin, pMax int32) *DevI2C {
|
|
h := &DevI2C{
|
|
bus: bus,
|
|
addr: uint8(addr),
|
|
dev: dev{
|
|
cmin: outMin,
|
|
cmax: outMax,
|
|
pmin: pMin,
|
|
pmax: pMax,
|
|
},
|
|
}
|
|
return h
|
|
}
|
|
|
|
// ReadTemperature reads and returns the temperature in milliKelvin (mC) from the I2C-attached HSC device.
|
|
// It performs an Update internally to get the latest temperature value.
|
|
func (h *DevI2C) ReadTemperature() (int32, error) {
|
|
err := h.Update(drivers.Temperature)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return h.Temperature(), nil
|
|
}
|
|
|
|
// Update reads both temperature and pressure data from the I2C-attached HSC device when
|
|
// the requested measurement mask includes pressure or temperature.
|
|
// If neither pressure nor temperature is requested, Update is a no-op.
|
|
func (d *DevI2C) Update(which drivers.Measurement) error {
|
|
// Update performs an I2C transaction to read 4 bytes, parses the status bits, 14-bit bridge data and
|
|
// temperature bits, and forwards them to the internal update routine. Any I2C transport error is returned,
|
|
// as well as errors produced by the internal update (e.g. errSensorMissing, errDiagnostic).
|
|
if which&measuremask == 0 {
|
|
return nil
|
|
}
|
|
rbuf := d.buf[:4]
|
|
wbuf := d.buf[4:6]
|
|
const reg = 0
|
|
value := (d.addr << 1) | 1
|
|
wbuf[0] = reg
|
|
wbuf[1] = value
|
|
err := d.bus.Tx(uint16(d.addr), wbuf, rbuf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
status := (rbuf[0] & statusMask) >> statusOffset
|
|
bridgeData := (uint16(rbuf[0]&^statusMask) << 8) | uint16(rbuf[1])
|
|
tempData := uint16(rbuf[2])<<8 | uint16(rbuf[3]&0xe0)>>5
|
|
return d.dev.update(status, bridgeData, tempData)
|
|
}
|
|
|
|
type pinout func(level bool)
|
|
|
|
// DevI2C is the TruStability® High Accuracy Silicon Ceramic (HSC) Series is a piezoresistive silicon pressure sensor offering a ratiometric
|
|
// analog or digital output for reading pressure over the specified full scale pressure span and temperature range.
|
|
type DevSPI struct {
|
|
spi drivers.SPI
|
|
cs pinout
|
|
dev
|
|
buf [4]byte
|
|
}
|
|
|
|
// NewDevSPI creates and returns a new DevSPI that communicates with an HSC device over SPI.
|
|
// Parameters:
|
|
// - conn: the SPI connection to use.
|
|
// - cs: a chip-select function that drives the device select line low/high.
|
|
// - outMin, outMax: raw output code range (counts) corresponding to the pressure span. Depends on sensor model.
|
|
// - pMin, pMax: pressure range endpoints in millipascals (mPa). Depends on sensor model.
|
|
//
|
|
// The function returns the constructed DevSPI and an error value (currently always nil).
|
|
func NewDevSPI(conn drivers.SPI, cs pinout, outMin, outMax uint16, pMin, pMax int32) (*DevSPI, error) {
|
|
h := &DevSPI{
|
|
spi: conn,
|
|
cs: cs,
|
|
dev: dev{
|
|
cmin: outMin,
|
|
cmax: outMax,
|
|
pmin: pMin,
|
|
pmax: pMax,
|
|
},
|
|
}
|
|
return h, nil
|
|
}
|
|
|
|
// ReadTemperature reads and returns the temperature in milliKelvin (mC) from the SPI-attached HSC device.
|
|
// It performs an Update internally to get the latest temperature value.
|
|
func (h *DevSPI) ReadTemperature() (int32, error) {
|
|
err := h.Update(drivers.Temperature)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return h.Temperature(), nil
|
|
}
|
|
|
|
// Update reads pressure and temperature data from the SPI-attached HSC device when the requested measurement mask includes
|
|
// pressure or temperature. If neither pressure nor temperature is requested, Update is a no-op.
|
|
func (h *DevSPI) Update(which drivers.Measurement) error {
|
|
// It toggles the provided chip-select, performs an SPI transfer to read 4 bytes, parses the status bits,
|
|
// 14-bit bridge data and temperature bits, and forwards them to the internal update routine. Any SPI
|
|
// transport error is returned, as well as errors produced by the internal update (e.g. errSensorMissing, errDiagnostic).
|
|
if which&measuremask == 0 {
|
|
return nil
|
|
}
|
|
buf := &h.buf
|
|
h.cs(false)
|
|
err := h.spi.Tx(nil, buf[:4])
|
|
h.cs(true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// First two bits are status bits.
|
|
status := (buf[0] & statusMask) >> statusOffset
|
|
bridgeData := (uint16(buf[0]&^statusMask) << 8) | uint16(buf[1])
|
|
|
|
tempData := uint16(buf[2])<<8 | uint16(buf[3]&0xe0)>>5
|
|
return h.dev.update(status, bridgeData, tempData)
|
|
}
|
|
|
|
type dev struct {
|
|
pressure int32
|
|
temp int32
|
|
cmin, cmax uint16
|
|
pmin, pmax int32
|
|
}
|
|
|
|
// Pressure returns the most recently computed pressure value in millipascals (mPa).
|
|
// The value is taken from the last successful Update.
|
|
func (d *dev) Pressure() int32 {
|
|
return d.pressure
|
|
}
|
|
|
|
// Temperature returns the most recently read temperature value in milliKelvin (mC).
|
|
// The value is taken from the last successful Update.
|
|
func (d *dev) Temperature() int32 {
|
|
return d.temp + 273_150
|
|
}
|
|
|
|
// update interprets raw sensor fields (status, bridgeData, tempData) and updates the dev's stored
|
|
// pressure and temperature. It returns errSensorMissing when the temperature raw value indicates no sensor
|
|
// (tempData == math.MaxUint16), errDiagnostic when the status indicates a device diagnostic condition
|
|
// (status == 3), or nil on success. Pressure is computed with integer arithmetic using the configured
|
|
// cmin/cmax -> pmin/pmax linear mapping in order to avoid overflows.
|
|
func (d *dev) update(status uint8, bridgeData, tempData uint16) error {
|
|
if tempData == math.MaxUint16 {
|
|
return errSensorMissing
|
|
} else if status == 3 {
|
|
return errDiagnostic
|
|
}
|
|
|
|
// Take care not to overflow here.
|
|
p := (int32(bridgeData)-int32(d.cmin))*(d.pmax-d.pmin)/int32(d.cmax-d.cmin) + d.pmin
|
|
d.temp = int32(tempData)
|
|
d.pressure = p
|
|
return nil
|
|
}
|