-
Notifications
You must be signed in to change notification settings - Fork 229
Add Honeywell HSC TruStability SPI+I2C pressure sensor driver #799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import ( | ||
"machine" | ||
"time" | ||
|
||
"tinygo.org/x/drivers" | ||
"tinygo.org/x/drivers/honeyhsc" | ||
) | ||
|
||
// Data taken from https://github.com/rodan/honeywell_hsc_ssc_i2c/blob/master/hsc_ssc_i2c.cpp | ||
// these defaults are valid for the HSCMRNN030PA2A3 chip | ||
const ( | ||
i2cAddress = 0x28 | ||
// 10% | ||
outputMinimum = 0x666 | ||
// 90% of 2^14 - 1 | ||
outputMax = 0x399A | ||
// min is 0 for sensors that give absolute values | ||
pressureMin = 0 | ||
// 30psi (and we want results in millipascals) | ||
// pressureMax = 206842.7 | ||
pressureMax = 206843 * 1000 | ||
) | ||
|
||
func main() { | ||
bus := machine.I2C0 | ||
err := bus.Configure(machine.I2CConfig{ | ||
Frequency: 10_000, | ||
SDA: machine.I2C0_SDA_PIN, | ||
SCL: machine.I2C0_SCL_PIN, | ||
}) | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
sensor := honeyhsc.NewDevI2C(bus, i2cAddress, outputMinimum, outputMax, pressureMin, pressureMax) | ||
for { | ||
time.Sleep(time.Second) | ||
const measuremask = drivers.Pressure | drivers.Temperature | ||
err := sensor.Update(measuremask) | ||
if err != nil { | ||
println("error updating measurements:", err.Error()) | ||
continue | ||
} | ||
P := sensor.Pressure() | ||
T := sensor.Temperature() | ||
println("pressure:", P, "temperature:", T) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,135 @@ | ||||||||||||
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 [4]byte | ||||||||||||
} | ||||||||||||
|
||||||||||||
func NewDevI2C(bus drivers.I2C, addr uint8, outMin, outMax uint16, pMin, pMax int32) *DevI2C { | ||||||||||||
soypat marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
h := &DevI2C{ | ||||||||||||
bus: bus, | ||||||||||||
addr: addr, | ||||||||||||
dev: dev{ | ||||||||||||
cmin: outMin, | ||||||||||||
cmax: outMax, | ||||||||||||
pmin: pMin, | ||||||||||||
pmax: pMax, | ||||||||||||
}, | ||||||||||||
} | ||||||||||||
return h | ||||||||||||
} | ||||||||||||
|
||||||||||||
func (d *DevI2C) Update(which drivers.Measurement) error { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, please add documentation to this method (especially since it is exported). |
||||||||||||
if which&measuremask == 0 { | ||||||||||||
return nil | ||||||||||||
} | ||||||||||||
buf := &d.buf | ||||||||||||
const reg = 0 | ||||||||||||
value := (d.addr << 1) | 1 | ||||||||||||
err := d.bus.Tx(uint16(d.addr), []byte{reg, value}, buf[:]) | ||||||||||||
|
||||||||||||
if err != nil { | ||||||||||||
return err | ||||||||||||
} | ||||||||||||
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 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 | ||||||||||||
} | ||||||||||||
|
||||||||||||
func NewDevSPI(conn drivers.SPI, cs pinout, outMin, outMax uint16, pMin, pMax int32) (*DevSPI, error) { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, this should get some explanation. At least clarifying with parameters like |
||||||||||||
h := &DevSPI{ | ||||||||||||
spi: conn, | ||||||||||||
cs: cs, | ||||||||||||
dev: dev{ | ||||||||||||
cmin: outMin, | ||||||||||||
cmax: outMax, | ||||||||||||
pmin: pMin, | ||||||||||||
pmax: pMax, | ||||||||||||
}, | ||||||||||||
} | ||||||||||||
return h, nil | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Update implements the sensor interface. | ||||||||||||
|
||||||||||||
func (h *DevSPI) Update(which drivers.Measurement) error { | ||||||||||||
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 pressure in millipascals [mPa]. | ||||||||||||
func (d *dev) Pressure() int32 { | ||||||||||||
return d.pressure | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Temperature returns temperature in milliKelvin [mK]. | ||||||||||||
func (d *dev) Temperature() int32 { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By far most drivers use milli-degrees Celsius. See for example: Lines 277 to 279 in 228e57c
And: Lines 180 to 181 in 228e57c
I would like to keep that as a convention. Also see #332 which I still think is a good idea. It's somewhat out of scope for this PR though. |
||||||||||||
return d.temp | ||||||||||||
} | ||||||||||||
|
||||||||||||
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 | ||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
10kHz is an unusually low frequency, is this intentional? (Many chips don't even support such low frequencies).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good catch. 100kHz is minimum for this IC.