Hello,
Have you ever wanted to--or needed to--add ridiculous numbers of GPIOs to your project? Did you want those ports to be as flexible as native ports, including features like pull-up resistors and interrupt support? Well then hopefully this driver will fit your needs.
This driver provides Netduino support for MCP23S08/MCP23S17 I/O expanders through SPI. You can, theoretically, add up to 128 GPIOs per chip select pin used. Each port on each expander can be configured as an input or output, and supports pull-up resistors on output ports and interrupts on input ports.
This driver makes use of Stefan Thoolen's excellent MultiSPI class to support multiple expanders.
This driver provides two means of interaction: All the ports on an expander can be written to or read from simultaneously, or a port on an expander can be setup and used as a drop-in replacement for a native GPIO.
Below is an example of using the driver with the latter method of interaction:
public class Program { // Create some standard Netduino variables and ports static int count = 0; static InputPort foo = new InputPort(Pins.GPIO_PIN_D0, false, Port.ResistorMode.Disabled); static InputPort bar = new InputPort(Pins.GPIO_PIN_D1, false, Port.ResistorMode.Disabled); static InterruptPort button = new InterruptPort(Pins.ONBOARD_BTN, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow); // Create the two expander objects static MCP23S17 expander1 = new MCP23S17(Pins.GPIO_PIN_D10, 0x00); static MCP23S17 expander2 = new MCP23S17(Pins.GPIO_PIN_D10, 0x01); // Create one output on each expander static ExpandedOuputPort output1 = new ExpandedOuputPort(MCP23S17.ports.GP9, false, expander1); static ExpandedOuputPort output2 = new ExpandedOuputPort(MCP23S17.ports.GP7, false, expander2); // Create one input on each expander static ExpandedInputPort input1 = new ExpandedInputPort(MCP23S17.ports.GP2, Port.ResistorMode.PullUp, expander1); static ExpandedInputPort input2 = new ExpandedInputPort(MCP23S17.ports.GP12, Port.ResistorMode.PullUp, expander2); public static void Main() { button.OnInterrupt += button_OnInterrupt; while (true) { // Check the states of the expanders' outputs using the Netduino inputs Debug.Print("One output: " + foo.Read().ToString()); Debug.Print("Two output: " + bar.Read().ToString() + "\n"); // Check the states of the expanders' inputs Debug.Print("One input: " + input1.Read().ToString()); Debug.Print("Two input: " + input2.Read().ToString() + "\n\n"); Thread.Sleep(1000); } } /// <summary> /// When the Netduino's button is pushed this will alternate between toggling each /// expander's output port, e.g. the first push will toggle the output on expander1, /// the second push will toggle the output on expander2, etc... /// </summary> /// <param name="pin">The pin triggering the interrupt</param> /// <param name="state">The pin state</param> /// <param name="time">The time of the interrupt</param> static void button_OnInterrupt(uint pin, uint state, DateTime time) { if (count == 0) { output1.Write(!output1.Read()); count++; } else { output2.Write(!output2.Read()); count = 0; } Debug.Print("Toggled"); } }
A few notes:
This driver does not prevent multiple assignments: e.g. one could assign a port as an output port, and later assign it as an input port and no error would be thrown. So it's important to take care when assigning ports.
Writing/reading to/from the all the ports simultaneously can be done while using the ExpandedInputPort or ExpandedOutputPort classes, however the two methods will overwrite each other, i.e whichever method is used last will be the one that is in effect.
I have not implemented an ExpandedInterruptPort class. However, the interrupt functions can still be used with the checkInterrupt() method, which will return the contents of the INTF and INTCAP registers.
This driver is still a draft, so any feedback or suggestions are more than welcome!