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
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
Also, you can shorten your bit-bang code to something like this. I learned that keeping the code clean helps in problem solving
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?
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
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!