diff --git a/Makefile b/Makefile index ea7ae48..b5e74e2 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ smoke-test: tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/lis3dh/main.go tinygo build -size short -o ./build/test.elf -target=arduino-nano33 ./examples/lsm6ds3/main.go tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/mag3110/main.go + tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/mcp3008/main.go tinygo build -size short -o ./build/test.elf -target=microbit ./examples/microbitmatrix/main.go tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/mma8653/main.go tinygo build -size short -o ./build/test.elf -target=itsybitsy-m0 ./examples/mpu6050/main.go diff --git a/README.md b/README.md index c428dc2..fa1479d 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ func main() { ## Currently supported devices +The following 34 devices are supported. + | Device Name | Interface Type | |----------|-------------| | [ADXL345 accelerometer](http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf) | I2C | @@ -71,6 +73,7 @@ func main() { | [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C | | [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) | I2C | | [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C | +| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI | | [BBC micro:bit LED matrix](https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf) | GPIO | | [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM | | [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C | diff --git a/examples/mcp3008/main.go b/examples/mcp3008/main.go new file mode 100644 index 0000000..fdef3c7 --- /dev/null +++ b/examples/mcp3008/main.go @@ -0,0 +1,32 @@ +// Connects to a MCP3008 ADC via SPI. +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/mcp3008" +) + +var ( + spi = machine.SPI0 + csPin = machine.D12 +) + +func main() { + spi.Configure(machine.SPIConfig{ + Frequency: 4000000, + Mode: 3}) + + adc := mcp3008.New(spi, csPin) + adc.Configure() + + // get "CH0" aka "machine.ADC" interface to channel 0 from ADC. + p := adc.CH0 + + for { + val := p.Get() + println(val) + time.Sleep(50 * time.Millisecond) + } +} diff --git a/mcp3008/mcp3008.go b/mcp3008/mcp3008.go new file mode 100644 index 0000000..799c52b --- /dev/null +++ b/mcp3008/mcp3008.go @@ -0,0 +1,92 @@ +// Package mcp3008 implements a driver for the MCP3008 Analog to Digital Converter. +// +// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf +// +package mcp3008 // import "tinygo.org/x/drivers/mcp3008" + +import ( + "errors" + "machine" +) + +// Device wraps MCP3008 SPI ADC. +type Device struct { + bus machine.SPI + cs machine.Pin + tx []byte + rx []byte + CH0 ADCPin + CH1 ADCPin + CH2 ADCPin + CH3 ADCPin + CH4 ADCPin + CH5 ADCPin + CH6 ADCPin + CH7 ADCPin +} + +// ADCPin is the implementation of the ADConverter interface. +type ADCPin struct { + machine.Pin + d *Device +} + +// New returns a new MCP3008 driver. Pass in a fully configured SPI bus. +func New(b machine.SPI, csPin machine.Pin) *Device { + d := &Device{bus: b, + cs: csPin, + tx: make([]byte, 3), + rx: make([]byte, 3), + } + + // setup all channels + d.CH0 = d.GetADC(0) + d.CH1 = d.GetADC(1) + d.CH2 = d.GetADC(2) + d.CH3 = d.GetADC(3) + d.CH4 = d.GetADC(4) + d.CH5 = d.GetADC(5) + d.CH6 = d.GetADC(6) + d.CH7 = d.GetADC(7) + + return d +} + +// Configure sets up the device for communication +func (d *Device) Configure() { + d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput}) +} + +// Read analog data from channel +func (d *Device) Read(ch int) (uint16, error) { + if ch < 0 || ch > 7 { + return 0, errors.New("invalid channel for MCP3008 Read") + } + + return d.GetADC(ch).Get(), nil +} + +// GetADC returns an ADC for a specific channel. +func (d *Device) GetADC(ch int) ADCPin { + return ADCPin{machine.Pin(ch), d} +} + +// Get the current reading for a specific ADCPin. +func (p ADCPin) Get() uint16 { + p.d.tx[0] = 0x01 + p.d.tx[1] = byte(8+p.Pin) << 4 + p.d.tx[2] = 0x00 + + p.d.cs.Low() + p.d.bus.Tx(p.d.tx, p.d.rx) + + // scale result to 16bit value like other ADCs + result := uint16((p.d.rx[1]&0x3))<<8 + uint16(p.d.rx[2])<<6 + p.d.cs.High() + + return result +} + +// Configure here just for interface compatibility. +func (p ADCPin) Configure() { +}