Skip to content

Commit

Permalink
Merge pull request #625 from WildernessLabs/mcp-simplification
Browse files Browse the repository at this point in the history
Remove bespoke bus abstraction in Mcp23xxx
  • Loading branch information
adrianstevens authored Apr 22, 2023
2 parents 47e30e5 + c733b8b commit 31604b6
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 126 deletions.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,35 @@ abstract partial class Mcp23xxx : IDigitalInputOutputController, ISpiDevice
/// <summary>
/// The default SPI bus speed for the device
/// </summary>
public Frequency DefaultSpiBusSpeed => _defaultSpiBusSpeed;
private static Frequency _defaultSpiBusSpeed = new Frequency(375, Frequency.UnitType.Kilohertz);
public Frequency DefaultSpiBusSpeed => new Frequency(375, Frequency.UnitType.Kilohertz);

/// <summary>
/// The SPI bus speed for the device
/// </summary>
public Frequency SpiBusSpeed
{
get => (mcpDevice as SpiMcpDeviceComms).BusSpeed;
set => (mcpDevice as SpiMcpDeviceComms).BusSpeed = value;
get => (mcpDevice as ISpiPeripheral).BusSpeed;
set => (mcpDevice as ISpiPeripheral).BusSpeed = value;
}

/// <summary>
/// The default SPI bus mode for the device
/// </summary>
public SpiClockConfiguration.Mode DefaultSpiBusMode => _defaultSpiBusMode;
private static SpiClockConfiguration.Mode _defaultSpiBusMode = SpiClockConfiguration.Mode.Mode0;
public SpiClockConfiguration.Mode DefaultSpiBusMode => SpiClockConfiguration.Mode.Mode0;

/// <summary>
/// The SPI bus mode for the device
/// </summary>
public SpiClockConfiguration.Mode SpiBusMode
{
get => (mcpDevice as SpiMcpDeviceComms).BusMode;
set => (mcpDevice as SpiMcpDeviceComms).BusMode = value;
get => (mcpDevice as ISpiPeripheral).BusMode;
set => (mcpDevice as ISpiPeripheral).BusMode = value;
}

private readonly IMcpDeviceComms mcpDevice;
private readonly IDigitalInputPort interruptPort;
private readonly IDigitalOutputPort resetPort;
private readonly IDictionary<IPin, DigitalInputPort> inputPorts;
private readonly IByteCommunications mcpDevice;
private IDigitalInputPort interruptPort;
private IDigitalOutputPort resetPort;
private IDictionary<IPin, DigitalInputPort> inputPorts;

private byte ioDirA, ioDirB;
private byte olatA, olatB;
Expand All @@ -75,9 +73,11 @@ public SpiClockConfiguration.Mode SpiBusMode
/// <param name="interruptPort">Optional interupt port, needed for input interrupts (pins 1-8)</param>
/// <param name="resetPort">Optional Meadow output port used to reset the mcp expander</param>
protected Mcp23xxx(II2cBus i2cBus, byte address,
IDigitalInputPort interruptPort = null, IDigitalOutputPort resetPort = null) :
this(new I2cMcpDeviceComms(i2cBus, address), interruptPort, resetPort)
{ }
IDigitalInputPort interruptPort = null, IDigitalOutputPort resetPort = null)
{
mcpDevice = new I2cPeripheral(i2cBus, address);
Initialize(interruptPort, resetPort);
}

/// <summary>
/// Mcpxxx base class contructor
Expand All @@ -89,28 +89,20 @@ protected Mcp23xxx(II2cBus i2cBus, byte address,
protected Mcp23xxx(ISpiBus spiBus,
IDigitalOutputPort chipSelectPort,
IDigitalInputPort interruptPort = null,
IDigitalOutputPort resetPort = null) :
this(new SpiMcpDeviceComms(spiBus, chipSelectPort, _defaultSpiBusSpeed, _defaultSpiBusMode), interruptPort, resetPort)
IDigitalOutputPort resetPort = null)
{

mcpDevice = new SpiPeripheral(spiBus, chipSelectPort, DefaultSpiBusSpeed, DefaultSpiBusMode);
Initialize(interruptPort, resetPort);
}

/// <summary>
/// Mcp23xxx base class
/// Initializes the Mcp23xxx
/// </summary>
/// <param name="device"></param>
/// <param name="interruptPort">optional interupt port, needed for input interrupts (pins 1-8)</param>
/// <param name="resetPort">Optional Meadow output port used to reset the mcp expander</param>
internal Mcp23xxx(IMcpDeviceComms device,
IDigitalInputPort interruptPort = null,
IDigitalOutputPort resetPort = null)
void Initialize(IDigitalInputPort interruptPort = null,
IDigitalOutputPort resetPort = null)
{
if (resetPort != null)
{
this.resetPort = resetPort;
ResetMcp();
}

// TODO: more interrupt
// check the interrupt mode and make sure it's correct
// raise an exception if not. also, doc in constructor what we expect from an interrupt port
Expand All @@ -120,12 +112,52 @@ internal Mcp23xxx(IMcpDeviceComms device,
interruptPort.Changed += InterruptPortChanged;
}

if (resetPort != null)
{
this.resetPort = resetPort;
ResetMcp();
}

inputPorts = new Dictionary<IPin, DigitalInputPort>();

IByteCommunications comms;
mcpDevice = device;
mcpDevice.WriteRegister(MapRegister(Registers.IODIR_IODirection, PortBank.A), 0xFF);
mcpDevice.WriteRegister(MapRegister(Registers.GPIO, PortBank.A), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.IPOL_InputPolarity, PortBank.A), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.GPINTEN_InterruptOnChange), 0x00);

Initialize();
if (NumberOfPins == 16)
{ //write the following registers as well (assume device is interleaving)
mcpDevice.WriteRegister(MapRegister(Registers.IODIR_IODirection, PortBank.B), 0xFF);
mcpDevice.WriteRegister(MapRegister(Registers.GPIO, PortBank.B), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.IPOL_InputPolarity, PortBank.B), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.GPINTEN_InterruptOnChange, PortBank.B), 0x00);
}

// save our state
ioDirA = ioDirB = 0xFF;
olatA = olatB = 0x00;

if (interruptPort != null)
{
bool intHigh = true;

if (interruptPort.Resistor == ResistorMode.InternalPullUp ||
interruptPort.Resistor == ResistorMode.ExternalPullUp)
{
intHigh = false;
}

byte iocon = 0x00;
iocon = BitHelpers.SetBit(iocon, 0x01, intHigh); //set interrupt pin to active high (true), low (false)
iocon = BitHelpers.SetBit(iocon, 0x02, false); //don't set interrupt to open drain (should be the default)

mcpDevice.WriteRegister(MapRegister(Registers.IOCON_IOConfiguration), iocon);

if (NumberOfPins == 16)
{
mcpDevice.WriteRegister(MapRegister(Registers.IOCON_IOConfiguration, PortBank.B), iocon);
}
}
}

/// <summary>
Expand Down Expand Up @@ -171,51 +203,6 @@ private void InterruptPortChanged(object sender, DigitalPortResult e)
InputChanged?.Invoke(this, new IOExpanderInputChangedEventArgs(interruptFlag, (ushort)(currentStatesB << 8 | currentStates)));
}

/// <summary>
/// Initializes the Mcp23xxx
/// </summary>
protected virtual void Initialize()
{
mcpDevice.WriteRegister(MapRegister(Registers.IODIR_IODirection, PortBank.A), 0xFF);
mcpDevice.WriteRegister(MapRegister(Registers.GPIO, PortBank.A), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.IPOL_InputPolarity, PortBank.A), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.GPINTEN_InterruptOnChange), 0x00);

if (NumberOfPins == 16)
{ //write the following registers as well (assume device is interleaving)
mcpDevice.WriteRegister(MapRegister(Registers.IODIR_IODirection, PortBank.B), 0xFF);
mcpDevice.WriteRegister(MapRegister(Registers.GPIO, PortBank.B), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.IPOL_InputPolarity, PortBank.B), 0x00);
mcpDevice.WriteRegister(MapRegister(Registers.GPINTEN_InterruptOnChange, PortBank.B), 0x00);
}

// save our state
ioDirA = ioDirB = 0xFF;
olatA = olatB = 0x00;

if (interruptPort != null)
{
bool intHigh = true;

if (interruptPort.Resistor == ResistorMode.InternalPullUp ||
interruptPort.Resistor == ResistorMode.ExternalPullUp)
{
intHigh = false;
}

byte iocon = 0x00;
iocon = BitHelpers.SetBit(iocon, 0x01, intHigh); //set interrupt pin to active high (true), low (false)
iocon = BitHelpers.SetBit(iocon, 0x02, false); //don't set interrupt to open drain (should be the default)

mcpDevice.WriteRegister(MapRegister(Registers.IOCON_IOConfiguration), iocon);

if (NumberOfPins == 16)
{
mcpDevice.WriteRegister(MapRegister(Registers.IOCON_IOConfiguration, PortBank.B), iocon);
}
}
}

/// <summary>
/// Checks if a pin exists on the Mcpxxxxx
/// </summary>
Expand Down

0 comments on commit 31604b6

Please sign in to comment.