Peter Oakes
Published

PiFace Digital 2 on a Rasberry PI 2 and Windows 10 IoT

A library and example UI for using the PiFace Digital 2 under Windows 10 IoT. you can find more examples here: youtube.com/c/thebreadboardca

IntermediateFull instructions provided10,409
PiFace Digital 2 on a Rasberry PI 2 and Windows 10 IoT

Things used in this project

Hardware components

Raspberry Pi 2 Model B
Raspberry Pi 2 Model B
×1
Piface digital 2
×1

Software apps and online services

Visual Studio Community Edition
Windows 10 IoT Core
Microsoft Windows 10 IoT Core

Story

Read more

Schematics

PIFaceDigitalII.JPG

Code

MCP23S17.cs

C#
Library for the MCP23S17 chip
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Spi;
using Windows.Devices.Enumeration;

namespace SPI_GPIO
{
    public class MCP23S17
    {

        private const byte IODIRA   = 0x00 ;     // I/O Direction Register
        private const byte IODIRB   = 0x01;      // 1 = Input (default), 0 = Output
        private const byte IPOLA    = 0x02 ;     // MCP23x17 Input Polarity Register
        private const byte IPOLB    = 0x03 ;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
        private const byte GPINTENA = 0x04 ;     // MCP23x17 Interrupt on Change Pin Assignements
        private const byte GPINTENB = 0x05 ;     // 0 = No Interrupt on Change (default), 1 = Interrupt on Change
        private const byte DEFVALA  = 0x06  ;    // MCP23x17 Default Compare Register for Interrupt on Change
        private const byte DEFVALB  = 0x07 ;     // Opposite of what is here will trigger an interrupt (default = 0)
        private const byte INTCONA  = 0x08 ;     // MCP23x17 Interrupt on Change Control Register
        private const byte INTCONB  = 0x09 ;     // 1 = pin is compared to DEFVAL, 0 = pin is compared to previous state (default)
        private const byte IOCONA   = 0x0A ;     // MCP23x17 Configuration Register
        private const byte IOCONB   = 0x0B  ;    //     Also Configuration Register
        private const byte GPPUA    = 0x0C ;     // MCP23x17 Weak Pull-Up Resistor Register
        private const byte GPPUB    = 0x0D ;     // INPUT ONLY: 0 = No Internal 100k Pull-Up (default) 1 = Internal 100k Pull-Up 
        private const byte INTFA    = 0x0E ;     // MCP23x17 Interrupt Flag Register
        private const byte INTFB    = 0x0F  ;    // READ ONLY: 1 = This Pin Triggered the Interrupt
        private const byte INTCAPA  = 0x10  ;    // MCP23x17 Interrupt Captured Value for Port Register
        private const byte INTCAPB  = 0x11  ;    // READ ONLY: State of the Pin at the Time the Interrupt Occurred
        private const byte GPIOA    = 0x12;      // MCP23x17 GPIO Port Register
        private const byte GPIOB    = 0x13;      // Value on the Port - Writing Sets Bits in the Output Latch
        private const byte OLATA    = 0x14;      // MCP23x17 Output Latch Register
        private const byte OLATB    = 0x15;      // 1 = Latch High, 0 = Latch Low (default) Reading Returns Latch State, Not Port Value!

        public const byte On = 1;
        public const byte Off= 0;
        public const byte Output= 0;
        public const byte Input = 1;

        private const byte Address = 0x00;   // offset address if hardware addressing is on and is 0 - 7 (A0 - A2) 
        private const byte BaseAddW = 0x40;  // MCP23S17 Write base address
        private const byte BaseAddR = 0x41;  // MCP23S17 Read Base Address
        private const byte HAEN     = 0x08;  // IOCON register for MCP23S17, x08 enables hardware address so sent address must match hardware pins A0-A2


        private static UInt16 PinMode = 0XFFFF;     // default Pinmode for the MXP23S17 set to inputs
        private static UInt16 PullUpMode = 0XFFFF;     // default pullups for the MXP23S17 set to weak pullup
        private static UInt16 InversionMode = 0X0000;     // default invert to normal
        private static UInt16 PinState = 0X0000;     // default pinstate to all 0's

        /*RaspBerry Pi2  Parameters*/
        private const string SPI_CONTROLLER_NAME = "SPI0";  /* For Raspberry Pi 2, use SPI0                             */
        private const Int32 SPI_CHIP_SELECT_LINE = 0;       /* Line 0 maps to physical pin number 24 on the Rpi2, line 1 to pin 26        */

        private static byte[] readBuffer3 = new byte[3]; /*this is defined to hold the output data*/
        private static byte[] readBuffer4 = new byte[4]; /*this is defined to hold the output data*/
        private static byte[] writeBuffer3 = new byte[3];//register, then 16 bit value
        private static byte[] writeBuffer4 = new byte[4];//register, then 16 bit value

        private static SpiDevice SpiGPIO;
        public static async Task InitSPI()
        {
            try
            {
                var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE);
                settings.ClockFrequency = 1000000;// 10000000;
                settings.Mode = SpiMode.Mode0; //Mode0,1,2,3;  MCP23S17 needs mode 0

                string spiAqs = SpiDevice.GetDeviceSelector(SPI_CONTROLLER_NAME);
                var deviceInfo = await DeviceInformation.FindAllAsync(spiAqs);
                SpiGPIO = await SpiDevice.FromIdAsync(deviceInfo[0].Id, settings);
            }

            /* If initialization fails, display the exception and stop running */
            catch (Exception ex)
            {
                //statusText.Text = "\nSPI Initialization Failed";
            }
        }

        public static void InitMCP23S17()
        {
            WriteRegister8(IOCONA, HAEN);                   // enable the hardware address incase there is more than one chip
            WriteRegister16(IODIRA, PinMode);                // Set the default or current pin mode

        }
        public static void WriteRegister8(byte register, byte value)
        {
            // Direct port manipulation speeds taking Slave Select LOW before SPI action
            writeBuffer3[0] = (BaseAddW | (Address << 1));
            writeBuffer3[1] = register;
            writeBuffer3[2] = value;
            try
            {
                SpiGPIO.Write(writeBuffer3);
            }

            /* If initialization fails, display the exception and stop running */
            catch (Exception ex)
            {
                //statusText.Text = "\nFailed to Wrie to DAC";
            }// Send the byte
        }
        public static void WriteRegister16(byte register, UInt16 value)
        {
            writeBuffer4[0] = (BaseAddW | (Address << 1));
            writeBuffer4[1] = register;
            writeBuffer4[2] = (byte)(value >> 8);
            writeBuffer4[3] = (byte)(value & 0XFF);
            try
            {
                SpiGPIO.Write(writeBuffer4);
            }

            /* If initialization fails, display the exception and stop running */
            catch (Exception ex)
            {
                //statusText.Text = "\nFailed to Wrie to DAC";
            }
        }
 
        // Set the pin mode a pin at a time or all 16 in one go
        // any value other then Input is taken as output
        public static void setPinMode(byte pin, byte mode) 
        {
            if (pin > 15) return;               // only a 16bit port so do a bounds check, it cant be less than zero as this is a byte value
            if (mode == Input)
            {
                PinMode |= (UInt16)(1 << (pin));               // update the pinMode register with new direction
            }
            else
            {
                PinMode &= (UInt16)(~(1 << (pin)));            // update the pinMode register with new direction
            }
            WriteRegister16(IODIRA, PinMode);                // Call the generic word writer with start register and the mode cache
        }
        public static void setPinMode(UInt16 mode)
        {
            WriteRegister16(IODIRA, mode);
            PinMode = mode;
        }

        // Set the pullup a pin at a time or all 16 in one go
        // any value other than On is taken as off
        public static void pullupMode(byte pin, byte mode)
        {
            if (pin > 15) return;
            if (mode == On)
            {
                PullUpMode |= (UInt16)(1 << (pin));
            }
            else
            {
                PullUpMode &= (UInt16)(~(1 << (pin)));
            }
            WriteRegister16(GPPUA, PullUpMode);
        }
        public static void pullupMode(UInt16 mode)
        {
            WriteRegister16(GPPUA, mode);
            PullUpMode = mode;
        }

        // Set the inversion a pin at a time or all 16 in one go
        public static void InvertMode(byte pin, byte mode)
        {
            if (pin > 15) return;
            if (mode == On)
            {
                InversionMode |= (UInt16)(1 << (pin - 1));
            }
            else
            {
                InversionMode &= (UInt16)(~(1 << (pin - 1)));
            }
            WriteRegister16(IPOLA, InversionMode);
        }
        public static void InvertMode(UInt16 mode)
        {
            WriteRegister16(IPOLA, mode);
            InversionMode = mode;
        }

        // WRITE FUNCTIONS - BY WORD AND BY PIN

        public static void WritePin(byte pin, byte value)
        {
            if (pin > 15) return;
            if (value > 1) return;
            if (value == 1)
            {
                PinState |= (UInt16)(1 << pin);
            }
            else
            {
                PinState &= (UInt16)(~(1 << pin));
            }
            WriteRegister16(GPIOA, PinState);
        }
        public static void WriteWord(UInt16 value)
        {
            WriteRegister16(GPIOA, value);
            PinState = value;
        }

        // READ FUNCTIONS - BY WORD, BYTE ANWrite Register8 or WriteRegister16D BY PIN
        public static UInt16 ReadRegister16()
        {     
            writeBuffer4[0] = (BaseAddR | (Address << 1));
            writeBuffer4[1] = GPIOA;
            writeBuffer4[2] = 0;
            writeBuffer4[3] = 0;
            SpiGPIO.TransferFullDuplex(writeBuffer4, readBuffer4);
            return convertToInt(readBuffer4);                             // Return the constructed word, the format is 0x(register value)
        }
        public static byte ReadRegister8(byte register)
        {        // This function will read a single register, and return it
            writeBuffer3[0] = (BaseAddR | (Address << 1));  // Send the MCP23S17 opcode, chip address, and read bit
            writeBuffer3[1] = register;
            SpiGPIO.TransferFullDuplex(writeBuffer3, readBuffer3);
            return readBuffer4[2]; // convertToInt(readBuffer);                             // Return the constructed word, the format is 0x(register value)
        }
        public static UInt16 ReadPin(byte pin)
        {       
            if (pin > 15) return 0x00;                  // If the pin value is not valid (1-16) return, do nothing and return
            UInt16 value = ReadRegister16();                        // Initialize a variable to hold the read values to be returned
            UInt16 pinmask = (UInt16)(1 << pin);                        // Initialize a variable to hold the read values to be returned
            return ((value & pinmask) > 0) ? On : Off;  // Call the word reading function, extract HIGH/LOW information from the requested pin
        }

        private static UInt16 convertToInt(byte[] data)
    {
        // byte[0] = command, byte[1] register, byte[2] = data high, byte[3] = data low
        UInt16 result = (UInt16)(data[2] & 0xFF);
        result <<= 8;
        result += data[3];
        return result;
    }

}
}

Mainpage.xaml

C#
XAML Main Page layout
<Page
    x:Class="PIFace_Digital_II.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PIFace_Digital_II"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" Width="1680" Height="1050" >

    <Grid Background="White" BorderBrush="#FF0093B9" BorderThickness="10" CornerRadius="50"  >
        <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="98" Margin="945,40,0,0" VerticalAlignment="Top" Width="507" CornerRadius="5"/>
        <TextBlock x:Name="textBlock_Copy11" HorizontalAlignment="Left" Margin="945,40,0,0" TextWrapping="Wrap" Text="Outputs - Open Collector" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Width="507" TextAlignment="Center" Foreground="#FF0093B9"/>
        <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="98" Margin="446,40,0,0" VerticalAlignment="Top" Width="494" CornerRadius="5"/>
        <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="145" Margin="1460,723,0,0" VerticalAlignment="Top" Width="121" CornerRadius="5"/>
        <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="145" Margin="1461,558,0,0" VerticalAlignment="Top" Width="121" CornerRadius="5"/>
        <Image x:Name="image" HorizontalAlignment="Left" Height="904" Margin="384,138,0,0" VerticalAlignment="Top" Width="1079" Source="Assets/PIFaceDigitalII.JPG"/>
        <ToggleButton x:Name="RelayA" HorizontalAlignment="Left" Margin="1025,462,0,0" VerticalAlignment="Top"  Checked="RelayA_Checked" Unchecked="RelayA_Unchecked" Width="275" Height="160" ToolTipService.ToolTip="Click with the mouse to toggle Relay R1 on and off wih Output 1">
            <Image x:Name="RelayAImage"  Source="Assets/Relay_OFF.jpg"  />
        </ToggleButton>
        <ToggleButton x:Name="RelayB" HorizontalAlignment="Left" Margin="1036,715,0,0" VerticalAlignment="Top" Height="180" Width="275" Checked="RelayB_Checked" Unchecked="RelayB_Unchecked" BorderThickness="0" ToolTipService.ToolTip="Click with the mouse to toggle Relay R0 on and off wih Output 0">
            <Image x:Name="RelayBImage"  Source="Assets/Relay_OFF.jpg" Margin="0"  />
        </ToggleButton>
        <Button x:Name="Switch3" Content="Switch3" HorizontalAlignment="Left" Height="93" Margin="461,271,0,0" VerticalAlignment="Top" Width="90" ToolTipService.ToolTip="Click the button with the mouse to simulate S3 being pressed, You can also press the real one"/>
        <Button x:Name="Switch2" Content="Switch2" HorizontalAlignment="Left" Height="93" Margin="577,267,0,0" VerticalAlignment="Top" Width="93" ToolTipService.ToolTip="Click the button with the mouse to simulate S2 being pressed, You can also press the real one"/>
        <Button x:Name="Switch1" Content="Switch1" HorizontalAlignment="Left" Height="93" Margin="694,271,0,0" VerticalAlignment="Top" Width="93" ToolTipService.ToolTip="Click the button with the mouse to simulate S1 being pressed, You can also press the real one"/>
        <Button x:Name="Switch0" Content="Switch0" HorizontalAlignment="Left" Height="93" Margin="812,271,0,0" VerticalAlignment="Top" Width="93" ToolTipService.ToolTip="Click the button with the mouse to simulate S0 being pressed, You can also press the real one"/>
        <ToggleButton x:Name="LED7" Content="7" HorizontalAlignment="Left" Height="73" Margin="958,250,0,0" VerticalAlignment="Top" Width="30" Checked="LED7_Checked" Unchecked="LED7_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 7"/>
        <ToggleButton x:Name="LED6" Content="6" HorizontalAlignment="Left" Height="73" Margin="1012,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED6_Checked" Unchecked="LED6_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 6"/>
        <ToggleButton x:Name="LED5" Content="5" HorizontalAlignment="Left" Height="73" Margin="1065,250,0,0" VerticalAlignment="Top" Width="32" Checked="LED5_Checked" Unchecked="LED5_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 5"/>
        <ToggleButton x:Name="LED4" Content="4" HorizontalAlignment="Left" Height="73" Margin="1121,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED4_Checked" Unchecked="LED4_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 4"/>
        <ToggleButton x:Name="LED3" Content="3" HorizontalAlignment="Left" Height="73" Margin="1179,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED3_Checked" Unchecked="LED3_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 3"/>
        <ToggleButton x:Name="LED2" Content="2" HorizontalAlignment="Left" Height="73" Margin="1234,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED2_Checked" Unchecked="LED2_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 2"/>
        <ToggleButton x:Name="LED1" Content="1" HorizontalAlignment="Left" Height="73" Margin="1290,250,0,0" VerticalAlignment="Top" Width="30" Checked="LED1_Checked" Unchecked="LED1_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 1 and Relay R1"/>
        <ToggleButton x:Name="LED0" Content="0" HorizontalAlignment="Left" Height="73" Margin="1343,250,0,0" VerticalAlignment="Top" Width="30" Checked="LED0_Checked" Unchecked="LED0_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 0 and Relay R2"/>
        <Image x:Name="image0" HorizontalAlignment="Left" Height="50" Margin="890,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png" />
        <Image x:Name="image1" HorizontalAlignment="Left" Height="50" Margin="831,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
        <Image x:Name="image2" HorizontalAlignment="Left" Height="50" Margin="776,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png" />
        <Image x:Name="image3" HorizontalAlignment="Left" Height="50" Margin="721,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png" />
        <Image x:Name="image4" HorizontalAlignment="Left" Height="50" Margin="666,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
        <Image x:Name="image5" HorizontalAlignment="Left" Height="50" Margin="611,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
        <Image x:Name="image6" HorizontalAlignment="Left" Height="50" Margin="556,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
        <Image x:Name="image7" HorizontalAlignment="Left" Height="50" Margin="501,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
        <Image x:Name="imageOn" Grid.Column="1" HorizontalAlignment="Left" Height="51" Margin="409,74,0,0" VerticalAlignment="Top" Width="61" Source="Assets/green-led-on-md.png" Visibility="Collapsed"/>
        <Image x:Name="imageOff" Grid.Column="1" HorizontalAlignment="Left" Height="50" Margin="475,74,0,0" VerticalAlignment="Top" Width="55" Source="Assets/green-led-off-md.png" Visibility="Collapsed"/>
        <Image x:Name="RelayOn" Grid.Column="1" HorizontalAlignment="Left" Height="51" Margin="409,74,0,0" VerticalAlignment="Top" Width="61" Source="Assets/Relay_ON.jpg" Visibility="Collapsed"/>
        <Image x:Name="RelayOff" Grid.Column="1" HorizontalAlignment="Left" Height="50" Margin="475,74,0,0" VerticalAlignment="Top" Width="55" Source="Assets/Relay_OFF.jpg" Visibility="Collapsed"/>
        <Image x:Name="image8" HorizontalAlignment="Left" Height="224.5" Margin="-312,449.5,0,0" VerticalAlignment="Top" Width="869.5" Source="Assets/Element14 Logo.png" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto">
            <Image.RenderTransform>
                <CompositeTransform Rotation="-90"/>
            </Image.RenderTransform>
        </Image>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="1468,819,0,0" TextWrapping="Wrap" Text="NO" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy" HorizontalAlignment="Left" Margin="1468,771,0,0" TextWrapping="Wrap" Text="C  - R0" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy1" HorizontalAlignment="Left" Margin="1468,723,0,0" TextWrapping="Wrap" Text="NC" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy2" HorizontalAlignment="Left" Margin="1463,660,0,0" TextWrapping="Wrap" Text="NO" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy3" HorizontalAlignment="Left" Margin="1468,606,0,0" TextWrapping="Wrap" Text="C  - R1" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy4" HorizontalAlignment="Left" Margin="1468,558,0,0" TextWrapping="Wrap" Text="NC" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="145" Margin="1461,396,0,0" VerticalAlignment="Top" Width="92" CornerRadius="5"/>
        <TextBlock x:Name="textBlock_Copy5" HorizontalAlignment="Left" Margin="1463,498,0,0" TextWrapping="Wrap" Text="GND" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy6" HorizontalAlignment="Left" Margin="1468,444,0,0" TextWrapping="Wrap" Text="GND" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy7" HorizontalAlignment="Left" Margin="1468,396,0,0" TextWrapping="Wrap" Text="5V" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
        <TextBlock x:Name="textBlock_Copy8" HorizontalAlignment="Left" Margin="1054,831,0,0" TextWrapping="Wrap" Text="R0" VerticalAlignment="Top" FontSize="32" FontWeight="Bold"/>
        <TextBlock x:Name="textBlock_Copy9" HorizontalAlignment="Left" Margin="1054,565,0,0" TextWrapping="Wrap" Text="R1" VerticalAlignment="Top" FontSize="32" FontWeight="Bold"/>
        <TextBlock x:Name="textBlock_Copy10" HorizontalAlignment="Left" Margin="446,40,0,0" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Width="494" TextAlignment="Center" Foreground="#FF0093B9">
        	<Run Text="Inputs"/>
        	<Run Text=" - Weak pullup"/>
        </TextBlock>
        <Button x:Name="btnExit" Content="Quit PiFaceDigital II" HorizontalAlignment="Left" Margin="55,33,0,0" VerticalAlignment="Top" Click="btnExit_Click" Height="108" Width="279" Foreground="White" FontSize="26.667" FontWeight="Bold" BorderBrush="#FF0093B9" ToolTipService.ToolTip="Click to exit the application, Come back soon!">
            <Button.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF0093B9" Offset="0"/>
                    <GradientStop Color="#FFF57E22" Offset="1"/>
                </LinearGradientBrush>
            </Button.Background>
        </Button>
        <TextBlock x:Name="textBlock_Copy12" HorizontalAlignment="Left" Margin="432,72,0,0" TextWrapping="Wrap" Text="GND" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" Foreground="#FF0192B8">
            <TextBlock.RenderTransform>
                <CompositeTransform Rotation="-90"/>
            </TextBlock.RenderTransform>
        </TextBlock>
        <TextBlock x:Name="textBlock_Copy13" HorizontalAlignment="Left" Margin="1403,84.5,0,0" TextWrapping="Wrap" Text="5V" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" Foreground="#FF0093B9">
            <TextBlock.RenderTransform>
                <CompositeTransform Rotation="-90"/>
            </TextBlock.RenderTransform>
        </TextBlock>
        <Image x:Name="image0_Out" HorizontalAlignment="Left" Height="50" Margin="1340,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" />
        <Image x:Name="image1_Out" HorizontalAlignment="Left" Height="50" Margin="1281,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
        <Image x:Name="image2_Out" HorizontalAlignment="Left" Height="50" Margin="1226,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" />
        <Image x:Name="image3_Out" HorizontalAlignment="Left" Height="50" Margin="1171,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" />
        <Image x:Name="image4_Out" HorizontalAlignment="Left" Height="50" Margin="1116,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
        <Image x:Name="image5_Out" HorizontalAlignment="Left" Height="50" Margin="1061,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
        <Image x:Name="image6_Out" HorizontalAlignment="Left" Height="50" Margin="1006,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
        <Image x:Name="image7_Out" HorizontalAlignment="Left" Height="50" Margin="951,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
        <Image x:Name="imageROn" HorizontalAlignment="Left" Height="50" Margin="1495,148,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-on-md.png" Visibility="Collapsed"/>
        <Image x:Name="imageROff" HorizontalAlignment="Left" Height="50" Margin="1495,213,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" Visibility="Collapsed"/>
        <TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="-119.25,530.75,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="755" Height="94.5" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" FontSize="40" FontWeight="Bold" FontFamily="Arial Black" Text="Brought to you by theBreadboard.ca  Youtube.com/user/thebreadboardca" Foreground="#FFFACAA1" TextAlignment="Center">
            <TextBlock.RenderTransform>
                <CompositeTransform Rotation="-90"/>
            </TextBlock.RenderTransform>
        </TextBlock>
        <TextBlock x:Name="textBlock2" HorizontalAlignment="Left" Margin="1471,50,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="180" FontSize="18.667" FontWeight="Bold" Foreground="#FF0092B9" TextAlignment="Center" Height="333">
        	<Run Text="Indicators are updated 5 times per second"/>
        	<LineBreak/>
        	<Run/>
        	<LineBreak/>
        	<Run Text="If yo"/>
        	<Run Text="u"/>
        	<Run Text=" ground an input the LED will light"/>
        	<LineBreak/>
        	<Run/>
        	<LineBreak/>
        	<Run Text="C"/>
        	<Run Text="lick an Output LED"/>
        	<Run Text=" to toggle its state"/>
        	<LineBreak/>
        	<Run/>
        	<LineBreak/>
        	<Run Text="LED0 and 1 also drive the Relays"/>
        	<LineBreak/>
        	<Run/>
        </TextBlock>
    </Grid>
</Page>

MainPage.xaml.cs

C#
Code behind for the MainPage.xaml
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Controls;
using SPI_GPIO;
using Windows.UI.Xaml.Input;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace PIFace_Digital_II
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private DispatcherTimer timer;         // create a timer
        private const byte Off = MCP23S17.Off;
        private const byte On = MCP23S17.On;
        public MainPage()
        {
            this.InitializeComponent();
            /* Register for the unloaded event so we can clean up upon exit */
            Unloaded += MainPage_Unloaded;

            /* Initialize GPIO, SPI, and the display */
            InitAll(); 

        }
        private void MainPage_Unloaded(object sender, object args)
        {
            /* Cleanup */
        }

        private void initTimer()
        {
            // read timer
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(200); //sample every 200mS
            timer.Tick += Timer_Tick;
            timer.Start();
        }
        // read GPIO and display it
        private void Timer_Tick(object sender, object e)
        {
            LightLEDs(MCP23S17.ReadRegister16());    // do something with the values
        }

        /* Initialize GPIO, SPI, and the display */
        private async void InitAll()
        {
            try
            {
                await MCP23S17.InitSPI();

                MCP23S17.InitMCP23S17();
                MCP23S17.setPinMode(0x00FF); // 0x0000 = all outputs, 0xffff=all inputs, 0x00FF is PIFace Default
                MCP23S17.pullupMode(0x00FF); // 0x0000 = no pullups, 0xffff=all pullups, 0x00FF is PIFace Default
                MCP23S17.WriteWord(0x0000); // 0x0000 = no pullups, 0xffff=all pullups, 0x00FF is PIFace Default
                Switch0.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch0_PointerPressed), true);
                Switch0.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch0_PointerReleased), true);
                Switch1.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch1_PointerPressed), true);
                Switch1.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch1_PointerReleased), true);
                Switch2.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch2_PointerPressed), true);
                Switch2.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch2_PointerReleased), true);
                Switch3.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch3_PointerPressed), true);
                Switch3.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch3_PointerReleased), true);

                initTimer();
            }
            catch (Exception ex)
            {
                //Text_Status.Text = "Exception: " + ex.Message;
                //if (ex.InnerException != null)
                //{
                //    Text_Status.Text += "\nInner Exception: " + ex.InnerException.Message;
                //}
                //return;
            }
        }

        private void LightLEDs(UInt16 Inputs)
        {
            image0.Source = ((Inputs & 1 << PFDII.IN0) != 0 && !Switch0.IsPressed) ? imageOn.Source : imageOff.Source;
            image1.Source = ((Inputs & 1 << PFDII.IN1) != 0 && !Switch1.IsPressed) ? imageOn.Source : imageOff.Source;
            image2.Source = ((Inputs & 1 << PFDII.IN2) != 0 && !Switch2.IsPressed) ? imageOn.Source : imageOff.Source;
            image3.Source = ((Inputs & 1 << PFDII.IN3) != 0 && !Switch3.IsPressed) ? imageOn.Source : imageOff.Source;
            image4.Source = ((Inputs & 1 << PFDII.IN4) != 0) ? imageOn.Source : imageOff.Source;
            image5.Source = ((Inputs & 1 << PFDII.IN5) != 0) ? imageOn.Source : imageOff.Source;
            image6.Source = ((Inputs & 1 << PFDII.IN6) != 0) ? imageOn.Source : imageOff.Source;
            image7.Source = ((Inputs & 1 << PFDII.IN7) != 0) ? imageOn.Source : imageOff.Source;

            image0_Out.Source = ((Inputs & 1 << PFDII.LED0) != 0) ? imageROn.Source : imageROff.Source;
            image1_Out.Source = ((Inputs & 1 << PFDII.LED1) != 0) ? imageROn.Source : imageROff.Source;
            image2_Out.Source = ((Inputs & 1 << PFDII.LED2) != 0) ? imageROn.Source : imageROff.Source;
            image3_Out.Source = ((Inputs & 1 << PFDII.LED3) != 0) ? imageROn.Source : imageROff.Source;
            image4_Out.Source = ((Inputs & 1 << PFDII.LED4) != 0) ? imageROn.Source : imageROff.Source;
            image5_Out.Source = ((Inputs & 1 << PFDII.LED5) != 0) ? imageROn.Source : imageROff.Source;
            image6_Out.Source = ((Inputs & 1 << PFDII.LED6) != 0) ? imageROn.Source : imageROff.Source;
            image7_Out.Source = ((Inputs & 1 << PFDII.LED7) != 0) ? imageROn.Source : imageROff.Source;

        }

        //Note RelayA = R1, RelayB = R0
        private void RelayA_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.RelayA , On);
            RelayAImage.Source =  RelayOn.Source;
            LED1.IsChecked = true; ;
        }

        private void RelayB_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.RelayB, On);
            RelayBImage.Source = RelayOn.Source;
            LED0.IsChecked = true; ;
        }

        private void RelayA_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.RelayA, Off);
            RelayAImage.Source = RelayOff.Source;
            LED1.IsChecked = false; ;
        }

        private void RelayB_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.RelayB, Off);
            RelayBImage.Source = RelayOff.Source;
            LED0.IsChecked = false; ;
        }

        private void LED0_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED0, On);
            RelayB.IsChecked = true; // LED0 and RelayA are the same output pin
        }

        private void LED1_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED1, On);
            RelayA.IsChecked = true; // LED1 and RelayB are the same output pin
        }

        private void LED2_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED2, On);
        }

        private void LED3_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED3, On);
        }

        private void LED4_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED4, On);
        }

        private void LED5_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED5, On);
        }

        private void LED6_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED6, On);
        }

        private void LED7_Checked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED7, On);
        }

        private void LED0_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED0, Off);
            RelayB.IsChecked = false; // LED0 and RelayA are the same output pin

        }

        private void LED1_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED1, Off);
            RelayA.IsChecked = false; // LED1 and RelayB are the same output pin
        }

        private void LED2_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED2, Off);
        }

        private void LED3_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED3, Off);
        }

        private void LED4_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED4, Off);
        }

        private void LED5_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED5, Off);
        }

        private void LED6_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED6, Off);
        }

        private void LED7_Unchecked(object sender, RoutedEventArgs e)
        {
            MCP23S17.WritePin(PFDII.LED7, Off);
        }

        private void Switch0_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch0.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
        }

        private void Switch0_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch0.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
        }
        private void Switch1_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch1.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
        }

        private void Switch1_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch1.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
        }
        private void Switch2_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch2.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
        }

        private void Switch2_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch2.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
        }
        private void Switch3_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch3.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
        }

        private void Switch3_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            Switch3.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
        }

        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            App.Current.Exit(); // exit the app
        }
    } // End of Class
} // End of NS

PiFaceDigital2.cs

C#
A helper class linrary for PiFace Digital 2 pins and other variables to make it easy to use
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SPI_GPIO
{
    public class PFDII
    {
        public const byte LED0 = 0x08;     // I/O Direction Register
        public const byte LED1 = 0x09;      // 1 = Input (default), 0 = Output
        public const byte LED2 = 0x0A;     // MCP23x17 Input Polarity Register
        public const byte LED3 = 0x0B;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
        public const byte LED4 = 0x0C;     // MCP23x17 Interrupt on Change Pin Assignements
        public const byte LED5 = 0x0D;      // 1 = Input (default), 0 = Output
        public const byte LED6 = 0x0E;     // MCP23x17 Input Polarity Register
        public const byte LED7 = 0x0F;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)

        public const byte IN0 = 0x00;     // I/O Direction Register
        public const byte IN1 = 0x01;      // 1 = Input (default), 0 = Output
        public const byte IN2 = 0x02;     // MCP23x17 Input Polarity Register
        public const byte IN3 = 0x03;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
        public const byte IN4 = 0x04;     // MCP23x17 Interrupt on Change Pin Assignements
        public const byte IN5 = 0x05;      // 1 = Input (default), 0 = Output
        public const byte IN6 = 0x06;     // MCP23x17 Input Polarity Register
        public const byte IN7 = 0x07;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)

        public const byte Sw0 = IN0;     // I/O Direction Register
        public const byte Sw1 = IN1;      // 1 = Input (default), 0 = Output
        public const byte Sw2 = IN2;     // MCP23x17 Input Polarity Register
        public const byte Sw3 = IN3;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)

        public const byte RelayA = LED1;     // MCP23x17 Input Polarity Register
        public const byte RelayB = LED0;     // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
    }
}

Credits

Peter Oakes

Peter Oakes

6 projects • 37 followers
Electronics Engineer, Programmer, and love to make Videos on Electronics Engineering related stuff and post on my YouTube Channel "thebreadboardca"

Comments