mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
4.1 KiB
Go
198 lines
4.1 KiB
Go
// Copyright 2020 The Periph Authors. All rights reserved.
|
|
// Use of this source code is governed under the Apache License, Version 2.0
|
|
// that can be found in the LICENSE file.
|
|
|
|
package mcp23xxx
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"time"
|
|
|
|
"periph.io/x/conn/v3/gpio"
|
|
"periph.io/x/conn/v3/physic"
|
|
"periph.io/x/conn/v3/pin"
|
|
)
|
|
|
|
// Pin extends gpio.PinIO interface with features supported by MCP23xxx devices.
|
|
type Pin interface {
|
|
gpio.PinIO
|
|
// SetPolarityInverted if set to true, GPIO register bit reflects the same logic state of the input pin.
|
|
SetPolarityInverted(p bool) error
|
|
// IsPolarityInverted returns true if the value of the input pin reflects inverted logic state.
|
|
IsPolarityInverted() (bool, error)
|
|
}
|
|
|
|
type port struct {
|
|
name string
|
|
|
|
// GPIO basic registers
|
|
iodir registerCache
|
|
gpio registerCache
|
|
olat registerCache
|
|
|
|
// polarity setting
|
|
ipol registerCache
|
|
|
|
// pull-up control register
|
|
// Not present in all devices
|
|
gppu registerCache
|
|
supportPullup bool
|
|
|
|
// interrupt handling registers
|
|
supportInterrupt bool
|
|
gpinten registerCache
|
|
intcon registerCache
|
|
intf registerCache
|
|
intcap registerCache
|
|
}
|
|
|
|
type portpin struct {
|
|
port *port
|
|
pinbit uint8
|
|
}
|
|
|
|
func (p *port) pins() []Pin {
|
|
result := make([]Pin, 8)
|
|
var i uint8
|
|
for i = 0; i < 8; i++ {
|
|
result[i] = &portpin{
|
|
port: p,
|
|
pinbit: i,
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (p *portpin) String() string {
|
|
return p.Name()
|
|
}
|
|
|
|
func (p *portpin) Halt() error {
|
|
// To halt all drive, set to high-impedance input
|
|
return p.In(gpio.Float, gpio.NoEdge)
|
|
}
|
|
|
|
func (p *portpin) Name() string {
|
|
return p.port.name + "_" + strconv.Itoa(int(p.pinbit))
|
|
}
|
|
|
|
func (p *portpin) Number() int {
|
|
return int(p.pinbit)
|
|
}
|
|
|
|
func (p *portpin) Function() string {
|
|
return string(p.Func())
|
|
}
|
|
|
|
func (p *portpin) In(pull gpio.Pull, edge gpio.Edge) error {
|
|
// Set pin to input
|
|
err := p.port.iodir.getAndSetBit(p.pinbit, true, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Set pullup
|
|
switch pull {
|
|
case gpio.PullNoChange:
|
|
// don't check, don't change
|
|
case gpio.PullDown:
|
|
// pull down is not supported by any device
|
|
return errors.New("MCP23xxx: PullDown is not supported")
|
|
case gpio.PullUp:
|
|
if !p.port.supportPullup {
|
|
return errors.New("MCP23xxx: PullUp is not supported by this device")
|
|
}
|
|
err = p.port.gppu.getAndSetBit(p.pinbit, true, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case gpio.Float:
|
|
if p.port.supportPullup {
|
|
err = p.port.gppu.getAndSetBit(p.pinbit, false, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
// check edge detection
|
|
// TODO interrupt support
|
|
return nil
|
|
}
|
|
|
|
func (p *portpin) Read() gpio.Level {
|
|
v, _ := p.port.gpio.getBit(p.pinbit, false)
|
|
if v {
|
|
return gpio.High
|
|
}
|
|
return gpio.Low
|
|
}
|
|
|
|
func (p *portpin) WaitForEdge(timeout time.Duration) bool {
|
|
// TODO interrupt handling
|
|
return false
|
|
}
|
|
|
|
func (p *portpin) Pull() gpio.Pull {
|
|
if !p.port.supportPullup {
|
|
return gpio.Float
|
|
}
|
|
v, err := p.port.gppu.getBit(p.pinbit, true)
|
|
if err != nil {
|
|
return gpio.PullNoChange
|
|
}
|
|
if v {
|
|
return gpio.PullUp
|
|
}
|
|
return gpio.Float
|
|
}
|
|
|
|
func (p *portpin) DefaultPull() gpio.Pull {
|
|
return gpio.Float
|
|
}
|
|
|
|
func (p *portpin) Out(l gpio.Level) error {
|
|
err := p.port.iodir.getAndSetBit(p.pinbit, false, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.port.olat.getAndSetBit(p.pinbit, l == gpio.High, true)
|
|
}
|
|
|
|
func (p *portpin) PWM(duty gpio.Duty, f physic.Frequency) error {
|
|
return errors.New("MCP23xxx: PWM is not supported")
|
|
}
|
|
|
|
func (p *portpin) Func() pin.Func {
|
|
v, _ := p.port.iodir.getBit(p.pinbit, true)
|
|
if v {
|
|
return gpio.IN
|
|
}
|
|
return gpio.OUT
|
|
}
|
|
|
|
func (p *portpin) SupportedFuncs() []pin.Func {
|
|
return supportedFuncs[:]
|
|
}
|
|
|
|
func (p *portpin) SetFunc(f pin.Func) error {
|
|
var v bool
|
|
switch f {
|
|
case gpio.IN:
|
|
v = true
|
|
case gpio.OUT:
|
|
v = false
|
|
default:
|
|
return errors.New("MCP23xxx: Function not supported: " + string(f))
|
|
}
|
|
return p.port.iodir.getAndSetBit(p.pinbit, v, true)
|
|
}
|
|
|
|
func (p *portpin) SetPolarityInverted(pol bool) error {
|
|
return p.port.ipol.getAndSetBit(p.pinbit, pol, true)
|
|
}
|
|
func (p *portpin) IsPolarityInverted() (bool, error) {
|
|
return p.port.ipol.getBit(p.pinbit, true)
|
|
}
|
|
|
|
var supportedFuncs = [...]pin.Func{gpio.IN, gpio.OUT}
|