From 2a621dc3b16c6ed1a62ca09da422f146360222e6 Mon Sep 17 00:00:00 2001 From: gmsec <18008688+gmonarque@users.noreply.github.com> Date: Sun, 12 May 2024 10:42:03 +0200 Subject: [PATCH] Add driver for MCP9808 i2c temperature sensor (#676) mcp9808: add support for temperature sensor --- examples/mcp9808/main.go | 48 ++++++++++++++++++++ go.mod | 2 + mcp9808/mcp9808.go | 98 ++++++++++++++++++++++++++++++++++++++++ mcp9808/registers.go | 53 ++++++++++++++++++++++ smoketest.sh | 1 + 5 files changed, 202 insertions(+) create mode 100644 examples/mcp9808/main.go create mode 100644 mcp9808/mcp9808.go create mode 100644 mcp9808/registers.go diff --git a/examples/mcp9808/main.go b/examples/mcp9808/main.go new file mode 100644 index 0000000..7b2c5ea --- /dev/null +++ b/examples/mcp9808/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "machine" + "time" + + "tinygo.org/x/drivers/mcp9808" +) + +func main() { + + //tinygo monitor + time.Sleep(time.Millisecond * 5000) + + //Configure I2C (in this case, I2C0 on RPI Pico), and wire the module accordingly + machine.I2C0.Configure(machine.I2CConfig{ + SCL: machine.GP1, + SDA: machine.GP0, + }) + + //Create sensor + sensor := mcp9808.New(machine.I2C0) + if !sensor.Connected() { + println("MCP9808 not found") + return + } else { + println("MCP9808 found") + } + + time.Sleep(time.Millisecond * 1000) + + //Set resolution + sensor.SetResolution(mcp9808.Maximum) + + time.Sleep(time.Millisecond * 1000) + + //Read temp. + temp, err := sensor.ReadTemperature() + if err != nil { + println("MCP9808 error reading temperature") + println(err.Error()) + return + } else { + fmt.Printf("Temperature: %.2f \n", temp) + } + return +} diff --git a/go.mod b/go.mod index 0fa3076..366deda 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module tinygo.org/x/drivers go 1.18 +replace tinygo.org/x/drivers/mcp9808 => /home/kasterby/Documents/drivers/mcp9808 + require ( github.com/eclipse/paho.mqtt.golang v1.2.0 github.com/frankban/quicktest v1.10.2 diff --git a/mcp9808/mcp9808.go b/mcp9808/mcp9808.go new file mode 100644 index 0000000..a4ec998 --- /dev/null +++ b/mcp9808/mcp9808.go @@ -0,0 +1,98 @@ +// Package mcp9808 implements a driver for the MCP9808 High Accuracy I2C Temperature Sensor +// +// Datasheet: https://cdn-shop.adafruit.com/datasheets/MCP9808.pdf +// Module: https://www.adafruit.com/product/1782 +// Only implemented: temperature reading, resolution read & set +package mcp9808 + +import ( + "encoding/binary" + "errors" + + "tinygo.org/x/drivers" +) + +type Device struct { + bus drivers.I2C + Address uint16 +} + +func New(bus drivers.I2C) Device { + return Device{bus, MCP9808_I2CADDR_DEFAULT} +} + +func (d *Device) Connected() bool { + data := make([]byte, 2) + d.Read(MCP9808_REG_DEVICE_ID, &data) + return binary.BigEndian.Uint16(data) == MCP9808_DEVICE_ID +} + +func (d *Device) ReadTemperature() (float64, error) { + data := make([]byte, 2) + var temp float64 + if err := d.Read(MCP9808_REG_AMBIENT_TEMP, &data); err != nil { + return 0, err + } + + data[0] = data[0] & 0x1F + if data[0]&0x10 == 0x10 { + data[0] = data[0] & 0x0F + temp = float64(data[0])*16 + float64(data[1])/16.0 - 256 + } + temp = float64(data[0])*16 + float64(data[1])/16.0 + return temp, nil +} + +func (d *Device) ReadResolution() (resolution, error) { + data := make([]byte, 2) + err := d.Read(MCP9808_REG_RESOLUTION, &data) + if err != nil { + return 0, err + } + switch data[0] { + case 0: + return Low, nil + case 1: + return Medium, nil + case 2: + return High, nil + case 3: + return Maximum, nil + + default: + return 0, errors.New("unknown resolution") + } +} + +func (d *Device) SetResolution(r resolution) error { + switch r { + case Low: + if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x00}); err != nil { + return err + } + case Medium: + if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x01}); err != nil { + return err + } + case High: + if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x02}); err != nil { + return err + } + case Maximum: + if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x03}); err != nil { + return err + } + default: + return nil + } + return nil +} + +func (d *Device) Write(register byte, data []byte) error { + buf := append([]byte{register}, data...) + return d.bus.Tx(d.Address, buf, nil) +} + +func (d *Device) Read(register byte, data *[]byte) error { + return d.bus.Tx(d.Address, []byte{register}, *data) +} diff --git a/mcp9808/registers.go b/mcp9808/registers.go new file mode 100644 index 0000000..a66d094 --- /dev/null +++ b/mcp9808/registers.go @@ -0,0 +1,53 @@ +// Package mcp9808 implements a driver for the MCP9808 High Accuracy I2C Temperature Sensor +// +// Datasheet: https://cdn-shop.adafruit.com/datasheets/MCP9808.pdf +// Module: https://www.adafruit.com/product/1782 +package mcp9808 + +// Constants/addresses used for I2C. +const ( + MCP9808_DEVICE_ID = 0x0400 + MCP9808_MANUF_ID = 0x0054 + + MCP9808_I2CADDR_DEFAULT = 0x18 //default I2C address + MCP9808_REG_CONFIG = 0x01 //MCP9808 config register + + MCP9808_REG_CONFIG_SHUTDOWN = 0x0100 //shutdown config + MCP9808_REG_CONFIG_CRITLOCKED = 0x0080 //critical trip lock + MCP9808_REG_CONFIG_WINLOCKED = 0x0040 //alarm window lock + MCP9808_REG_CONFIG_INTCLR = 0x0020 //interrupt clear + MCP9808_REG_CONFIG_ALERTSTAT = 0x0010 //alert output status + MCP9808_REG_CONFIG_ALERTCTRL = 0x0008 //alert output control + MCP9808_REG_CONFIG_ALERTSEL = 0x0004 //alert output select + MCP9808_REG_CONFIG_ALERTPOL = 0x0002 //alert output polarity + MCP9808_REG_CONFIG_ALERTMODE = 0x0001 //alert output mode + + MCP9808_REG_UPPER_TEMP = 0x02 //upper alert boundary + MCP9808_REG_LOWER_TEMP = 0x03 //lower alert boundery + MCP9808_REG_CRIT_TEMP = 0x04 //critical temperature + MCP9808_REG_AMBIENT_TEMP = 0x05 //ambient temperature + MCP9808_REG_MANUF_ID = 0x06 //manufacturer ID + MCP9808_REG_DEVICE_ID = 0x07 //device ID + MCP9808_REG_RESOLUTION = 0x08 //resolution +) + +/* +======= ============ ============== +value resolution reading Time +======= ============ ============== + + 0 0.5°C 30 ms + 1 0.25°C 65 ms + 2 0.125°C 130 ms + 3 0.0625°C 250 ms + +======= ============ ============== +*/ +type resolution uint8 + +const ( + Low resolution = iota + Medium + High + Maximum +) diff --git a/smoketest.sh b/smoketest.sh index b7530b2..a10c9fe 100755 --- a/smoketest.sh +++ b/smoketest.sh @@ -130,6 +130,7 @@ tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/n tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/main.go tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/sh1106/macropad_spi tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/encoders/quadrature-interrupt +tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mcp9808/main.go # network examples (espat) tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/ # network examples (wifinina)