Peter Oakes
Published

SHARP96 LCD Displays on a PI 2, Windows 10 IoT

How to drive SHARP96 LS013B4DN04 LCD Displays from a PI 2 with Win10 for IoT. For more see, https://www.youtube.com/c/thebreadboard

IntermediateFull instructions provided3,514
SHARP96 LCD Displays on a PI 2, Windows 10 IoT

Things used in this project

Hardware components

Raspberry Pi 2 Model B
Raspberry Pi 2 Model B
×1
430BOOST-SHARP96
×1
SHARP MEMORY DISPLAY BREAKOUT - 1.3" 96X96 SILVER MONOCHROME
×1

Story

Read more

Schematics

Pi Header connections

Ti Boosterpack connections

Code

mainpage.xaml.cs

C#
using System;
using Windows.Security.Cryptography;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using SHARP96Driver;
using System.Threading.Tasks;


// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace SHARP96Test
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {

        sharp96Display display1 ;
        sharp96Display display2 ;
        private static DispatcherTimer timer; // for VCOM refresh of displays
        bool fontsizecaptured = false;
        double fontsizeX1 = 0;

        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();

        }
        /* Initialize GPIO, SPI, and the display */
        private async void InitAll()
        {
            try
            {
                await Sharp96.InitSPI();
                //Sharp96.InitGPIO();
                 display1 = new sharp96Display("\n    Display 1\n\n brought to you\n       by\n\nthebreadboard.ca\n      and\n\n    Element14", sharp96Display.SHARP_BLACK, 5); // using GPIO 5 for CS as the CS0 and 1 work the wrong way
                 display2 = new sharp96Display("\n    Display 2\n\n brought to you\n       by\n\nthebreadboard.ca\n      and\n\n    Element14", sharp96Display.SHARP_WHITE, 6); // using GPIO 6 for CS as the CS0 and 1 work the wrong way
                InitSharp96(); // do this last so we dont kick non existant displays

            }
            /* If initialization fails, display the exception and stop running */
            catch (Exception ex)
            {
                Text_Status.Text = "Exception: " + ex.Message;
                if (ex.InnerException != null)
                {
                    Text_Status.Text += "\nInner Exception: " + ex.InnerException.Message;
                }
                return;
            }
        }
        public void InitSharp96()
        {
            // Start the VCOM toggle
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(100);
            timer.Tick += Timer_Tick;
            timer.Start();
        }
        // Send out the alternating VCOM to prevent screen bias build up
        private void Timer_Tick(object sender, object e)
        {
            // Somewhere to do stuff in the background
            // like the screen VCOM to prevent static buildup messing the display
            Sharp96.Sharp96x96_SendToggleVCOMCommand(display1);
            Sharp96.Sharp96x96_SendToggleVCOMCommand(display2);
        }
        private void MainPage_Unloaded(object sender, object args)
        {
            /* Cleanup */

        }
        // clear both screens to silver
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Sharp96.Sharp96x96_ClearScreen(display1, 0x00);
            Sharp96.Sharp96x96_ClearScreen(display2, 0x00);
        }
        // clear both screens to white
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            Sharp96.Sharp96x96_ClearScreen(display1, 0xFF);
            Sharp96.Sharp96x96_ClearScreen(display2, 0xFF);
        }
        // Run a DEMO loop, adjust speed with onscreen slider and forever loop with checkbox
        private async void button4_Click(object sender, RoutedEventArgs e)
        {
            bool doneOneloop = false;
            sharp96Display nextDisplay;
            try
            {
                while (LoopDemo.IsChecked == true || doneOneloop == false)
                {
                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display2 : display1;
                    doneOneloop = true;
                    Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0xFF);
                    Sharp96.Graphics_Rectangle rect = new Sharp96.Graphics_Rectangle();
                    rect.XMin = 0;
                    rect.XMax = 95;
                    rect.YMin = 0;
                    rect.YMax = 95;
                    Sharp96.Sharp96x96_RectFill(nextDisplay, rect, 0x0);
                    rect.XMin = 20;
                    rect.XMax = 76;
                    rect.YMin = 20;
                    rect.YMax = 76;
                    Sharp96.Sharp96x96_RectFill(nextDisplay, rect, 0x1);
                    rect.XMin = 40;
                    rect.XMax = 56;
                    rect.YMin = 40;
                    rect.YMax = 56;
                    Sharp96.Sharp96x96_RectFill(nextDisplay, rect, 0x0);
                    Sharp96.Sharp96x96_Flush(nextDisplay);
                    await Task.Delay((int)LoopDelay.Value);

                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display1 : display2;
                    Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0xFF);
                    for (int x = 0; x < sharp96Display.LCD_HORIZONTAL_MAX / 2 - 1; x += 2)
                    {
                        int x2 = sharp96Display.LCD_VERTICAL_MAX - 1 - x;
                        int y = x;
                        int y2 = sharp96Display.LCD_VERTICAL_MAX - 1 - y;
                        Sharp96.Sharp96x96_LineDrawH(nextDisplay, x, x2, y, 0);
                        Sharp96.Sharp96x96_LineDrawH(nextDisplay, x, x2, y2, 0);
                        Sharp96.Sharp96x96_LineDrawV(nextDisplay, x, y, y2, 0);
                        Sharp96.Sharp96x96_LineDrawV(nextDisplay, x2, y, y2, 0);

                    }
                    Sharp96.Sharp96x96_Flush(nextDisplay);
                    Task.Delay((int)LoopDelay.Value);

                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display1 : display2;
                    Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0xFF);
                    for (int x = 0; x < 50; x++)
                    {
                        Sharp96.Sharp96x96_drawLine(nextDisplay, GenerateRndNumber(), GenerateRndNumber(), GenerateRndNumber(), GenerateRndNumber(), 0);
                    }
                    Sharp96.Sharp96x96_Flush(nextDisplay);
                    await Task.Delay((int)LoopDelay.Value);

                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display1 : display2;
                    Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0xFF);
                    Sharp96.Arc(nextDisplay, 6, 6, 83, 90, 180, 0);
                    Sharp96.Arc(nextDisplay, 89, 89, 83, 270, 360, 0);
                    Sharp96.Arc(nextDisplay, 6, 89, 83, 0, 90, 0);
                    Sharp96.Arc(nextDisplay, 89, 6, 83, 180, 270, 0);
                    Sharp96.DrawCircle(nextDisplay, 48, 48, 41, 0);
                    Sharp96.Sharp96x96_Flush(nextDisplay);
                    await Task.Delay((int)LoopDelay.Value);

                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display1 : display2;
                    Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0x00);
                    Sharp96.setCursor(nextDisplay, 15, 30);
                    Sharp96.write(nextDisplay, "Hello".ToCharArray(), 2, 1);
                    Sharp96.setCursor(nextDisplay, 32, 47);
                    Sharp96.write(nextDisplay, "Hi There".ToCharArray(), 1, 1);
                    Sharp96.Sharp96x96_Flush(nextDisplay);
                    await Task.Delay((int)LoopDelay.Value);

                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display1 : display2;
                    Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0xFF);
                    Sharp96.setCursor(nextDisplay, 0, 0);
                    Sharp96.write(nextDisplay, "Hi There".ToCharArray(), 1, 0);
                    Sharp96.setCursor(nextDisplay, 0, 9);
                    Sharp96.write(nextDisplay, "Hi There".ToCharArray(), 2, 0);
                    Sharp96.setCursor(nextDisplay, 0, 26);
                    Sharp96.write(nextDisplay, "Hi".ToCharArray(), 4,0);
                    Sharp96.setCursor(nextDisplay, 0, 53);
                    Sharp96.write(nextDisplay, "Hi".ToCharArray(), 6, 0);
                    Sharp96.Sharp96x96_Flush(nextDisplay);
                    await Task.Delay((int)LoopDelay.Value);

                    nextDisplay = (GenerateRndNumber() % 2 == 1) ? display1 : display2;
                    for (byte x = 1; x < 9; x++)
                    {
                        Sharp96.Sharp96x96_ClearScreen(nextDisplay, 0xFF);
                        Sharp96.setCursor(nextDisplay, 0, 0);
                        Sharp96.write(nextDisplay, "Hi".ToCharArray(), x, 0);
                        Sharp96.Sharp96x96_Flush(nextDisplay);
                        await Task.Delay((int)LoopDelay.Value);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        // Exit the program
        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            App.Current.Exit(); // exit the app
        }
        // Copy contents of Onscreen display 1 to the real display 1
        // not the onscreen is only an approximation and therefor
        // the real screen may look slightly different
        //You can change the font size with the big slider and edit the text boxes on the displays
        private void UpdateDisp1_Click(object sender, RoutedEventArgs e)
        {
            Sharp96.Sharp96x96_ClearScreen(display1, sharp96Display.SHARP_WHITE);
            Sharp96.setCursor(display1, 0, 0);
            Sharp96.write(display1, txtDisplay1.Text.ToCharArray(), (byte)font_Size.Value, sharp96Display.SHARP_BLACK);
            Sharp96.Sharp96x96_Flush(display1);

        }
        // Copy contents of Onscreen display 2 to the real display 2
        // not the onscreen is only an approximation and therefor
        // the real screen may look slightly different
        //You can change the font size with the big slider and edit the text boxes on the displays
        private void UpdateDisp2_Click(object sender, RoutedEventArgs e)
        {
            Sharp96.Sharp96x96_ClearScreen(display2, sharp96Display.SHARP_WHITE);
            Sharp96.setCursor(display2, 0, 0);
            Sharp96.write(display2, txtDisplay2.Text.ToCharArray(), (byte)font_Size.Value, sharp96Display.SHARP_BLACK);
            Sharp96.Sharp96x96_Flush(display2);

        }
        public UInt16 GenerateRndNumber()
        {
            // Generate a random number.
            UInt32 Rnd = CryptographicBuffer.GenerateRandomNumber( ) % 96; //limit between 0 and 96
            return (UInt16)Rnd;
        }
        // Event handler, changes the onscreen FONT size and the setting for screen to real font size
        private void font_Size_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
        {
            // playing on the fact this is entered as a bug in XAML before anything is changed
            // so we capture the base setting for the font to use when we change it
            if (fontsizecaptured == false)
            {
                fontsizeX1 = txtDisplay1.FontSize;
                fontsizecaptured = true;
            }
            txtDisplay1.FontSize = font_Size.Value * fontsizeX1;
            txtDisplay2.FontSize = font_Size.Value * fontsizeX1;
        }
    }
}

mainpage.xaml

C#
<Page
    x:Class="SHARP96Test.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SHARP96Test"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="White" BorderBrush="#FF0192B0" BorderThickness="5" CornerRadius="10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10,68,25,68" Width="989" >
        <Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="59" Margin="490,532,0,0" VerticalAlignment="Top" Width="474" CornerRadius="3"/>
        <Button x:Name="button1" Content="Fill 0's" HorizontalAlignment="Left" Margin="396,538,0,0" VerticalAlignment="Top" Click="button1_Click" Height="48" Width="84" Background="#FF0198BB" Foreground="White" BorderBrush="#FFF07C20"/>
        <Button x:Name="button2" Content="Fill 1's" HorizontalAlignment="Left" Margin="298,538,0,0" VerticalAlignment="Top" Click="button2_Click" Height="48" Width="84" Background="#FF0198BB" Foreground="White" RenderTransformOrigin="0.293,5.135" BorderBrush="#FFF07C20"/>
        <Button x:Name="button4" Content="DEMO" HorizontalAlignment="Left" Margin="498,538,0,0" VerticalAlignment="Top" Click="button4_Click" Height="48" Width="87" Background="#FF0198BB" Foreground="White" BorderBrush="#FFF07C20"/>
        <CheckBox x:Name="LoopDemo" Content="Loop" HorizontalAlignment="Left" Margin="598,547,0,0" VerticalAlignment="Top" Height="23" Width="87"/>
        <TextBlock x:Name="Text_Status" HorizontalAlignment="Left" Margin="296,591,0,0" TextWrapping="Wrap" Text="Status" VerticalAlignment="Top" Width="463" Height="31"/>
        <Image x:Name="image" HorizontalAlignment="Left" Height="254" Margin="298,171,0,0" VerticalAlignment="Top" Width="251" Source="Assets/430BOOST-SHARP96.png"/>
        <Image x:Name="image1" HorizontalAlignment="Left" Height="254" Margin="557,171,0,0" VerticalAlignment="Top" Width="251" Source="Assets/430BOOST-SHARP96.png"/>
        <Image x:Name="image2" HorizontalAlignment="Left" Height="110" Margin="296,59,0,0" VerticalAlignment="Top" Width="490" Source="Assets/Windows+10+IoT+Raspberry+Pi.jpg"/>
        <Button x:Name="UpdateDisp1" Content="Update" HorizontalAlignment="Left" Margin="362,434,0,0" VerticalAlignment="Top" Background="#FF0198BB" Foreground="White" Height="53" Width="126" Click="UpdateDisp1_Click" BorderBrush="#FFF07C20"/>
        <Button x:Name="UpdateDisp2" Content="Update" HorizontalAlignment="Left" Margin="606,434,0,0" VerticalAlignment="Top" Background="#FF0198BB" Foreground="White" Height="53" Width="126" Click="UpdateDisp2_Click" BorderBrush="#FFF07C20"/>
        <Image x:Name="image3" HorizontalAlignment="Left" Height="110.607" Margin="-95.559,317.454,0,0" VerticalAlignment="Top" Width="487.237" Source="Assets/Element14 LOGO.jpg" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto">
            <Image.RenderTransform>
                <CompositeTransform Rotation="-90"/>
            </Image.RenderTransform>
        </Image>
        <TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="-4.338,317.65,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="478.828" Height="97.328" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" FontSize="26.667" FontWeight="Bold" FontFamily="Arial Black" Text="Brought to you by theBreadboard.ca  Youtube.com/c/thebreadboardca" Foreground="#FFFACAA1" TextAlignment="Center">
            <TextBlock.RenderTransform>
                <CompositeTransform Rotation="-90"/>
            </TextBlock.RenderTransform>
        </TextBlock>
        <Button x:Name="btnExit" Content="Quit Demo" HorizontalAlignment="Left" Margin="100,64,0,0" VerticalAlignment="Top" Click="btnExit_Click" Height="65" Width="158" 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>
        <TextBox x:Name="txtDisplay1" HorizontalAlignment="Left" Margin="318,198,0,0" TextWrapping="Wrap" Text="Hello and Welcome to Display 1, you can have up to 144 characters at this font size of 6*8, well actually 16 * 12 lines to be exact, When you edit in this box, it even does spell checking.. nice" VerticalAlignment="Top" Background="{x:Null}" Height="167" Width="182" AcceptsReturn="True" PlaceholderText="" ToolTipService.ToolTip="Type your text here and press upload to send to the display, note it may not render exactly the same on the display due to differences in the scaling etc" MaxLength="144" FontSize="14.667" FontFamily="Global Monospace">
            <TextBox.Foreground>
                <SolidColorBrush Color="{ThemeResource SystemChromeBlackMediumColor}"/>
            </TextBox.Foreground>
        </TextBox>
        <TextBox x:Name="txtDisplay2" HorizontalAlignment="Left" Margin="577,198,0,0" TextWrapping="Wrap" Text="     Hi There&#xD;&#xA;  Volts = 50.0mV&#xD;&#xA;   Temp = 23C&#xD;&#xA;    Hum = 66%&#xD;&#xA;   &#xD;&#xA;And more can Be shown with ease if you take the time to format it" VerticalAlignment="Top" Background="{x:Null}" Height="167" Width="182" AcceptsReturn="True" PlaceholderText="" ToolTipService.ToolTip="Type your text here and press upload to send to the display, note it may not render exactly the same on the display due to differences in the scaling etc" MaxLength="144" FontSize="14.667" FontFamily="Global Monospace">
            <TextBox.Foreground>
                <SolidColorBrush Color="{ThemeResource SystemChromeBlackMediumColor}"/>
            </TextBox.Foreground>
        </TextBox>
        <Slider x:Name="font_Size" HorizontalAlignment="Left" Height="38" Margin="298,492,0,0" VerticalAlignment="Top" Width="488" LargeChange="1" Maximum="8" Minimum="1" TickFrequency="1" ToolTipService.ToolTip="Select the Font Size" Value="1" ValueChanged="font_Size_ValueChanged"/>
        <Image x:Name="image4" HorizontalAlignment="Left" Height="563" Margin="791,59,0,0" VerticalAlignment="Top" Width="173" Source="Assets/SHARP96 RPI2 HEADER.png"/>
        <TextBlock x:Name="textBlock1_Copy" HorizontalAlignment="Left" Margin="67.726,11.67,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="885.939" Height="34.154" RenderTransformOrigin="0.456,0.258" UseLayoutRounding="False" d:LayoutRounding="Auto" FontSize="32" FontWeight="Bold" FontFamily="Arial Black" Foreground="#FFF38323" TextAlignment="Center">
            <TextBlock.RenderTransform>
                <CompositeTransform Rotation="-0.175" TranslateX="-0.026" TranslateY="0.125"/>
            </TextBlock.RenderTransform>
        	<Run Text="Sharp96 ("/>
        	<Run Text="DUAL "/>
        	<Run Text="96*96 pixel "/>
        	<Run Text="SPI"/>
        	<Run Text=" displays on RPI2 IoT"/>
        </TextBlock>
        <Slider x:Name="LoopDelay" HorizontalAlignment="Left" Height="33" Margin="689,543,0,0" VerticalAlignment="Top" Width="229" Background="#FFFD7E28" BorderBrush="#FF0292B7" BorderThickness="2" Maximum="2000" LargeChange="100"  ToolTipService.ToolTip="Change Delay between steps from 1mS - 2 Seconds" Value="500" TickPlacement="None" Minimum="1"/>
    </Grid>
</Page>

SHARP96.cs

C#
using System;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.Spi;
using Windows.Devices.Gpio;

namespace SHARP96Driver
{
    public class sharp96Display
    {
        public string DefaultText ;
        public static UInt16 LCD_VERTICAL_MAX = 96; // Y
        public static UInt16 LCD_HORIZONTAL_MAX = 96; // X
        public static int SHARP_BLACK = 0x00;
        public static int SHARP_WHITE = 0xFF;
        public int VCOMbit;
        public GpioPin PIN;
        public byte cursorX;
        public byte cursorY;
        public byte[,] DisplayBuffer; // A working pixel buffer for your code
        public sharp96Display(string defaultText, int ulValue,  int pin)
        {
            //LCD_VERTICAL_MAX = 96;
            //LCD_HORIZONTAL_MAX = 96;
            //SHARP_BLACK = 0x00;
            //SHARP_WHITE = 0xFF;
            PIN = Sharp96.InitGPIO(pin, GpioPinDriveMode.Output, GpioPinValue.Low);
            cursorX = 0;
            cursorY = 0;
            VCOMbit = 0x40; // used to toggle the VCOM bit to prevent screen biasing
            DisplayBuffer = new byte[LCD_VERTICAL_MAX, LCD_HORIZONTAL_MAX / 8]; // A working pixel buffer for your code
            Sharp96.Sharp96x96_InitializeDisplayBuffer(this, (ulValue==0)? SHARP_BLACK: SHARP_WHITE) ;
            DefaultText = defaultText;
            Sharp96.write(this, defaultText.ToCharArray(), 1, (ulValue==0) ? SHARP_WHITE : SHARP_BLACK);
            if (PIN != null) Sharp96.Sharp96x96_Flush(this);
        }
    }

    public static class Sharp96
    {
        //*****************************************************************************
        //1.3-inch screen has 96x96 resolution (9216 pixels stripe array)
        // LCD Screen Dimensions
        //*****************************************************************************
        public const UInt16 LCD_VERTICAL_MAX = 96;  // Y
        public const UInt16 LCD_HORIZONTAL_MAX = 96; // X

        private static bool AutoWrap = true;
        //*****************************************************************************
        // for the Display Driver
        //*****************************************************************************
        public const int SHARP_BLACK = 0x00;
        public const int SHARP_WHITE = 0xFF;
        private const int SHARP_SEND_TOGGLE_VCOM_COMMAND = 0x01;
        private const int SHARP_SKIP_TOGGLE_VCOM_COMMAND = 0x00;
        private const int SHARP_LCD_TRAILER_BYTE = 0x00;
        private const int SHARP_VCOM_TOGGLE_BIT = 0x40;
        private const int SHARP_LCD_CMD_CHANGE_VCOM = 0x00;
        private const int SHARP_LCD_CMD_CLEAR_SCREEN = 0x20;
        private const int SHARP_LCD_CMD_WRITE_LINE = 0x80;
        public static byte[] reverse_data = { 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F };
        private static int VCOMbit = 0x40;
        private static int flagSendToggleVCOMCommand = 0;
        private const int ClrBlack = SHARP_BLACK;
        public struct Graphics_Rectangle
        {
            public int XMin;
            public int XMax;
            public int YMin;
            public int YMax;
        }
        //*****************************************************************************
        //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[] writeBuffer2 = new byte[2];// for simple comands like CLS or VCON
        private static byte[] writeBuffer1346 = new byte[1346];// for writing a buffer to the screen
        private static byte[] readBuffer4 = new byte[4]; /*this is defined to hold the output data*/
        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 = 5000000;// 500kHz;
                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 GpioPin InitGPIO(int GPIOpin, GpioPinDriveMode mode, GpioPinValue HiLow )
        {
            var gpio = GpioController.GetDefault();
            // Show an error if there is no GPIO controller
            if (gpio == null)
            {
                return null;
            }

            var pin = gpio.OpenPin(GPIOpin);

            if (pin == null)
            {
                return null;
            }
            pin.SetDriveMode(mode);
            pin.Write(HiLow);
            return pin;
        }

        //*******************************************************************************
        //
        //! Reverses the bit order.- Since the bit reversal function is called
        //! frequently by the several driver function this function is implemented
        //! to maximize code execution
        //
        // { 0x00,0x08,0x04,0x0C,0x02,0x0A,0x06,0x0E,0x01,0x09,0x05,0x0D,0x03,0x0B,0x07,0x0F }
        //
        //*******************************************************************************
        static byte Sharp96x96_reverse(byte x)
        {
            byte b = 0;

            b = (byte)(reverse_data[x & 0xF] << 4);
            b |= reverse_data[(x & 0xF0) >> 4];
            return b;
        }

        //*****************************************************************************
        //
        //! Initialize DisplayBuffer.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //!
        //!	\param ulValue is the foreground color of the buffered data.
        //!
        //! This function initializes the display buffer and discards any cached data.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_InitializeDisplayBuffer(sharp96Display display, int ulValue)
        {
            UInt16 i = 0, j = 0;
            for (i = 0; i < LCD_VERTICAL_MAX; i++)
                for (j = 0; j < (LCD_HORIZONTAL_MAX >> 3); j++)
                    display.DisplayBuffer[i, j] = (byte)ulValue;
        }

        //*****************************************************************************
        //
        //! Draws a pixel on the screen.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //! \param lX is the X coordinate of the pixel.
        //! \param lY is the Y coordinate of the pixel.
        //! \param ulValue is the color of the pixel.
        //!
        //! This function sets the given pixel to a particular color.  The coordinates
        //! of the pixel are assumed to be within the extents of the display.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_PixelDraw(sharp96Display display, UInt16 lX, UInt16 lY, int ulValue)
        {
            if ((lY >= LCD_VERTICAL_MAX) || (lX >= LCD_HORIZONTAL_MAX)) return;
            if (ClrBlack == ulValue)
            {
                display.DisplayBuffer[lY, lX >> 3] &= (byte)(~(0x80 >> (lX & 0x7)));
            }
            else
            {
                display.DisplayBuffer[lY, lX >> 3] |= (byte)((0x80 >> (lX & 0x7)));
            }
        }

        //*****************************************************************************
        //
        //! Draws a horizontal line.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //! \param lX1 is the X coordinate of the start of the line.
        //! \param lX2 is the X coordinate of the end of the line.
        //! \param lY is the Y coordinate of the line.
        //! \param ulValue is the color of the line.
        //!
        //! This function draws a horizontal line on the display.  The coordinates of
        //! the line are assumed to be within the extents of the display.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_LineDrawH(sharp96Display display, int lX1, int lX2, int lY, int ulValue)
        {
            // sanity check
            if(lX1 > lX2) { int temp = lX2; lX2 = lX1; lX1 = temp; }

                int xi = 0;
                int x_index_min = lX1 >> 3;
                int x_index_max = lX2 >> 3;
                int ucfirst_x_byte, uclast_x_byte;

                //calculate first byte
                //mod by 8 and shift this # bits
                ucfirst_x_byte = (byte)(0xFF >> (lX1 & 0x7));
                //calculate last byte
                //mod by 8 and shift this # bits
                uclast_x_byte = (byte)(0xFF << (7 - (lX2 & 0x7)));
            try
            {
                //check if more than one data byte
                if (x_index_min != x_index_max)
                {

                    //black pixels (clear bits)
                    if (ClrBlack == ulValue)
                    {
                        //write first byte
                        display.DisplayBuffer[lY, x_index_min] &= (byte)(~ucfirst_x_byte);

                        //write middle bytes
                        for (xi = x_index_min; xi < x_index_max - 1; xi++)
                        {
                            display.DisplayBuffer[lY, xi + 1] = 0x00;
                        }

                        //write last byte
                        display.DisplayBuffer[lY, xi + 1] &= (byte)(~uclast_x_byte);
                    }
                    //white pixels (set bits)
                    else
                    {
                        //write first byte
                        display.DisplayBuffer[lY, xi] |= (byte)(ucfirst_x_byte);

                        //write middle bytes
                        for (xi = x_index_min; xi < x_index_max - 1; xi++)
                        {
                            display.DisplayBuffer[lY, xi + 1] = 0xFF;
                        }

                        //write last byte
                        display.DisplayBuffer[lY, xi + 1] |= (byte)(uclast_x_byte);
                    }
                }
                //only one data byte
                else
                {
                    //calculate value of single byte
                    ucfirst_x_byte &= uclast_x_byte;

                    //draw black pixels (clear bits)
                    if (ClrBlack == ulValue)
                    {
                        display.DisplayBuffer[lY, xi] &= (byte)(~ucfirst_x_byte);
                    }
                    //white pixels (set bits)
                    else
                    {
                        display.DisplayBuffer[lY, xi] |= (byte)(ucfirst_x_byte);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
    }

        //*****************************************************************************
        //
        //! Draws a vertical line.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //! \param lX is the X coordinate of the line.
        //! \param lY1 is the Y coordinate of the start of the line.
        //! \param lY2 is the Y coordinate of the end of the line.
        //! \param ulValue is the color of the line.
        //!
        //! This function draws a vertical line on the display.  The coordinates of the
        //! line are assumed to be within the extents of the display.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_LineDrawV(sharp96Display display, int lX, int lY1, int lY2, int ulValue)
        {
            int yi = 0;
            int x_index = lX >> 3;
            int data_byte;

            //calculate data byte
            //mod by 8 and shift this # bits
            data_byte = (0x80 >> (lX & 0x7));

            //write data to the display buffer
            for (yi = lY1; yi <= lY2; yi++)
            {
                //black pixels (clear bits)
                if (ClrBlack == ulValue)
                {
                    display.DisplayBuffer[yi,x_index] &= (byte)(~data_byte);
                }
                //white pixels (set bits)
                else
                {
                    display.DisplayBuffer[yi,x_index] |= (byte)(data_byte);
                }
            }
        }

        //*****************************************************************************
        //
        //! Draws a line.
        //!
        //! \param context is a pointer to the drawing context to use.
        //! \param x1 is the X coordinate of the start of the line.
        //! \param y1 is the Y coordinate of the start of the line.
        //! \param x2 is the X coordinate of the end of the line.
        //! \param y2 is the Y coordinate of the end of the line.
        //!
        //! This function draws a line, utilizing Sharp96x96_LineDrawH() and 
        //! Sharp96x96_LineDrawV() to draw the line as efficiently as possible.  
        //! it proceeds using Bresenham's line drawing algorithm.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_drawLine(sharp96Display display, UInt16 x1, UInt16 y1, UInt16 x2, UInt16 y2, int ulValue)
            {
            UInt16 error, deltaX, deltaY;
            int yStep;
            bool SwapXY;

            // is this a vertical line as we can call an optimized routine for it
            if(x1 == x2)
            {
                Sharp96x96_LineDrawV(display, x1, y1, y2, ulValue);
                return;
            }
                    // is this a horizontal line as we can call an optimized routine for it
                    if (y1 == y2)
            {
                        Sharp96x96_LineDrawH(display, x1, y1, y2, ulValue);
                        return;
            }

            // Determine if the line is steep.  A steep line has more motion in the Y
            // direction than the X direction.
            if(((y2 > y1) ? (y2 - y1) : (y1 - y2)) > ((x2 > x1) ? (x2 - x1) : (x1 - x2)))
            {
                SwapXY = true;
            }
            else
            {
                SwapXY = false;
            }

            // If the line is steep, then swap the X and Y coordinates.
            if(SwapXY)
            {
                error = x1;
                x1 = y1;
                y1 = error;
                error = x2;
                x2 = y2;
                y2 = error;
            }

            //
            // If the starting X coordinate is larger than the ending X coordinate,
            // then swap the start and end coordinates.
            //
            if(x1 > x2)
            {
                error = x1;
                x1 = x2;
                x2 = error;
                error = y1;
                y1 = y2;
                y2 = error;
            }
            // Compute the difference between the start and end coordinates in each axis.
            deltaX = (UInt16)(x2 - x1);
            deltaY = (UInt16)((y2 > y1) ? (y2 - y1) : (y1 - y2));

            // Initialize the error term to negative half the X delta.
            error = (UInt16)(-deltaX / 2);

            // Determine the direction to step in the Y axis when required.
            if(y1<y2) yStep = 1;
            else yStep = -1;

            // Loop through all the points along the X axis of the line.
            for(; x1 <= x2; x1++)
            {
                // See if this is a steep line.
                if(SwapXY)
                {
                            // Plot this point of the line, swapping the X and Y coordinates.
                            Sharp96x96_PixelDraw(display, y1, x1, ulValue);
                }
                else
                {
                            // Plot this point of the line, using the coordinates as is.
                            Sharp96x96_PixelDraw(display, x1, y1, ulValue);
                        }
                        // Increment the error term by the Y delta.
                        error += deltaY;
                // See if the error term is now greater than zero.
                if(error > 0)
                {
                    // Take a step in the Y axis.
                    y1 = (UInt16)(y1 + yStep); // this could be a - or a + step
                    // Decrement the error term by the X delta.
                    error -= deltaX;
                }
            }
        }

        //*****************************************************************************
        //
        //! Fills a rectangle.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //! \param pRect is a pointer to the structure describing the rectangle.
        //! \param ulValue is the color of the rectangle.
        //!
        //! This function fills a rectangle on the display.  The coordinates of the
        //! rectangle are assumed to be within the extents of the display, and the
        //! rectangle specification is fully inclusive (in other words, both sXMin and
        //! sXMax are drawn, along with sYMin and sYMax).
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_RectFill(sharp96Display display, Graphics_Rectangle pRect, int ulValue)
        {
            // Bounds Checking, if there all out, simply return, if any are in then do what can be done
            if ((pRect.XMin >= LCD_HORIZONTAL_MAX) && (pRect.YMin >= LCD_VERTICAL_MAX) && (pRect.XMax >= LCD_HORIZONTAL_MAX) && (pRect.YMax >= LCD_VERTICAL_MAX)) return;
            if (pRect.XMin >= LCD_HORIZONTAL_MAX) pRect.XMin = LCD_HORIZONTAL_MAX-1;
            if (pRect.YMin >= LCD_VERTICAL_MAX) pRect.YMin = LCD_VERTICAL_MAX-1;
            if (pRect.XMax >= LCD_HORIZONTAL_MAX) pRect.XMax = LCD_HORIZONTAL_MAX-1;
            if (pRect.YMax >= LCD_VERTICAL_MAX) pRect.YMax = LCD_VERTICAL_MAX-1;
            int xi = 0;
            int yi = 0;
            int x_index_min = pRect.XMin >> 3;
            int x_index_max = pRect.XMax >> 3;
            byte ucfirst_x_byte, uclast_x_byte;


            //calculate first byte
            //mod by 8 and shift this # bits
            ucfirst_x_byte = (byte)(0xFF >> (pRect.XMin & 0x7));  

            //calculate last byte
            //mod by 8 and shift this # bits
            uclast_x_byte = (byte)(0xFF << (7-(pRect.XMax & 0x7)));   

            //check if more than one data byte
            if(x_index_min != x_index_max)
            {
		        //write bytes
		        for (yi = pRect.YMin; yi<= pRect.YMax; yi++)
		        {
			        //black pixels (clear bits)
			        if(ClrBlack == ulValue)
			        {
                        //write first byte
                        display.DisplayBuffer[yi, x_index_min] &= (byte)~ucfirst_x_byte;

				        //write middle bytes
				        for(xi = x_index_min+1; xi<x_index_max; xi++)
				        {
                            display.DisplayBuffer[yi, xi] = 0x00;
				        }

                        //write last byte
                        display.DisplayBuffer[yi, x_index_max] &= (byte)~uclast_x_byte;
                    }
			        //white pixels (set bits)
			        else
			        {
                        //write first byte
                        display.DisplayBuffer[yi, x_index_min] |= (byte)ucfirst_x_byte;

				        //write middle bytes
				        for(xi = x_index_min+1; xi<x_index_max; xi++)
				        {
                            display.DisplayBuffer[yi, xi] = 0xFF;
				        }

                        //write last byte
                        display.DisplayBuffer[yi, x_index_max] |= (byte)uclast_x_byte;
			        }
		        }       
	        }
	        //only one data byte
	        else
	        {
		        //calculate value of single byte
		        ucfirst_x_byte &= uclast_x_byte;

		        //black pixels (clear bits)
		        if(ClrBlack == ulValue)
		        {
                    //write bytes
                    for (yi = pRect.YMin; yi <= pRect.YMax; yi++)
                        display.DisplayBuffer[yi, x_index_min] &= (byte)~ucfirst_x_byte;
		        }
		        //white pixels (set bits)
		        else
		        {
                    for (yi = pRect.YMin; yi <= pRect.YMax; yi++)
                        display.DisplayBuffer[yi, x_index_min] |= (byte)ucfirst_x_byte;
		        }
	        }
        }

        //*****************************************************************************
        //
        //! Flushes any cached drawing operations.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //!
        //!
        //! This functions flushes any cached drawing operations to the display.  This
        //! is useful when a local frame buffer is used for drawing operations, and the
        //! flush would copy the local frame buffer to the display.
        //! it builds a byte array for the call for a single refresh operation
        //! for more info see http://www.sharpmemorylcd.com/resources/programming_memory_lcd_app_note.pdf
        //! \return None.
        //
        //*****************************************************************************
        public static async Task Sharp96x96_Flush(sharp96Display display)
        {
            byte xi = 0;
            byte yi = 0;
            //image update mode(1X000000b)
            int bufferIndex = 0;
            int command = SHARP_LCD_CMD_WRITE_LINE;

            //COM inversion bit
            command = command ^ VCOMbit;
            writeBuffer1346[bufferIndex++] = (byte)command;
            flagSendToggleVCOMCommand = SHARP_SKIP_TOGGLE_VCOM_COMMAND;

            for (yi = 0; yi < LCD_VERTICAL_MAX; yi++) // Vertical (y)
            {
                writeBuffer1346[bufferIndex++] = Sharp96x96_reverse((byte)(yi+1)) ; // Write row Address

                for (xi = 0; xi < (LCD_HORIZONTAL_MAX >> 3); xi++) // Horizontal (x) - should be 12 bytes for 96 bits
                {
                    writeBuffer1346[bufferIndex++] = display.DisplayBuffer[yi, xi];
                }
                writeBuffer1346[bufferIndex++] = SHARP_LCD_TRAILER_BYTE;
            }
            writeBuffer1346[bufferIndex] = SHARP_LCD_TRAILER_BYTE; // this is the last byte so it will overflow with a ++
            HAL_LCD_writeCommandOrData(display, writeBuffer1346);
        }

        //*****************************************************************************
        //
        //! Send command to clear screen.
        //!
        //! \param pvDisplayData is a pointer to the driver-specific data for this
        //! display driver.
        //! \param ulValue is the background color of the buffered data.
        //!
        //! This function sets every pixel to the background color.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_ClearScreen(sharp96Display display, int ulValue)
        {
            Sharp96x96_ClearScreen(display);

            if (ClrBlack == ulValue)
                Sharp96x96_InitializeDisplayBuffer(display, SHARP_BLACK);
            else
                Sharp96x96_InitializeDisplayBuffer(display, SHARP_WHITE);
            Sharp96x96_Flush(display);
        }
        public static void Sharp96x96_ClearScreen(sharp96Display display)
        {
            //clear screen mode(0X100000b)
            int command = SHARP_LCD_CMD_CLEAR_SCREEN;
            //COM inversion bit
            command = command ^ VCOMbit;

            writeBuffer2[0] = (byte)command;
            writeBuffer2[1] = SHARP_LCD_TRAILER_BYTE;
            HAL_LCD_writeCommandOrData(display, writeBuffer2);
            flagSendToggleVCOMCommand = SHARP_SKIP_TOGGLE_VCOM_COMMAND;
        }

        //*****************************************************************************
        //
        // Writes command or data to the LCD Driver
        //
        // \param ucCmdData is the 8 or 16 bit command to send to the LCD driver
        // Uses the SET_LCD_DATA macro
        //
        // \return None
        //
        //*****************************************************************************
        static void HAL_LCD_writeCommandOrData(sharp96Display display, byte[] command)
        {
            try
            {// ignoring real SS lines CS0 and CS1 as there wrong polarity
                display.PIN.Write(GpioPinValue.High);
                SpiGPIO.Write(command);
                display.PIN.Write(GpioPinValue.Low);
            }
            catch (Exception e)
            {
                throw new Exception(e.InnerException.Message); // Help Me !!!!
            }
        }

        //*****************************************************************************
        //
        //! Send toggle VCOM command.
        //!
        //! This function toggles the state of VCOM which prevents a DC bias from being
        //! built up within the panel.
        //!
        //! \return None.
        //
        //*****************************************************************************
        public static void Sharp96x96_SendToggleVCOMCommand(sharp96Display display)
        {
            display.VCOMbit ^= SHARP_VCOM_TOGGLE_BIT;

            if (SHARP_SEND_TOGGLE_VCOM_COMMAND == flagSendToggleVCOMCommand)
            {
                //clear screen mode(0X100000b)
                int command = SHARP_LCD_CMD_CHANGE_VCOM;
                //COM inversion bit
                command = command ^ display.VCOMbit;
                writeBuffer2[0] = (byte)command;
                writeBuffer2[1] = SHARP_LCD_TRAILER_BYTE;
                HAL_LCD_writeCommandOrData(display,writeBuffer2);
            }

            flagSendToggleVCOMCommand = SHARP_SEND_TOGGLE_VCOM_COMMAND;
        }

        public static void Arc(sharp96Display display, UInt16 lX, UInt16 lY, UInt16 Radius, UInt16 startAngle, UInt16 endAngle, int ulValue)
        {
            ArcEx(display, lX, lY, Radius, startAngle, endAngle, 0.1, ulValue);
        }
        public static void ArcEx(sharp96Display display, UInt16 lX, UInt16 lY, UInt16 Radius, UInt16 startAngle, UInt16 endAngle, double increment, int ulValue)
        {
            double startA = startAngle;
            double endA = endAngle;
            if (startA > 360) startA = 360;
            if (endA > 360) endA = 360;
            if (increment > 10) increment = 10.0;
            if (increment < 0.1) increment = 0.1;

            for (double i = startA; i < endA; i += increment)
            {
                double angle = i * System.Math.PI / 180;
                byte x = (byte)(lX + Radius * System.Math.Sin(angle));
                byte y = (byte)(lY - Radius * System.Math.Cos(angle));
                Sharp96x96_PixelDraw(display, x, y, ulValue);
            }
        }
        public static void DrawCircle(sharp96Display display, UInt16 x0, UInt16 y0, UInt16 radius, int ulValue)
        {
            // Based on https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
            int x = radius;
            int y = 0;
            int decisionOver2 = 1 - x;   // Decision criterion divided by 2 evaluated at x=r, y=0

            while (x >= y)
            {
                Sharp96x96_PixelDraw(display, (UInt16)(x + x0), (UInt16)(y + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(y + x0), (UInt16)(x + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(-x + x0), (UInt16)(y + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(-y + x0), (UInt16)(x + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(-x + x0), (UInt16)(-y + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(-y + x0), (UInt16)(-x + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(x + x0), (UInt16)(-y + y0), ulValue);
                Sharp96x96_PixelDraw(display, (UInt16)(y + x0), (UInt16)(-x + y0), ulValue);
                y++;
                if (decisionOver2 <= 0)
                {
                    decisionOver2 += 2 * y + 1;   // Change in decision criterion for y -> y+1
                }
                else
                {
                    x--;
                    decisionOver2 += 2 * (y - x) + 1;   // Change for y -> y+1, x -> x-1
                }
            }
        }
        public static void write(sharp96Display display, char[] c, byte textsize, int ulValue)
        {
            for (int len = 0; len < c.Length; len++)
            {
                write(display, c[len], textsize, ulValue);
            }
        }
        public static void write(sharp96Display display, char c, byte textsize, int ulValue)
        {
            // bounds check
            if (display.cursorY >= LCD_VERTICAL_MAX) return; // were off the screen
            if (c == '\n') // do we have a new line, if so simply adjust cursor position
            {
                display.cursorY += (byte)(textsize * 8);   // next line based on font size
                display.cursorX = 0;               // back to  character 0
            }
            else if (c == '\r')
            {
                display.cursorX = 0;               // back to  character 0
            }
            else
            {
                drawChar(display, display.cursorX, display.cursorY, (byte)c, textsize, ulValue);
                display.cursorX += (byte)(textsize * 6);
                if (AutoWrap && (display.cursorX > (LCD_HORIZONTAL_MAX - textsize * 6)))
                {
                    display.cursorY += (byte)(textsize * 8);   // next line based on font size
                    display.cursorX = 0;               // back to  character 0
                }
            }
        }
        public static void drawChar(sharp96Display display, UInt16 x, UInt16 y,  byte c, UInt16 size, int ulValue)
        {
            if ((x >= LCD_HORIZONTAL_MAX) || (y >= LCD_VERTICAL_MAX) || ((x + 6 * size - 1) < 0) || ((y + 8 * size - 1) < 0))   
                return;  // bounds checks

            for (byte i = 0; i < 6; i++) // 5*7 font + space
            {
                UInt16 line; // index into character font array
                if (i == 5) line = 0x0; // space between characters
                else line = DisplayFont.font[((c * 5) + i)];

                for (byte j = 0; j < 8; j++) // now process each bit of the character
                {// we have a bit and normal colour or no bit and inverted
                    if ( 
                        (((line & 0x1)==1) && (ulValue != 0)) || (((line & 0x1) == 0) && (ulValue == 0))
                        )       // do we have a bit and black pixels (clear bits)         
                    {
                        if (size == 1) // default size
                            Sharp96x96_PixelDraw(display, (UInt16)(x + i),(UInt16)(y + j), 0xFF);
                        else
                        {  // scaled up font
                            Graphics_Rectangle pRect;
                            pRect.XMin = x + (i * size);
                            pRect.YMin = y + (j * size);
                            pRect.XMax = pRect.XMin + size-1;
                            pRect.YMax = pRect.YMin + size-1;
                            Sharp96x96_RectFill(display, pRect, 0xFF);
                        }
                    }
                    else // no bit so clear it, we need to handle reverse colour at some point
                    {
                        if (size == 1) // default size
                            Sharp96x96_PixelDraw(display, (UInt16)(x + i),(UInt16)(y + j), 0x00);
                        else
                        {  // big size
                            Graphics_Rectangle pRect;
                            pRect.XMin = x + (i * size);
                            pRect.YMin = y + (j * size);
                            pRect.XMax = pRect.XMin + size-1;
                            pRect.YMax = pRect.YMin + size-1;
                            Sharp96x96_RectFill(display, pRect, 0x00);
                        }
                    }
                    line >>= 1; // next bit in the line
                }
            }
        }
        public static void setCursor(sharp96Display display, UInt16 x, UInt16 y)
        {
            // needs some bounds checking
            display.cursorX = (byte)x;
            display.cursorY = (byte)y;
        }
    }
}

Complete App as a Microsoft Visual Studio 2015 Solution

Plain text
No preview (download only).

DisplayFont.cs

This is called glcdfont.c on the adafruit github

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