Skip to content
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
25 changes: 25 additions & 0 deletions src/devices/Mcp23xxx/Bank.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Iot.Device.Mcp23xxx
{
/// <summary>
/// The MCP28XXX family has an address mapping concept for accessing registers.
/// This provides a way to easily address registers by group or type.
/// </summary>
public enum Bank
{
/// <summary>
/// This mode is used specifically for 16-bit devices where it causes the
/// address pointer to toggle between associated A/B register pairs.
/// </summary>
Bank0 = 0,
/// <summary>
/// This mode is used to group each port's registers together.
/// This mode is the default since 8-bit devices only have one port and
/// 16-bit devices are initialized in this state.
/// </summary>
Bank1 = 1
}
}
78 changes: 78 additions & 0 deletions src/devices/Mcp23xxx/Mcp23xxx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Device.Gpio;
using System.Device.Spi;

namespace Iot.Device.Mcp23xxx
{
public class Mcp23xxx : IDisposable
{
private readonly SpiDevice _spiDevice;

private enum CommunicationProtocol
{
I2c,
Spi
}

public Mcp23xxx(SpiDevice spiDevice)
{
_spiDevice = spiDevice;
}

public void Dispose()
{
}

public byte Read(int deviceAddress, Register.Address registerAddress, Port port = Port.PortA, Bank bank = Bank.Bank1)
{
byte opCode = OpCode.GetOpCode(deviceAddress, true);
byte mappedAddress = Register.GetMappedAddress(registerAddress, port, bank);
byte[] writeBuffer = new byte[] { opCode, mappedAddress, 0 };
byte[] readBuffer = new byte[3];

_spiDevice.TransferFullDuplex(writeBuffer, readBuffer);
return readBuffer[2];
}

public byte[] Read(int deviceAddress, Register.Address startingRegisterAddress, byte byteCount, Port port = Port.PortA, Bank bank = Bank.Bank1)
{
byte opCode = OpCode.GetOpCode(deviceAddress, true);
byte mappedAddress = Register.GetMappedAddress(startingRegisterAddress, port, bank);

byteCount += 2; // Include OpCode and Register Address.
byte[] writeBuffer = new byte[byteCount];
writeBuffer[0] = opCode;
writeBuffer[1] = (byte)startingRegisterAddress;
byte[] readBuffer = new byte[byteCount];

_spiDevice.TransferFullDuplex(writeBuffer, readBuffer);
return readBuffer.AsSpan().Slice(2).ToArray(); // First 2 bytes are from sending OpCode and Register Address.
}

public void Write(int deviceAddress, Register.Address registerAddress, byte data, Port port = Port.PortA, Bank bank = Bank.Bank1)
{
byte opCode = OpCode.GetOpCode(deviceAddress, false);
byte mappedAddress = Register.GetMappedAddress(registerAddress, port, bank);
byte[] writeBuffer = new byte[] { opCode, mappedAddress, data };

_spiDevice.Write(writeBuffer);
}

public void Write(int deviceAddress, Register.Address startingRegisterAddress, byte[] data, Port port = Port.PortA, Bank bank = Bank.Bank1)
{
byte opCode = OpCode.GetOpCode(deviceAddress, false);
byte mappedAddress = Register.GetMappedAddress(startingRegisterAddress, port, bank);

byte[] writeBuffer = new byte[data.Length + 2]; // Include OpCode and Register Address.
writeBuffer[0] = opCode;
writeBuffer[1] = (byte)startingRegisterAddress;
data.CopyTo(writeBuffer, 2);

_spiDevice.Write(writeBuffer);
}
}
}
22 changes: 22 additions & 0 deletions src/devices/Mcp23xxx/Mcp23xxx.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<!--Disabling default items so samples source won't get build by the main library-->
</PropertyGroup>

<ItemGroup>
<Compile Include="Bank.cs" />
<Compile Include="Mcp23xxx.cs" />
<Compile Include="OpCode.cs" />
<Compile Include="Port.cs" />
<Compile Include="Register.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Device.Gpio" Version="0.1.0-prerelease*" />
<None Include="README.md" />
</ItemGroup>

</Project>
21 changes: 21 additions & 0 deletions src/devices/Mcp23xxx/OpCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Iot.Device.Mcp23xxx
{
public class OpCode
{
public static byte GetOpCode(int deviceAddress, bool isReadCommand)
{
int opCode = 0b0100_0000 | (deviceAddress << 1);

if (isReadCommand)
{
opCode |= 0b000_0001; // Set read bit.
}

return (byte)opCode;
}
}
}
12 changes: 12 additions & 0 deletions src/devices/Mcp23xxx/Port.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Iot.Device.Mcp23xxx
{
public enum Port
{
PortA,
PortB
}
}
44 changes: 44 additions & 0 deletions src/devices/Mcp23xxx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Microchip Mcp23xxx

## Summary
The MCP23XXX device family provides 8/16-bit, general purpose parallel I/O expansion for I2C or SPI applications. These devices include a range of addressing schemes and I/O configurations including pull-up resistors, polarity inverting, and interrupts.

## Device Family
MCP23XXX devices contain different markings to distinguish features like interfacing, packaging, and temperature ratings. For example, MCP23017 contains an I2C interface and MCP23S17 contains a SPI interface. Please review specific datasheet for more information.

**MCP23X08**: http://ww1.microchip.com/downloads/en/DeviceDoc/21919e.pdf
**MCP23X09**: http://ww1.microchip.com/downloads/en/DeviceDoc/20002121C.pdf
**MCP23X17**: http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf
**MCP23X18**: http://ww1.microchip.com/downloads/en/DeviceDoc/22103a.pdf

**NOTE**: MCP23X16 contains different internal circuitry and is not compatible with this binding.

## Binding Notes

### Register Banking
The number of ports vary between Mcp23xxx devices depending if it is 8-bit (1 port) or 16-bit (2 ports). The internal circuitry has a banking concept to group by port registers or by register type. This enables different configurations for reading/writing schemes.

To allow this binding to work across the device family, you must use the provided arguments when using Reading/Writing methods.

#### Example for 16-bit device
The MCP23X17 has registers defaulted to Bank 1, which group port registers by type. It is recommended to use the optional arguments for port and bank when addressing the correct register.

``` csharp
// Read Port B's Input Polarity Port Register (IPOL) from device 3.
byte data = mcp23xxx.Read(3, Register.Address.IPOL, Port.PortB, Bank.Bank0);

// If the device is configured for Bank 1, you can ignore the optional argument.
byte data = mcp23xxx.Read(3, Register.Address.IPOL, Port.PortB);
```
#### Example for 8-bit device
The MCP23X08 only contains 1 port so you must use Bank 1 when addressing the correct register. In this case, the optional arguments can be ignored.

``` csharp
// Read port A's GPIO Pull-Up Resistor Register (GPPU) from device 1.
byte data = mcp23xxx.Read(1, Register.Address.GPPU);
// or..
byte data = mcp23xxx.Read(1, Register.Address.GPPU, Port.PortA, Bank.Bank1);
```

## References
https://www.adafruit.com/product/732
Loading