mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-18 13:43:58 +00:00
mcp23017: implement pin toggling
Also add an example for using multiple devices.
This commit is contained in:
@@ -85,6 +85,8 @@ smoke-test:
|
|||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017-multiple/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// This example demonstrates putting several mcp23017 devices together into
|
||||||
|
// a single virtual I/O array.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/mcp23017"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := machine.I2C0.Configure(machine.I2CConfig{
|
||||||
|
Frequency: machine.TWI_FREQ_400KHZ,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Assume the devices are at addresses 0x20, 0x21
|
||||||
|
dev, err := mcp23017.NewI2CDevices(machine.I2C0, 0x20, 0x21)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Configure pin 0 for input and all the others for output.
|
||||||
|
if err := dev.SetModes([]mcp23017.PinMode{
|
||||||
|
mcp23017.Input | mcp23017.Pullup,
|
||||||
|
mcp23017.Output,
|
||||||
|
}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
input := dev.Pin(0)
|
||||||
|
// Make a mask that represents all the output pins.
|
||||||
|
// Note that this leverages the driver behaviour which replicates the highest bit in
|
||||||
|
// the last slice element (1 in this case) to all other pins
|
||||||
|
outputMask := mcp23017.PinSlice{^mcp23017.Pins(1 << 0)} // All except pin 0
|
||||||
|
inputVal, err := input.Get()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
println("input value: ", inputVal)
|
||||||
|
// Set the values of all the output pins.
|
||||||
|
err = dev.SetPins(mcp23017.PinSlice{0b1011011_01101110, 0b11111101_11100110}, outputMask)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -154,6 +154,15 @@ func (d *Device) SetPins(pins, mask Pins) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TogglePins inverts the values on all pins for
|
||||||
|
// which mask is high.
|
||||||
|
func (d *Device) TogglePins(mask Pins) error {
|
||||||
|
if mask == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.SetPins(^d.pins, mask)
|
||||||
|
}
|
||||||
|
|
||||||
// Pin returns a Pin representing the given pin number (from 0 to 15).
|
// Pin returns a Pin representing the given pin number (from 0 to 15).
|
||||||
// Pin numbers from 0 to 7 represent port A pins 0 to 7.
|
// Pin numbers from 0 to 7 represent port A pins 0 to 7.
|
||||||
// Pin numbers from 8 to 15 represent port B pins 0 to 7.
|
// Pin numbers from 8 to 15 represent port B pins 0 to 7.
|
||||||
@@ -295,6 +304,11 @@ func (p Pin) Low() error {
|
|||||||
return p.Set(false)
|
return p.Set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle inverts the value output on the pin.
|
||||||
|
func (p Pin) Toggle() error {
|
||||||
|
return p.dev.TogglePins(p.mask)
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns the current value of the given pin.
|
// Get returns the current value of the given pin.
|
||||||
func (p Pin) Get() (bool, error) {
|
func (p Pin) Get() (bool, error) {
|
||||||
// TODO this reads 2 registers when we could read just one.
|
// TODO this reads 2 registers when we could read just one.
|
||||||
@@ -357,6 +371,11 @@ func (p *Pins) Low(pin int) {
|
|||||||
*p &^= pinMask(pin)
|
*p &^= pinMask(pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle inverts the value of the given pin.
|
||||||
|
func (p *Pins) Toggle(pin int) {
|
||||||
|
*p ^= pinMask(pin)
|
||||||
|
}
|
||||||
|
|
||||||
func pinMask(pin int) Pins {
|
func pinMask(pin int) Pins {
|
||||||
return 1 << pin
|
return 1 << pin
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,25 @@ func TestSetPins(t *testing.T) {
|
|||||||
c.Assert(pins, qt.Equals, Pins(0b01010000_00011010))
|
c.Assert(pins, qt.Equals, Pins(0b01010000_00011010))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTogglePins(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := newBus(c)
|
||||||
|
fdev := bus.addDevice(0x20)
|
||||||
|
fdev.Registers[rGPIO] = 0b00001111
|
||||||
|
fdev.Registers[rGPIO|portB] = 0b11110000
|
||||||
|
dev, err := NewI2C(bus, 0x20)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
pins, err := dev.GetPins()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(pins, qt.Equals, Pins(0b11110000_00001111))
|
||||||
|
|
||||||
|
err = dev.TogglePins(0b10101010_01010101)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
pins, err = dev.GetPins()
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(pins, qt.Equals, Pins(0b01011010_01011010))
|
||||||
|
}
|
||||||
|
|
||||||
func TestSetGetModes(t *testing.T) {
|
func TestSetGetModes(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
bus := newBus(c)
|
bus := newBus(c)
|
||||||
@@ -108,6 +127,24 @@ func TestPinSetGet(t *testing.T) {
|
|||||||
c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0))
|
c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPinToggle(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := newBus(c)
|
||||||
|
fdev := bus.addDevice(0x20)
|
||||||
|
dev, err := NewI2C(bus, 0x20)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
pin := dev.Pin(1)
|
||||||
|
v, err := pin.Get()
|
||||||
|
c.Assert(err, qt.Equals, nil)
|
||||||
|
c.Assert(v, qt.Equals, false)
|
||||||
|
err = pin.Toggle()
|
||||||
|
c.Assert(err, qt.Equals, nil)
|
||||||
|
c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0b10))
|
||||||
|
err = pin.Toggle()
|
||||||
|
c.Assert(err, qt.Equals, nil)
|
||||||
|
c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0))
|
||||||
|
}
|
||||||
|
|
||||||
func TestPinMode(t *testing.T) {
|
func TestPinMode(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
bus := newBus(c)
|
bus := newBus(c)
|
||||||
|
|||||||
@@ -117,6 +117,22 @@ func (devs Devices) SetPins(pins, mask PinSlice) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TogglePins inverts the values on all pins for
|
||||||
|
// which mask is high.
|
||||||
|
func (devs Devices) TogglePins(mask PinSlice) error {
|
||||||
|
defaultMask := mask.extra()
|
||||||
|
for i, dev := range devs {
|
||||||
|
devMask := defaultMask
|
||||||
|
if i < len(mask) {
|
||||||
|
devMask = mask[i]
|
||||||
|
}
|
||||||
|
if err := dev.TogglePins(devMask); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// PinSlice represents an arbitrary nunber of pins, each element corresponding
|
// PinSlice represents an arbitrary nunber of pins, each element corresponding
|
||||||
// to the pins for one device. The value of the highest numbered pin in the
|
// to the pins for one device. The value of the highest numbered pin in the
|
||||||
// slice is extended to all other pins beyond the end of the slice.
|
// slice is extended to all other pins beyond the end of the slice.
|
||||||
@@ -154,6 +170,11 @@ func (pins PinSlice) Low(pin int) {
|
|||||||
pins[pin/PinCount].Low(pin % PinCount)
|
pins[pin/PinCount].Low(pin % PinCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle inverts the value of the given pin.
|
||||||
|
func (pins PinSlice) Toggle(pin int) {
|
||||||
|
pins[pin/PinCount].Toggle(pin % PinCount)
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure checks that pins has enough space to store
|
// Ensure checks that pins has enough space to store
|
||||||
// at least length pins. If it does, it returns pins unchanged.
|
// at least length pins. If it does, it returns pins unchanged.
|
||||||
// Otherwise, it returns pins with elements appended as needed,
|
// Otherwise, it returns pins with elements appended as needed,
|
||||||
|
|||||||
@@ -102,6 +102,26 @@ func TestDevicesSetPinsMask(t *testing.T) {
|
|||||||
c.Assert(pins, qt.DeepEquals, PinSlice{0b01010011_10101101, 0b01010010_10101100})
|
c.Assert(pins, qt.DeepEquals, PinSlice{0b01010011_10101101, 0b01010010_10101100})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDevicesTogglePins(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
bus := newBus(c)
|
||||||
|
bus.addDevice(0x20)
|
||||||
|
bus.addDevice(0x21)
|
||||||
|
devs, err := NewI2CDevices(bus, 0x20, 0x21)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
mask := make(PinSlice, 2)
|
||||||
|
mask.High(0)
|
||||||
|
mask.High(16)
|
||||||
|
|
||||||
|
err = devs.TogglePins(mask)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
pins := make(PinSlice, 2)
|
||||||
|
err = devs.GetPins(pins)
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(pins, qt.DeepEquals, PinSlice{0b00000000_00000001, 0b00000000_00000001})
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevicesSetGetModes(t *testing.T) {
|
func TestDevicesSetGetModes(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
bus := newBus(c)
|
bus := newBus(c)
|
||||||
@@ -163,4 +183,6 @@ func TestPinSlice(t *testing.T) {
|
|||||||
c.Assert(pins.Get(16), qt.Equals, false)
|
c.Assert(pins.Get(16), qt.Equals, false)
|
||||||
pins.High(16)
|
pins.High(16)
|
||||||
c.Assert(pins.Get(16), qt.Equals, true)
|
c.Assert(pins.Get(16), qt.Equals, true)
|
||||||
|
pins.Toggle(16)
|
||||||
|
c.Assert(pins.Get(16), qt.Equals, false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user