Windows IoT and N18Display

Hello,

Someone has already try to connect N18Display with Raspberry pi and IoT ?
I can’t succeed to display anything !!! I just can enable and disable backligth !

Thanks for any help…

The operating system is not aware of spi connected devices. You would be drawing through whatever spi driver you implement.

@ Gus - Thanks for reply.
I can’t talk to spi device with this code ?


        protected override async Task Initialize(ISocket parentSocket)
        {
            _data = null;
            _spiDevice =
                await
                    parentSocket.CreateSpiDeviceAsync(new SpiConnectionSettings(0)
                    {
                        Mode = SpiMode.Mode0,
                        ClockFrequency = 12000
                    });
            _resetIo = await parentSocket.CreateDigitalIOAsync(SocketPinNumber.Three, false);
            _backlightIo = await parentSocket.CreateDigitalIOAsync(SocketPinNumber.Four, true);
            _cdIo = await parentSocket.CreateDigitalIOAsync(SocketPinNumber.Five, false);

Good starting point. Now you need to convert the gadgeteer driver.

@ Gus - In beginning of driver on GitHub there are these lines:


	public class DisplayN18 : GTM.Module.DisplayModule {
		private const byte ST7735_MADCTL = 0x36;
		private const byte MADCTL_MY = 0x80;
		private const byte MADCTL_MX = 0x40;
		private const byte MADCTL_MV = 0x20;
		private const byte MADCTL_BGR = 0x08;

What are theirs roles ? (I don’t see they appear anywhere in code).

Second question: N18Display is driven by ST7735 or ST7735R ?

And another question ! :slight_smile:
It seems that spi just accept writing byte and not ushort. Any tips on converting ? What I want is have a method:


        private void WriteData(ushort[] data)
{
      _cdIO.Write(true);
      _spi.Write(data); // But data is ushort[] and it only exists Write(byte[]).
}


But as they don’t appear anywhere in code, I think they are useless. Aren’t they ?

Thnaks a lot to make me look again !!! It was in code ! :wall: :wall: :wall: I think a pause is required …

After a pause, driver is rewritten, but now I just have a blank and white screen. Drawpixel seems do Nothing, and even clear function seems to not clear screen. Perhaps others eyes can see some stupid mistakes I wrote.


using System;
using System.Threading.Tasks;
using Windows.Devices.Spi;
using GHIElectronics.UWP.GadgeteerCore;
using GHIElectronics.UWP.GadgeteerCore.SocketInterfaces;
using SpiDevice = GHIElectronics.UWP.GadgeteerCore.SocketInterfaces.SpiDevice;

namespace N18Display
{
    public class N18Display : Module
    {
        public override string Name => "N18Display";
        public override string Manufacturer => "GHI";

        private SpiDevice _spiDevice;
        private DigitalIO _resetIo; // Hardware reset
        private DigitalIO _backlightIo; // backlight control
        private DigitalIO _cdIo; // command: false, data: true
        private byte[] _data;
        private ushort[] _ushortData;

        #region Command for ST7735
        private byte CASET = 0x2A;
        private byte RASET = 0x2B;
        private byte RAMWR = 0x2C;
        private byte DISPON = 0x29;
        private byte SLPOUT = 0x11;
        private byte FRMCTR1 = 0xB1;
        private byte FRMCTR2 = 0xB2;
        private byte FRMCTR3 = 0xB3;
        private byte INVCTR = 0xB4;
        private byte PWCTR1 = 0xC0;
        private byte PWCTR2=0xC1;
        private byte PWCTR3=0xC2;
        private byte PWCTR4=0xC3;
        private byte PWCTR5=0xC4;
        private byte VMCTR1=0xC5;
        private byte GMCTRP1=0xE0;
        private byte GMCTRN1=0xE1;
        private byte COLMOD=0x3A;
        private byte MADCTL=0x36;

        #endregion

        protected override async Task Initialize(ISocket parentSocket)
        {
            _data = null;
            _spiDevice =
                await
                    parentSocket.CreateSpiDeviceAsync(new SpiConnectionSettings(0)
                    {
                        Mode = SpiMode.Mode0,
                        ClockFrequency = 12000000,
                    });
            _resetIo = await parentSocket.CreateDigitalIOAsync(SocketPinNumber.Three, false);
            _backlightIo = await parentSocket.CreateDigitalIOAsync(SocketPinNumber.Four, true);
            _cdIo = await parentSocket.CreateDigitalIOAsync(SocketPinNumber.Five, false);
            _data = new byte[1];
            _ushortData = new ushort[2];
            Reset(); // Hard reset
            ConfigureDisplay();
            Clear();
        }

        private void ConfigureDisplay()
        {
            // ST7735R

            WriteCommand(SLPOUT); // Exit sleep mode
            Task.Delay(120);
            WriteCommand(FRMCTR1);
            WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
            WriteCommand(FRMCTR2);
            WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
            WriteCommand(FRMCTR3);
            WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
            WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
            WriteCommand(INVCTR); // Column inversion
            WriteData(0x07);

            // Power Sequence
            WriteCommand(PWCTR1);
            WriteData(0xA2); WriteData(0x02); WriteData(0x84);
            WriteCommand(PWCTR2);
            WriteData(0xc5);
            WriteCommand(PWCTR3);
            WriteData(0x0a); WriteData(0x00);
            WriteCommand(PWCTR4);
            WriteData(0x8a); WriteData(0x2a);
            WriteCommand(PWCTR5);
            WriteData(0x8a); WriteData(0xee);

            // VCOM
            WriteCommand(VMCTR1);
            WriteData(0x0e);

            // Mode address
            WriteCommand(MADCTL);
            WriteData(0xc8);
            //

            // Gamma Sequence
            WriteCommand(GMCTRP1);
            WriteData(0x0f); WriteData(0x1a); WriteData(0x0f); WriteData(0x18);
            WriteData(0x2f); WriteData(0x28); WriteData(0x20); WriteData(0x22);
            WriteData(0x1f); WriteData(0x1b); WriteData(0x23); WriteData(0x37);
            WriteData(0x00); WriteData(0x07); WriteData(0x02); WriteData(0x10);
            WriteCommand(GMCTRN1);
            WriteData(0x0f); WriteData(0x1b); WriteData(0x0f); WriteData(0x17);
            WriteData(0x33); WriteData(0x2c); WriteData(0x29); WriteData(0x2e);
            WriteData(0x30); WriteData(0x30); WriteData(0x39); WriteData(0x3f);
            WriteData(0x00); WriteData(0x07); WriteData(0x03); WriteData(0x10);

            WriteCommand(CASET);
            WriteData(0x00); WriteData(0x00); WriteData(0x00); WriteData(0x7f);
            WriteCommand(RASET);
            WriteData(0x00); WriteData(0x00); WriteData(0x00); WriteData(0x9f);

            WriteCommand(0xf0); // Enable test command
            WriteData(0x01);
            WriteCommand(0xf6); // Disable ram power save mode
            WriteData(0x00);
            WriteCommand(COLMOD); // 65k mode
            WriteData(0x05);
            WriteCommand(DISPON); // Display on
        }

        public bool Backlight
        {
            get { return _backlightIo.Read(); }
            set { _backlightIo.Write(value); }
        }

        public async void Reset()
        {
            _resetIo.Write(false);
            await Task.Delay(150);
            _resetIo.Write(true);
        }

        private void WriteCommand(byte command)
        {
            _data[0] = command;
            _cdIo.Write(false);
            _spiDevice.Write(_data);
        }

        private void WriteData(byte[] data)
        {
            _cdIo.Write(true);
            _spiDevice.Write(data);
        }

        private void WriteData(byte data)
        {
            _data[0] = data;
            WriteData(_data);
        }

        private void WriteData(ushort[] data)
        {
            _cdIo.Write(true);
            foreach (var us in data)
            {
            _spiDevice.Write(BitConverter.GetBytes(us));
                
            }
        }

        public void Clear()
        {
            var data = new byte[64 * 80 * 2];
            DrawRaw(data, 0, 0, 64, 80);
            DrawRaw(data, 64, 0, 64, 80);
            DrawRaw(data, 0, 80, 64, 80);
            DrawRaw(data, 64, 80, 64, 80);
        }

        public void DrawRaw(byte[] data, int x, int y, int width, int height)
        {
            SetClippingArea(x,y,width-1,height-1);
            WriteCommand(RAMWR);
            WriteData(data);
        }

        private void SetClippingArea(int x, int y, int width, int height)
        {
            _ushortData[0] = (ushort)x;
            _ushortData[1] = (ushort)(x + width);
            WriteCommand(CASET);
            WriteData(_ushortData);
            _ushortData[0] = (ushort)y;
            _ushortData[1] = (ushort)(y + height);
            WriteCommand(RASET);
            WriteData(_ushortData);
        }

        public void DrawPixel(int x, int y, byte r, byte g, byte b)
        {
            SetClippingArea(x,y,0,0);
            WriteCommand(RAMWR);
            WriteData(r);
            WriteData(g);
            WriteData(b);
        }
    }
}


Hi,
did you see this turorial?
https://developer.microsoft.com/en-us/windows/iot/samples/spidisplay

Do you have an oscilloscope or logicanalyser to see what happens at the pins?

I try to do simplest thing first: I only use Normal format. Format is in ConfigureDisplay after mode address comment.

@ RoSchmi - No I don’t have. I can be very easier.

I test communication with:


        public void ReadDisplayStatus()
        {
            _data[0] = RDDST;
            var readBuffer = new byte[4];
            _cdIo.Write(false);
            _spiDevice.Write(_data);
            _cdIo.Write(true);
            _spiDevice.Read(readBuffer);
        }

readbuffer is always containing 0. So I suspect a wrong communication with spi … But without analyzer it’s difficult to understand what’s happened !

@ Bauland - do you know if there are pull up resistors on CLCK, MOSI, MISO CS? If there are no pull-ups the signal might not be able to go high. I would try to apply a 10 KOhm resistor from 3.3 V power to each of the SPI datalines

Well, I finished to find an oscillo.
I try to send a command to read display power mode (0x0a).
Then I read and I should received 0x1c.

I obtain the image below on oscilloscope.
Three observations:
[ol] write command is correctly send,
read signal is too low to be read but it exists,
value is not what I expect[/ol]
Reason can be that display use MOSI line to send data. Indeed MISO is not connected if I correctly read n18display schematic.
So I suspect it’s not a real spi communication (or just to send command from mainboard to display).

@ Bauland - great :clap: :clap: I would now doublecheck with the oscilloscope that RS and CS have the right polarity. And doublecheck that the correct commands are sent in the configureDisplay() method.
Yes, it seems that only the spi write function is implemented.

Edit: Perhaps it can help to Debug.Print the sent spi commands and data to compare wheter they are the same on the NETMF and the Raspberry side.

What build are you running of Win10 IoT? I don’t know anything but was interested - and like I needed something else to distract me (oooh, shiny!) I might be able to squeeze in some time to run up a check if you needed more eyes looking.

Looking at the scope it shows that the data is being set on the rising edge of the clock. Is this the correct mode for the display?

If you look at the reply, it appears that the display is clocking out on the falling edge. It’s not 100% clear so maybe you can check this? This would be correct if the polarity is right as one of the modes is to clock in on rising and out on falling.

SPI has 2 modes for the clock. Try changing to the other one and see if the device responds correctly.

1 Like

Tests have been made with the lastest official version.
I’m trying now 14376 version from insider and try to enable Lightning driver (Perhaps it could increase speed).
Monday I should receive an analyzer (it would be more easier to read all 5 signal (clk, mosi, miso, cd, cs).

I’ve test all four modes and indeed, 2 of them seems close. From datasheet if I read correctly, it corresponds to mode 0. I will more test with analyzer it could be more accurate.

It’s indeed easier with analyzer.
I’ve take a spider motherboard, connect the N18Display module and see what happened (I have just modifier spi frequency to see more accuratly what happened).

Picture seems confirm that spi mode is mode0.

Now I must try to create same data on spi with Raspberry pi. I think I would begin without FEZ Cream.

1 Like