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

Remove bespoke bus abstraction in Mcp23xxx #625

Merged
merged 2 commits into from
Apr 22, 2023
Merged
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

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