- add support for tmp006

- refactor the i2c interface
This commit is contained in:
Karan Misra 2014-01-05 14:27:29 +05:30
parent 1a6f97f102
commit 0563d2be5c
9 changed files with 513 additions and 70 deletions

View File

@ -22,22 +22,26 @@ const (
// A Bus implements access to the I2C two wire bus.
type Bus interface {
// Read a byte from the given address.
// ReadByte reads a byte from the given address.
ReadByte(addr byte) (value byte, err error)
// Write a byte to the given address.
// WriteByte writes a byte to the given address.
WriteByte(addr, value byte) error
// Write a bunch of bytes ot the given address.
// WriteBytes writes a slice bytes to the given address.
WriteBytes(addr byte, value []byte) error
// Read a bunch of bytes (len(value)) from the given address and register.
ReadFromReg(addr, reg byte, value []byte) (err error)
// Read a byte from the given address and register.
// ReadFromReg reads n (len(value)) bytes from the given address and register.
ReadFromReg(addr, reg byte, value []byte) error
// ReadByteFromReg reads a byte from the given address and register.
ReadByteFromReg(addr, reg byte) (value byte, err error)
// Read a int from the given address and register.
ReadInt(addr, reg byte) (value int, err error)
// ReadU16FromReg reads a unsigned 16 bit integer from the given address and register.
ReadWordFromReg(addr, reg byte) (value uint16, err error)
// Write a byte to the given address and register.
WriteToReg(addr, reg, value byte) error
// WriteToReg writes len(value) bytes to the given address and register.
WriteToReg(addr, reg byte, value []byte) error
// WriteByteToReg writes a byte to the given address and register.
WriteByteToReg(addr, reg, value byte) error
// WriteU16ToReg
WriteWordToReg(addr, reg byte, value uint16) error
}
type i2c_msg struct {
@ -108,7 +112,6 @@ func (b *bus) setAddress(addr byte) (err error) {
return
}
// Read a byte from the given address.
func (b *bus) ReadByte(addr byte) (value byte, err error) {
b.mu.Lock()
defer b.mu.Unlock()
@ -129,7 +132,6 @@ func (b *bus) ReadByte(addr byte) (value byte, err error) {
return
}
// Write a byte to the given address.
func (b *bus) WriteByte(addr, value byte) (err error) {
b.mu.Lock()
defer b.mu.Unlock()
@ -147,7 +149,6 @@ func (b *bus) WriteByte(addr, value byte) (err error) {
return
}
// Write a bunch of bytes ot the given address.
func (b *bus) WriteBytes(addr byte, value []byte) error {
b.mu.Lock()
defer b.mu.Unlock()
@ -172,7 +173,6 @@ func (b *bus) WriteBytes(addr byte, value []byte) error {
return nil
}
// Read a bunch of bytes (len(value)) from the given address and register.
func (b *bus) ReadFromReg(addr, reg byte, value []byte) (err error) {
b.mu.Lock()
defer b.mu.Unlock()
@ -206,7 +206,6 @@ func (b *bus) ReadFromReg(addr, reg byte, value []byte) (err error) {
return nil
}
// Read a byte from the given address and register.
func (b *bus) ReadByteFromReg(addr, reg byte) (value byte, err error) {
buf := make([]byte, 1)
if err = b.ReadFromReg(addr, reg, buf); err != nil {
@ -216,18 +215,16 @@ func (b *bus) ReadByteFromReg(addr, reg byte) (value byte, err error) {
return
}
// Read a int from the given address and register.
func (b *bus) ReadInt(addr, reg byte) (value int, err error) {
var buf = make([]byte, 2)
func (b *bus) ReadWordFromReg(addr, reg byte) (value uint16, err error) {
buf := make([]byte, 2)
if err = b.ReadFromReg(addr, reg, buf); err != nil {
return
}
value = int((int(buf[0]) << 8) | int(buf[1]))
value = uint16((uint16(buf[0]) << 8) | uint16(buf[1]))
return
}
// Write a byte to the given address and register.
func (b *bus) WriteToReg(addr, reg, value byte) (err error) {
func (b *bus) WriteToReg(addr, reg byte, value []byte) (err error) {
b.mu.Lock()
defer b.mu.Unlock()
@ -235,16 +232,81 @@ func (b *bus) WriteToReg(addr, reg, value byte) (err error) {
return
}
var outbuf [2]byte
outbuf := append([]byte{reg}, value...)
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&outbuf))
var message i2c_msg
message.addr = uint16(addr)
message.flags = 0
message.len = uint16(len(outbuf))
message.buf = uintptr(unsafe.Pointer(&hdrp.Data))
var packets i2c_rdwr_ioctl_data
packets.msgs = uintptr(unsafe.Pointer(&message))
packets.nmsg = 1
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
err = syscall.Errno(errno)
return
}
return
}
func (b *bus) WriteByteToReg(addr, reg, value byte) (err error) {
b.mu.Lock()
defer b.mu.Unlock()
if err = b.setAddress(addr); err != nil {
return
}
outbuf := [...]byte{
reg,
value,
}
var message i2c_msg
message.addr = uint16(addr)
message.flags = 0
message.len = uint16(len(outbuf))
message.buf = uintptr(unsafe.Pointer(&outbuf))
var packets i2c_rdwr_ioctl_data
packets.msgs = uintptr(unsafe.Pointer(&message))
packets.nmsg = 1
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
err = syscall.Errno(errno)
return
}
return
}
func (b *bus) WriteWordToReg(addr, reg byte, value uint16) (err error) {
b.mu.Lock()
defer b.mu.Unlock()
if err = b.setAddress(addr); err != nil {
return
}
outbuf := [...]byte{
reg,
byte(value >> 8),
byte(value),
}
var messages i2c_msg
messages.addr = uint16(addr)
messages.flags = 0
messages.len = uint16(len(outbuf))
messages.buf = uintptr(unsafe.Pointer(&outbuf))
outbuf[0] = reg
outbuf[1] = value
var packets i2c_rdwr_ioctl_data
packets.msgs = uintptr(unsafe.Pointer(&messages))
@ -258,37 +320,47 @@ func (b *bus) WriteToReg(addr, reg, value byte) (err error) {
return
}
// Read a byte from the given address.
// ReadByte reads a byte from the given address.
func ReadByte(addr byte) (value byte, err error) {
return Default.ReadByte(addr)
}
// Write a byte to the given address.
func WriteByte(addr, value byte) (err error) {
// WriteByte writes a byte to the given address.
func WriteByte(addr, value byte) error {
return Default.WriteByte(addr, value)
}
// Write a bunch of bytes ot the given address.
// WriteBytes writes a slice bytes to the given address.
func WriteBytes(addr byte, value []byte) error {
return Default.WriteBytes(addr, value)
}
// Read a bunch of bytes (len(value)) from the given address and register.
func ReadFromReg(addr, reg byte, value []byte) (err error) {
// ReadFromReg reads n (len(value)) bytes from the given address and register.
func ReadFromReg(addr, reg byte, value []byte) error {
return Default.ReadFromReg(addr, reg, value)
}
// Read a byte from the given address and register.
// ReadByteFromReg reads a byte from the given address and register.
func ReadByteFromReg(addr, reg byte) (value byte, err error) {
return Default.ReadByteFromReg(addr, reg)
}
// Read a int from the given address and register.
func ReadInt(addr, reg byte) (value int, err error) {
return Default.ReadInt(addr, reg)
// ReadU16FromReg reads a unsigned 16 bit integer from the given address and register.
func ReadWordFromReg(addr, reg byte) (value uint16, err error) {
return Default.ReadWordFromReg(addr, reg)
}
// Write a byte to the given address and register.
func WriteToReg(addr, reg, value byte) (err error) {
// WriteToReg writes len(value) bytes to the given address and register.
func WriteToReg(addr, reg byte, value []byte) error {
return Default.WriteToReg(addr, reg, value)
}
// WriteByteToReg writes a byte to the given address and register.
func WriteByteToReg(addr, reg, value byte) error {
return Default.WriteByteToReg(addr, reg, value)
}
// WriteU16ToReg
func WriteWordToReg(addr, reg byte, value uint16) error {
return Default.WriteWordToReg(addr, reg, value)
}

View File

@ -14,11 +14,11 @@ func main() {
log.Panic(err)
}
lightingSensor := bh1750fvi.New(bh1750fvi.High, bus)
defer lightingSensor.Close()
sensor := bh1750fvi.New(bh1750fvi.High, bus)
defer sensor.Close()
for {
lighting, err := lightingSensor.Lighting()
lighting, err := sensor.Lighting()
if err != nil {
log.Panic(err)
}

41
samples/tmp006.go Normal file
View File

@ -0,0 +1,41 @@
package main
import (
"log"
"os"
"os/signal"
"github.com/kid0m4n/go-rpi/i2c"
"github.com/kid0m4n/go-rpi/sensor/tmp006"
)
func main() {
bus, err := i2c.NewBus(1)
if err != nil {
log.Panic(err)
}
sensor := tmp006.New(bus, 0x40)
if status, err := sensor.Present(); err != nil || !status {
log.Print("tmp006: not found")
log.Print(err)
return
}
defer sensor.Close()
sensor.Start()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, os.Kill)
for {
select {
case temp := <-sensor.ObjTemps():
log.Printf("tmp006: got obj temp %.2f", temp)
case temp := <-sensor.RawDieTemps():
log.Printf("tmp006: got die temp %.2f", temp)
case <-stop:
return
}
}
}

View File

@ -90,12 +90,12 @@ func (d *bh1750fvi) measureLighting() (lighting float64, err error) {
}
time.Sleep(180 * time.Millisecond)
var sensorReading int
if sensorReading, err = d.bus.ReadInt(d.i2cAddr, defReadReg); err != nil {
var reading uint16
if reading, err = d.bus.ReadWordFromReg(d.i2cAddr, defReadReg); err != nil {
return
}
lighting = float64(sensorReading) / measurementAcuuracy
lighting = float64(int16(reading)) / measurementAcuuracy
return
}

View File

@ -102,8 +102,8 @@ func (d *bmp085) calibrate() (err error) {
defer d.cmu.Unlock()
readInt16 := func(reg byte) (value int16, err error) {
var v int
if v, err = d.bus.ReadInt(address, reg); err != nil {
var v uint16
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
return
}
value = int16(v)
@ -111,8 +111,8 @@ func (d *bmp085) calibrate() (err error) {
}
readUInt16 := func(reg byte) (value uint16, err error) {
var v int
if v, err = d.bus.ReadInt(address, reg); err != nil {
var v uint16
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
return
}
value = uint16(v)
@ -185,16 +185,13 @@ func (d *bmp085) calibrate() (err error) {
}
func (d *bmp085) readUncompensatedTemp() (temp uint16, err error) {
if err = d.bus.WriteToReg(address, control, readTempCmd); err != nil {
if err = d.bus.WriteByteToReg(address, control, readTempCmd); err != nil {
return
}
time.Sleep(tempReadDelay)
var t int
t, err = d.bus.ReadInt(address, tempData)
if err != nil {
if temp, err = d.bus.ReadWordFromReg(address, tempData); err != nil {
return
}
temp = uint16(t)
return
}
@ -250,7 +247,7 @@ func (d *bmp085) Temperature() (temp float64, err error) {
}
func (d *bmp085) readUncompensatedPressure() (pressure uint32, err error) {
if err = d.bus.WriteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
if err = d.bus.WriteByteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
return
}
time.Sleep(time.Duration(2+(3<<d.oss)) * time.Millisecond)

View File

@ -102,8 +102,8 @@ func (d *bmp180) calibrate() (err error) {
defer d.cmu.Unlock()
readInt16 := func(reg byte) (value int16, err error) {
var v int
if v, err = d.bus.ReadInt(address, reg); err != nil {
var v uint16
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
return
}
value = int16(v)
@ -111,8 +111,8 @@ func (d *bmp180) calibrate() (err error) {
}
readUInt16 := func(reg byte) (value uint16, err error) {
var v int
if v, err = d.bus.ReadInt(address, reg); err != nil {
var v uint16
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
return
}
value = uint16(v)
@ -185,16 +185,13 @@ func (d *bmp180) calibrate() (err error) {
}
func (d *bmp180) readUncompensatedTemp() (temp uint16, err error) {
if err = d.bus.WriteToReg(address, control, readTempCmd); err != nil {
if err = d.bus.WriteByteToReg(address, control, readTempCmd); err != nil {
return
}
time.Sleep(tempReadDelay)
var t int
t, err = d.bus.ReadInt(address, tempData)
if err != nil {
if temp, err = d.bus.ReadWordFromReg(address, tempData); err != nil {
return
}
temp = uint16(t)
return
}
@ -250,7 +247,7 @@ func (d *bmp180) Temperature() (temp float64, err error) {
}
func (d *bmp180) readUncompensatedPressure() (pressure uint32, err error) {
if err = d.bus.WriteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
if err = d.bus.WriteByteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
return
}
time.Sleep(time.Duration(2+(3<<d.oss)) * time.Millisecond)

View File

@ -213,10 +213,10 @@ func (d *l3gd20) setup() (err error) {
d.mu.Lock()
defer d.mu.Unlock()
if err = d.bus.WriteToReg(address, ctrlReg1, ctrlReg1Default); err != nil {
if err = d.bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Default); err != nil {
return
}
if err = d.bus.WriteToReg(address, ctrlReg4, d.rng.value); err != nil {
if err = d.bus.WriteByteToReg(address, ctrlReg4, d.rng.value); err != nil {
return
}
@ -370,5 +370,5 @@ func (d *l3gd20) Close() (err error) {
if d.quit != nil {
d.quit <- struct{}{}
}
return d.bus.WriteToReg(address, ctrlReg1, ctrlReg1Finished)
return d.bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Finished)
}

View File

@ -52,7 +52,7 @@ type LSM303 interface {
// Run starts the sensor data acquisition loop.
Run() error
// Close closes the sensor data acquisition loop and put the LSM303 into sleep mode.
// Close closes the sensor data acquisition loop and puts the LSM303 into sleep mode.
Close() error
}
@ -91,10 +91,10 @@ func (d *lsm303) setup() (err error) {
d.mu.Lock()
defer d.mu.Unlock()
if err = d.bus.WriteToReg(magAddress, magConfigRegA, MagCRADefault); err != nil {
if err = d.bus.WriteByteToReg(magAddress, magConfigRegA, MagCRADefault); err != nil {
return
}
if err = d.bus.WriteToReg(magAddress, magModeReg, MagMRDefault); err != nil {
if err = d.bus.WriteByteToReg(magAddress, magModeReg, MagMRDefault); err != nil {
return
}
@ -182,7 +182,7 @@ func (d *lsm303) Close() (err error) {
if d.quit != nil {
d.quit <- struct{}{}
}
err = d.bus.WriteToReg(magAddress, magModeReg, MagSleep)
err = d.bus.WriteByteToReg(magAddress, magModeReg, MagSleep)
return
}

336
sensor/tmp006/tmp006.go Normal file
View File

@ -0,0 +1,336 @@
package tmp006
import (
"errors"
"fmt"
"log"
"math"
"sync"
"time"
"github.com/kid0m4n/go-rpi/i2c"
)
const (
b0 = -0.0000294
b1 = -0.00000057
b2 = 0.00000000463
c2 = 13.4
tref = 298.15
a2 = -0.00001678
a1 = 0.00175
s0 = 6.4
vObjReg = 0x00
tempAmbReg = 0x01
configReg = 0x02
manIdReg = 0xFE
manId = 0x5449
devIdReg = 0xFF
devId = 0x0067
reset = 0x8000
modeOn = 0x7000
drdyEn = 0x0100
configRegDefault = modeOn | drdyEn
)
type SampleRate struct {
enabler uint16
samples int
timeRequired float64
}
var (
SR1 = &SampleRate{0x0000, 1, 0.25} // 1 sample, 0.25 second between measurements.
SR2 = &SampleRate{0x0200, 2, 0.5} // 2 samples, 0.5 second between measurements.
SR4 = &SampleRate{0x0400, 4, 1} // 4 samples, 1 second between measurements.
SR8 = &SampleRate{0x0600, 8, 2} // 8 samples, 2 seconds between measurements.
SR16 = &SampleRate{0x0800, 16, 4} // 16 samples, 4 seconds between measurements.
)
// Device represents a TMP006 thermopile sensor.
type Device struct {
// Bus to communicate over.
Bus i2c.Bus
// Addr of the sensor.
Addr byte
// Debug turns on additional debug output.
Debug bool
// SampleRate specifies the sampling rate for the sensor.
SampleRate *SampleRate
initialized bool
mu sync.RWMutex
rawDieTemps chan float64
objTemps chan float64
closing chan chan struct{}
}
// New creates a new TMP006 sensor.
func New(bus i2c.Bus, addr byte) *Device {
return &Device{
Bus: bus,
Addr: addr,
}
}
func (d *Device) validate() error {
if d.Bus == nil {
return errors.New("tmp006: bus is nil")
}
if d.Addr == 0x00 {
return fmt.Errorf("tmp006: %#x is not a valid address", d.Addr)
}
return nil
}
// Close puts the device into low power mode.
func (d *Device) Close() (err error) {
if err = d.setup(); err != nil {
return
}
if d.closing != nil {
waitc := make(chan struct{})
d.closing <- waitc
<-waitc
}
if d.Debug {
log.Print("tmp006: resetting")
}
if err = d.Bus.WriteWordToReg(d.Addr, configReg, reset); err != nil {
return
}
return
}
// Present checks if the device is present at the given address.
func (d *Device) Present() (status bool, err error) {
if err = d.validate(); err != nil {
return
}
var mid, did uint16
if mid, err = d.Bus.ReadWordFromReg(d.Addr, manIdReg); err != nil {
return
}
if d.Debug {
log.Printf("tmp006: got manufacturer id %#04x", mid)
}
if mid != manId {
err = fmt.Errorf("tmp006: not found at %#02x, manufacturer id mismatch", d.Addr)
return
}
if did, err = d.Bus.ReadWordFromReg(d.Addr, devIdReg); err != nil {
return
}
if d.Debug {
log.Printf("tmp006: got device id %#04x", did)
}
if did != devId {
err = fmt.Errorf("tmp006: not found at %#02x, device id mismatch", d.Addr)
return
}
status = true
return
}
func (d *Device) setup() (err error) {
d.mu.RLock()
if d.initialized {
d.mu.RUnlock()
return
}
d.mu.RUnlock()
d.mu.Lock()
defer d.mu.Unlock()
if err = d.validate(); err != nil {
return
}
if d.SampleRate == nil {
if d.Debug {
log.Printf("tmp006: sample rate = nil, using SR16")
}
d.SampleRate = SR16
}
if d.Debug {
log.Printf("tmp006: configuring with %#04x", configRegDefault|d.SampleRate.enabler)
}
if err = d.Bus.WriteWordToReg(d.Addr, configReg, configRegDefault|d.SampleRate.enabler); err != nil {
return
}
d.initialized = true
return
}
func (d *Device) measureRawDieTemp() (temp float64, err error) {
if err = d.setup(); err != nil {
return
}
var raw uint16
if raw, err = d.Bus.ReadWordFromReg(d.Addr, tempAmbReg); err != nil {
return
}
raw >>= 2
if d.Debug {
log.Printf("tmp006: raw die temp %#04x", raw)
}
temp = float64(int16(raw)) * 0.03125
return
}
func (d *Device) measureRawVoltage() (volt int16, err error) {
if err = d.setup(); err != nil {
return
}
var vlt uint16
if vlt, err = d.Bus.ReadWordFromReg(d.Addr, vObjReg); err != nil {
return
}
volt = int16(vlt)
if d.Debug {
log.Printf("tmp006: raw voltage %#04x", volt)
}
return
}
func (d *Device) measureObjTemp() (temp float64, err error) {
if err = d.setup(); err != nil {
return
}
tDie, err := d.measureRawDieTemp()
if err != nil {
return
}
if d.Debug {
log.Printf("tmp006: tdie = %.2f C", tDie)
}
tDie += 273.15 // Convert to K
vo, err := d.measureRawVoltage()
if err != nil {
return
}
vObj := float64(vo)
vObj *= 156.25 // 156.25 nV per LSB
vObj /= 1000 // nV -> uV
if d.Debug {
log.Printf("tmp006: vObj = %.5f uV", vObj)
}
vObj /= 1000 // uV -> mV
vObj /= 1000 // mV -> V
tdie_tref := tDie - tref
s := 1 + a1*tdie_tref + a2*tdie_tref*tdie_tref
s *= s0
s /= 10000000
s /= 10000000
Vos := b0 + b1*tdie_tref + b2*tdie_tref*tdie_tref
fVobj := (vObj - Vos) + c2*(vObj-Vos)*(vObj-Vos)
temp = math.Sqrt(math.Sqrt(tDie*tDie*tDie*tDie + fVobj/s))
temp -= 273.15
return
}
// RawDieTemp returns the current raw die temp reading.
func (d *Device) RawDieTemp() (temp float64, err error) {
select {
case temp = <-d.rawDieTemps:
return
default:
return d.measureRawDieTemp()
}
}
// RawDieTemps returns a channel to get future raw die temps from.
func (d *Device) RawDieTemps() <-chan float64 {
return d.rawDieTemps
}
// ObjTemp returns the current obj temp reading.
func (d *Device) ObjTemp() (temp float64, err error) {
select {
case temp = <-d.objTemps:
return
default:
return d.measureObjTemp()
}
}
// ObjTemps returns a channel to fetch obj temps from.
func (d *Device) ObjTemps() <-chan float64 {
return d.objTemps
}
// Start starts the data acquisition loop.
func (d *Device) Start() (err error) {
if err = d.setup(); err != nil {
return
}
d.rawDieTemps = make(chan float64)
d.objTemps = make(chan float64)
go func() {
var rawDieTemp, objTemp float64
var rdtAvlb, otAvlb bool
var err error
var timer <-chan time.Time
resetTimer := func() {
timer = time.After(time.Duration(d.SampleRate.timeRequired*1000) * time.Millisecond)
}
resetTimer()
for {
var rawDieTemps, objTemps chan float64
if rdtAvlb {
rawDieTemps = d.rawDieTemps
}
if otAvlb {
objTemps = d.objTemps
}
select {
case <-timer:
var rdt float64
if rdt, err = d.measureRawDieTemp(); err != nil {
log.Printf("tmp006: %v", err)
} else {
rawDieTemp = rdt
rdtAvlb = true
}
var ot float64
if ot, err = d.measureObjTemp(); err != nil {
log.Printf("tmp006: %v", err)
} else {
objTemp = ot
otAvlb = true
}
resetTimer()
case rawDieTemps <- rawDieTemp:
rdtAvlb = false
case objTemps <- objTemp:
otAvlb = false
case waitc := <-d.closing:
waitc <- struct{}{}
close(d.rawDieTemps)
close(d.objTemps)
return
}
}
}()
return
}