From 0563d2be5c98ee652e8cd3a979040cb9de9a1b2e Mon Sep 17 00:00:00 2001 From: Karan Misra Date: Sun, 5 Jan 2014 14:27:29 +0530 Subject: [PATCH] - add support for tmp006 - refactor the i2c interface --- i2c/i2c.go | 146 +++++++++++---- samples/bh1750fvi.go | 6 +- samples/tmp006.go | 41 +++++ sensor/bh1750fvi/bh1750fvi.go | 6 +- sensor/bmp085/bmp085.go | 17 +- sensor/bmp180/bmp180.go | 17 +- sensor/l3gd20/l3gd20.go | 6 +- sensor/lsm303/lsm303.go | 8 +- sensor/tmp006/tmp006.go | 336 ++++++++++++++++++++++++++++++++++ 9 files changed, 513 insertions(+), 70 deletions(-) create mode 100644 samples/tmp006.go create mode 100644 sensor/tmp006/tmp006.go diff --git a/i2c/i2c.go b/i2c/i2c.go index 8926b2a..26fcf20 100644 --- a/i2c/i2c.go +++ b/i2c/i2c.go @@ -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) +} diff --git a/samples/bh1750fvi.go b/samples/bh1750fvi.go index 50dc54d..2717caf 100644 --- a/samples/bh1750fvi.go +++ b/samples/bh1750fvi.go @@ -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) } diff --git a/samples/tmp006.go b/samples/tmp006.go new file mode 100644 index 0000000..6c23729 --- /dev/null +++ b/samples/tmp006.go @@ -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 + } + } +} diff --git a/sensor/bh1750fvi/bh1750fvi.go b/sensor/bh1750fvi/bh1750fvi.go index 93c8d50..ac5eae6 100644 --- a/sensor/bh1750fvi/bh1750fvi.go +++ b/sensor/bh1750fvi/bh1750fvi.go @@ -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 } diff --git a/sensor/bmp085/bmp085.go b/sensor/bmp085/bmp085.go index 7822a5c..411ffcd 100644 --- a/sensor/bmp085/bmp085.go +++ b/sensor/bmp085/bmp085.go @@ -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<>= 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 +}