Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for PCA9548A 8-channel I2C-bus #644

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions examples/pca9548a/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"machine"
"time"
"tinygo.org/x/drivers/bme280"
"tinygo.org/x/drivers/pca9548a"
)

func main() {
time.Sleep(5 * time.Second)
err := machine.I2C0.Configure(machine.I2CConfig{})
if err != nil {
panic(err.Error())
}
mux := pca9548a.New(machine.I2C0, pca9548a.Address)
if !mux.IsConnected() {
println("NO DEVICE DETECTED")
return
}

port := mux.GetPortState()
println("GET PORT", port)
mux.DisablePort()
mux.SetPort(0)
port = mux.GetPortState()
println("GET PORT", port)
mux.SetPort(1)
port = mux.GetPortState()
println("GET PORT", port)

tmpSensors := make([]bme280.Device, 2)

for i := uint8(0); i < 2; i++ {
mux.SetPort(i)
time.Sleep(10 * time.Millisecond)
tmpSensors[i] = bme280.New(machine.I2C0)
tmpSensors[i].Configure()

connected := tmpSensors[i].Connected()
if !connected {
println("\nBME280 Sensor not detected\n", i)
} else {
println("\nBME280 Sensor detected\n", i)
}
}
time.Sleep(10000 * time.Millisecond)

for {
for i := uint8(0); i < 2; i++ {
mux.SetPort(i)
t, err := tmpSensors[i].ReadTemperature()
if err != nil {
println(i, "Error reading temperature")
}
println(i, "temperature", t)

p, err := tmpSensors[i].ReadPressure()
if err != nil {
println("Error reading pressure")
}
println(i, "pressure", p)

}
time.Sleep(40 * time.Millisecond)
}
}
87 changes: 87 additions & 0 deletions pca9548a/pca9685a.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Package pca9548a provides a driver for the PCA9548A 8-channel I2C-bus.
//
// Datasheet:
// https://www.nxp.com/docs/en/data-sheet/PCA9548A.pdf
package pca9548a // import "tinygo.org/x/drivers/pca9548a"

import (
"tinygo.org/x/drivers"
)

// Device is a handle to the PCA9548A device given an address
type Device struct {
addr uint8
bus drivers.I2C
buf [4]byte
}

// New creates a new instance of a PCA9548A device. It performs
// no IO on the i2c bus.
func New(bus drivers.I2C, addr uint8) Device {
return Device{
bus: bus,
addr: addr,
}
}

// Connected returns whether a PCA9548A has been found.
// It does a "who am I" request and checks the response.
func (d *Device) IsConnected() bool {
d.SetPortState(0xA5)
response := d.GetPortState()
d.SetPortState(0x00)
return response == 0xA5
}

// SetPort enables the given port to send data.
func (d *Device) SetPort(portNumber byte) {
portValue := uint8(0)
if portNumber <= 7 {
portValue = 1 << portNumber
}
d.bus.Tx(uint16(d.addr), []byte{portValue}, nil)
}

// GetPort gets the first port enabled.
func (d *Device) GetPort() byte {
portBits := d.GetPortState()
for i := uint8(0); i < 8; i++ {
if (portBits & (1 << i)) != 0x00 {
return i
}
}
return InvalidPort
}

// SetPortState set the states of all the ports at the same time, this could cause some issues if
// you enable two (or more) ports with the same devices at the same time.
func (d *Device) SetPortState(portBits byte) {
d.bus.Tx(uint16(d.addr), []byte{portBits}, nil)
}

// GetPortState get the state of all the ports.
func (d *Device) GetPortState() byte {
portBits := make([]byte, 1)
d.bus.Tx(uint16(d.addr), nil, portBits)
return portBits[0]
}

// EnablePort enables the given port without modifying any other, this could cause some issues if
// you enable two (or more) ports with the same devices at the same time.
func (d *Device) EnablePort(portNumber byte) {
if portNumber > 7 {
portNumber = 7
}

settings := d.GetPortState()
settings |= 1 << portNumber

d.SetPortState(settings)
}

// DisablePort disables the given port without modifying any other.
func (d *Device) DisablePort() byte {
portBits := make([]byte, 1)
d.bus.Tx(uint16(d.addr), nil, portBits)
return portBits[0]
}
6 changes: 6 additions & 0 deletions pca9548a/registers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package pca9548a

const (
Address = 0x70
InvalidPort = 0xff
)
1 change: 1 addition & 0 deletions smoketest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ tinygo build -size short -o ./build/test.hex -target=pico ./examples/ndir/main_n
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ndir/main_ndir.go
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ndir/main_ndir.go
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/main.go
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/pca9548a/main.go
tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/sh1106/macropad_spi
# network examples (espat)
tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/
Expand Down