Cobra : how to use fez touch-like 8bits or 16 bits LCD?

Hi Wouter.
I will finally try to use a display “umsh 8252md-t” (datasheet here http://www.avnet-embedded.eu/fileadmin/user_upload/Files/Displays/Colour_TFT/UMSH-8252MD-T.pdf)
Unfortunately, it seems that I need to use spi commands before using rgb parallel bus. I have just white screen for now, wich means backlight is ok but I am on the same step than you. Lets code some SPI…

Well as you can see here: http://www.tinyclr.com/forum/topic?id=8450
I’ve managed to get the correct SPI command sequence I had to send to the display, I contacted a local sales rep for Kyocera (manufacturer of the display I was using) and after few mails I received a nice document with complete initialization sequence for that particular LCD.

The datasheet you’re referring to doesn’t contain the used controller IC nor a command set. So you’ll have to figure that out first, try to contact a sales rep at Avnet and request complete documentation. Believe me, you’ll not be able to figure out the correct settings by brute forcing them. At a certain point you need to set different LCD glass voltages, which are only known by the manufacturer.

Cool hardware and software job! I see that you had hard work during this time! For my part, I just come back today on this project.
I was originally trying to find a low-cost lcd with parallel RGB bus.
A local vendor advices me the “umsh 8252md-t” but we realized after that it needs some SPI commands to work properly.
I am hoping that the issue was “just” to connect RGB + spi properly and code SPI init sequence (for me, the command set is described in the datasheet p14, do you think I will need more?)
Did you encounter a lot of difficulties beetween the briliant blank screen step and the time-to-display-first-picture? I think that the voltage management is easiest on my screen…

My backup solution is the “NHD-3.5-320240MF-ATXL#-1-ND” (datasheet here http://www.newhavendisplay.com/specs/NHD-3.5-320240MF-ATXL-1.pdf), wich seems to be more “plug&play” because purely parallel RGB, but should arrive in 4 weeks now…

I finally had some sucess with my screen.
After coding the proper initialisation sequence through 3-wires SPI, picture has shown :
-For now I have tuned the parameters of the tft through SPI to make it less ugly (set orientation, correct horizontal and vertical porch to make it compatible with existing GHI LCD driver)
-But I have some extra tuning to do, because colors are quite bad (gamma correction and analog settings have to be changed I guess…) and the 30 last lines just don’t show! (still blank, probably some timing issue, I will investigate but have no precise idea for now…)
If people are interested here is the code : I will update it if I kill the “30last lines not showing” issue:

          



  // -----------------Adjust the Gamma Curve----//
            WriteRegisterData(0x30, 0x00, 0x00);    // Gamma B control1
            WriteRegisterData(0x31, 0x01, 0x01);    // Gamma B control2//
            WriteRegisterData(0x32, 0x01, 0x00);    // Gamma B control3
            WriteRegisterData(0x33, 0x03, 0x05);    // Gamma B control4
            WriteRegisterData(0x34, 0x07, 0x07);    // Gamma B control5 //
            WriteRegisterData(0x35, 0x03, 0x05);    // Gamma B control6
            WriteRegisterData(0x36, 0x07, 0x07);    // Gamma B control7
            WriteRegisterData(0x37, 0x02, 0x01);    // Gamma B control8 //
            WriteRegisterData(0x3A, 0x12, 0x00);    // Gamma B control9 
            WriteRegisterData(0x3B, 0x09, 0x00);    // Gamma B control10 //

            
            Debug.Print("SPI startup seq started");
            WriteRegisterData(0x03, 0x6A, 0x38);    // VGL/VGH = 5/-3
            WriteRegisterData(0x01, 0x72, 0xEF);    // Gate lines=240
            WriteRegisterData(0x28, 0x00, 0x06);    // Enable R25 R29 Regs
            WriteRegisterData(0x12, 0x09, 0x99);    // Sleep mode
            WriteRegisterData(0x26, 0x38, 0x00);    // Analogue settings
            WriteRegisterData(0x0C, 0x00, 0x04);    // VCIX2
            WriteRegisterData(0x0D, 0x00, 0x0A);    // VLCD63
            WriteRegisterData(0x0E, 0x26, 0x00);    // VCOML
            WriteRegisterData(0x1E, 0x00, 0xAF);    // VCOMH

            WriteRegisterData(0x01, 0x72, 0xEF);    // CCA pour orientation
            WriteRegisterData(0x16, 0x00, 0x43);    // Horizontal Porch 3D
            WriteRegisterData(0x17, 0x00, 0x13);    // Vertical Porch 10

            //Send Display setting sequence (doc urt chapter 2-5-1)
            WriteRegisterData(0x07, 0x00, 0x21);    // DisplayControl
            WriteRegisterData(0x00, 0x00, 0x01);    // OSCEN=1
            WriteRegisterData(0x07, 0x00, 0x23);    // DisplayControl
            WriteRegisterData(0x10, 0x00, 0x00);    // Sleep=0
            Thread.Sleep(30);
            WriteRegisterData(0x07, 0x00, 0x33);    // DisplayControl

            WriteRegisterData(0x11, 0xC6, 0x70);    // 262Kmode RGB inteface 
            WriteRegisterData(0x02, 0x06, 0x00);    // line inversion
            WriteRegisterData(0x22, 0xDC, 0xDC);    // Write to RAM


            Debug.Print("SPI startup seq ended");

 //Initialisation ecran
        static OutputPort ScreenSCS = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO26, true);  // spi 3 wires : chip select
        static OutputPort ScreenSCL = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO27, true);  // spi 3 wires : clock
        static OutputPort ScreenSDI = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO24, false); // spi 3 wires : MOSI /SDI

        
        static void WriteRegisterData(byte bRegAdress, byte bDataHigh , byte bDataLow )
        {
            //Bitbanging du protocole SPI 3x9bits :
            //Cf SSD2119 datasheet p31/95:
            
             bool bTemp = false;
             ScreenSCL.Write(true); 

            //////////////////////////////
            //Frame 1 : Command
            ScreenSCS.Write(false); //Transfert start
            ScreenSDI.Write(false); //first send DC bit = command register
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge

            //Send byte
            bTemp = ((bRegAdress & 0x80) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x40) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x20) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x10) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x08) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x04) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x02) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bRegAdress & 0x01) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge

            ScreenSCS.Write(true); //Transfert ends
      

            //////////////////////////////
            //Frame 2 : Data 1
            ScreenSCS.Write(false); //Transfert start
            ScreenSDI.Write(true); //first send DC bit = data ram
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge

            //Send byte
            bTemp = ((bDataHigh & 0x80) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x40) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x20) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x10) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x08) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x04) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x02) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataHigh & 0x01) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge

            ScreenSCS.Write(true); //Transfert ends
   
            //////////////////////////////
            //Frame 3 : Data 2
            //DC bit : data ram
            ScreenSCS.Write(false); //Transfert start
            ScreenSDI.Write(true); //first send DC bit = data ram
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge

            //Send byte
            bTemp = ((bDataLow & 0x80) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x40) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x20) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x10) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x08) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x04) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x02) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge
            bTemp = ((bDataLow & 0x01) != 0);
            ScreenSDI.Write(bTemp);
            ScreenSCL.Write(false); ScreenSCL.Write(true);//clock rising edge

            ScreenSCS.Write(true); //Transfert ends
        }

Where did you get those voltage and gamma values for your display? If you didn’t get them from the manufacturer, it will explain why picture is looking bad :slight_smile:

Guessing these voltages is impossible and can result in a dead display.

Hi Wouter,

For voltage and gamma values,they are set by register through the 9bits/3wires spi interface coded below: I have blindly applied the values given on p13 of : http://www.avnet-embedded.eu/fileadmin/user_upload/Files/Displays/Colour_TFT/UMSH-8252MD-T.pdf
Indeed, some settings have been changed according to the SSD2119 driver IC (the one used in my screen) datasheet.

I have now a “working” screen, but colors are not really beautifull, so I am currently looking on SSD2119 documentation to understand if I can do the things look better!
(I guess with the registers for gamma settings and analog settings…)
Regards,
CCa

What is the reason why you are using these values:


            WriteRegisterData(0x0C, 0x00, 0x04);    // VCIX2
            WriteRegisterData(0x0D, 0x00, 0x0A);    // VLCD63
            WriteRegisterData(0x0E, 0x26, 0x00);    // VCOML
            WriteRegisterData(0x1E, 0x00, 0xAF);    // VCOMH

while the datasheets tells you these:


            WriteRegisterData(0x0C, 0x00, 0x05);    // VCIX2
            WriteRegisterData(0x0D, 0x00, 0x0D);    // VLCD63
            WriteRegisterData(0x0E, 0x23, 0x00);    // VCOML
            WriteRegisterData(0x1E, 0x00, 0x10);    // VCOMH

Also, are you sure your SPI configuration is correct? I suppose yes, otherwise you would have no visual at all :slight_smile:

Also, you can shorten your bit-bang code to something like this. I learned that keeping the code clean helps in problem solving :wink:


static void Write9bit(byte data, bool command)
{
   bool bit = !command;
   ScreenSCS.Write(false);
   for (int i = 0; i < 9; i++)
   {
      ScreenSDI.Write(bit);
      ScreenSCL.Write(false);
      ScreenSCL.Write(true);
      bit = (data & 0x80) != 0;
      data <<= 1;
   }
   ScreenSCS.Write(true);
}

static void WriteRegisterData(byte bRegAdress, byte bDataHigh , byte bDataLow )
{
   Write9bit(bRegAddress, true);
   Write9bit(bDataHigh, false);
   Write9bit(bDataLow, false);
}

static void WriteRegisterData(byte bRegAdress, ushort usData)
{
   Write9bit(bRegAddress, true);
   Write9bit((byte)(usData >> 8), false);
   Write9bit((byte)usData, false);
}

An other funny fact is that the VGH/VGL, VCIX2 and VLCD63 values differ in the datasheet for 16bit 8080 interface or 18bit interface. In my opinion, these have nothing to do with the interface (they can depend on the pixelclock though). So I would try the voltage values listed under the 16bit 8080 interface example on page 12

Thank you for your feedback, WouterH.

->Sorry, the link that I provide is an old datasheet version. its rev3(2010) and I use rev4(2012).In my code the values are up to date.

->Yes I guess my SPI config is correct! (at least registers values apply correctly)

->Thanks for the submission, but I deliberately expanded the code because I see that the compact and elegant way (with for loop) is slower (the magic of .NETMF I guess??) . and I want to boot as fast as possible.

->Yes I agree it is not normal. That’s why I will check by myself the best settings for image quality with the help of SSD2119 documentation… Except r30h to r3bh gamma registers and VGH/VGL, VCIX2 and VLCD63 settings, do you know if other registers can impact the quality of color?

Then why bit-banging instead of using a hardware SPI port? :slight_smile:

The image on my display was bad to in the beginning, until I’ve set the correct gamma + voltage levels, so I guess it’s all about those settings. The voltage values depend on the pixelclock (at least in my case). I had to adjust the pixelclock and set a prescaler register in the LCD to ensure that the LCD internal clock was close to 1MHz. The LCD uses this reference clock for voltage regulation and other timings.

In the datasheet of your display, I see they refer to a ‘typical’ dotclock of 5.5MHz, what rate are you using?

I have a bit played with gamma registers, but I think that my current settings are finally not so bad and that I was abused by optical capabilities. Indeed, the viewing angles of that LCD are restricted and if you look it with the bad angle (as I was doing) a sad green taint appears.
If you are looking on the screen from front or from the top it is okay, but from below its not really good.

Indeed, I will double check dotclock settings, and maybe make some functions to tune gamma values more easily from buttons …

Because I don’t think from NETMF we can use SPI class to send 3*9bits (only Nx8bits is possible I guess).
And I think that mixing IO and SPI on the same pins in the same sequence is not elegant and not efficient…

I think I will consider me happy with that screen, as my application is not purely oriented for media (video, pictures) purpose .

Ah, you’re right, I though you would be able to change the # of bits through the Register class, but the SPI.Write() overloads will configure the # of bits each time you call it. No luck here :frowning:

And for the clock prescaler I have tried 72 / 13 = 5.53Mhz to 72 / 10 = 7.2Mhz and it seems to me that 7.2Mhz gives better results than 5.5 (I can detect some glittering at 5.5Mhz…) So i will stick to 7.2Mhz!