ILI9341 grey screen problem. - Page 1
Forum section: electronics / general

author: phil from seattle
author_rank: Super Contributor
timestamp: January 15, 2018, 08:49:41 pm
content: I've been using these little 2.2" TFT QVGA (320x240) ILI9341 based displays with several projects. They are cheap ($6-ish from china), easy to interface to (SPI) and for the most part work pretty well. There are several very good drivers out there and font support to allow me to make some nice looking interfaces.The "for the most part" comment stems from an occasional "grey screen" at start up. Once in a while upon power up, the screen will turn a light shade of grey and stay that way. The system is otherwise working and I can see flashes through the grey screen when display updates happen so I'm pretty sure the ILI9341 is mostly working. I've tried a number of things but the only thing that seems to work is to power cycle it. And that only works about 20% of the time. Sometimes it persists and I have to stop working on it. It always reverts to correct operation inevitably. Initially I suspected something was overheating but could not find a hot spot and I usually can run the display for hours without problem.Anyone know about this issue and/or fix(es)? It would be a shame to not use these displays as they are a perfect fit for a number of my projects.I recently read that during power-on the device is susceptible to noisy power and to add a cap across power and gnd. I'm a little skeptical of that advice because it was for a different board with the ILI9341 and, frankly, seemed seemed to be speculation. A look at the datasheet didn't show any power up procedures that I could do.https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwiiss7f6NrYAhVC1WMKHU6rAHUQFggpMAA&url=https%3A%2F%2Fcdn-shop.adafruit.com%2Fdatasheets%2FILI9341.pdf&usg=AOvVaw1c2_IoNnlHoQnTC7qN9yABBut given the possibility, I've put a 100nF cap across +5V and gnd. We'll see. I might try something bigger. The gpu itself is a 3.3V device and there is a cap across +3V3 and Gnd at on-board regulator. We shall see if the 100nF cap helps. I'm wondering if I should delay powering the display for some period of time after board power up.

author: mbless
author_rank: Regular Contributor
timestamp: January 15, 2018, 09:47:03 pm
content: Quote from: phil from seattle on January 15, 2018, 08:49:41 pmList what you've tried, don't leave us guessing.Have you tried working and non-working displays on the same system (mcu, etc.)?

author: phil from seattle
author_rank: Super Contributor
timestamp: January 16, 2018, 03:15:43 am
content: There's really not that much to try. I've swapped displays and the new one usually works. However, it will eventually have the problem and when I swap the other one back, it works, for a while. That's why I thought overheating but couldn't find a hot spot anywhere. and, like I said, the display can be run for hours with no problems. Unfortunately, the one on the system I'm currently debugging is soldered in place. I've tried SW resetting the ILI9341 while still powered and it doesn't help.If I do a revision of the PCB I'm working on I will add the ability to control power to the display board. There is no way to control the reset line of the ILI9341.

author: Bud
author_rank: Super Contributor
timestamp: January 16, 2018, 03:41:27 am
content: Maybe there is a reason they cost only $6

author: ajb
author_rank: Super Contributor
timestamp: January 16, 2018, 04:01:32 am
content: Quote from: phil from seattle on January 16, 2018, 03:15:43 amNo? The reset line is usually brought out on those PCBs. Note section 12 of the datasheet, it specifies the handling of the reset line, in particular:QuoteSo a pullup from RESX to VDD, as I suspect those cheap boards have, is not guaranteed to work! You might be able to get away with a pullup resistor and a capacitor on RESX, but this is still not guaranteed to work in all situations. The best bet is to drive RESX from your MCU and supply an appropriate reset signal as part of your initialization process. Note that you will want to hold RESX low for the correct length of time as specified by the datasheet, and then wait an appropriate length of time before sending the ILI9341 any commands so that it has time to complete its reset sequence.

author: phil from seattle
author_rank: Super Contributor
timestamp: January 16, 2018, 07:58:00 pm
content: Yeah, my bad, the reset line does come out and the driver code does drive it. The driver toggles it and it occurs well after power-on in my code (at least several hundred mS). What's not clear is whether the external reset pin on the display pcb directly drives RESX as I have no easy access to the ILI9341 chip - the LCD panel is glued to the PCB.Here is the arduino driver code that is executed during initialization. I believe it presumes this from the data sheet section 12.1 Case 1 – RESX line is held High or Unstable by Host at Power ONCode:// toggle RST low to resetif (_rst < 255) {pinMode(_rst, OUTPUT);digitalWrite(_rst, HIGH);delay(5);digitalWrite(_rst, LOW);delay(20);digitalWrite(_rst, HIGH);delay(150);}Delay is in mS and _rst was set to the actual pin number. I've verified with an LA that the display's reset line is pulled high for 5 mS, low for 20 and then high again. The data sheet doesn't show a minimum time that RESX needs to be high or low during this. I presume the 5 mS high and 20 mS low from the driver code is vastly overkill. I've also issued this reset from my code when the problem shows and it doesn't resolve it.

author: ajb
author_rank: Super Contributor
timestamp: January 16, 2018, 08:38:37 pm
content: In that case, I would guess that your SPI timings are marginal. Have you verified them with a logic analyzer or scope? The ILI9341 supports several different serial formats, so it's important to ensure that your MCU is configured for the right one. And IIRC the SPI is only like 10MHz or something, so double check your clock rate as well. This is a downside of those cheap breakout PCBs--if you had access to the parallel interface that runs at ~15MHz, so it's ~12x faster at 8 bits wide.It wouldn't hurt to post the full initialization sequence you're using as well.

author: phil from seattle
author_rank: Super Contributor
timestamp: January 16, 2018, 09:57:47 pm
content: Yeah, I'll check out the SPI timings. Might take a few days. I kind of think it's a wild goose chase because it only happens infrequently at startup. But, I'll try anything to be able to reliably use these inexpensive displays. Wish I could cause the problem to happen at will.I'm also going to try and hack up a way to cleanly power cycle the display. I have a spare couple of pins that my PCB brings out.Here's the driver's begin code, not sure it's that useful without the entire driver. I didn't write it. It's derivative of the Paul Stoffregen derivative of Limor Fried's (Lady Ada) original driver and uses a modification of the SPI driver (to run on the cortex M0+). I don't feel comfortable posting the entire driver. It can be obtained here:https://github.com/KurtE/ILI9341_t3nProbably tl:dr-ish. Note that the use of 255 as a pin number means use a default pin. Yeah, I know the driver seems like a bit of a house of cards but it's otherwise quite solid.I have it running on both a Teensy 3.2 (Freescale K20) and a Teensy LC (48 MHz Cortex-M0+). Exact same problem on both. The problem also showed with the Paul Stoffregen version (which only runs on the Teensy 3.2. KurtE's version makes it also run on the Cortex-M0+ processor.Here's my declaration of the ILI9341 objectCode://// pin assignments for focus rail board V2.07//#define TFT_DC 20#define TFT_CS 15#define TFT_RST 21#define TFT_MOSI 7#define TFT_SCLK 13#define TFT_MISO 8#define TFT_BKL 9uint8_t tftBacklight = 64;ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC,TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);And then I just call tft.begin(); in the setup code.Code:void ILI9341_t3n::begin(void){// verify SPI pins are valid;// allow user to say use current ones...if ((_mosi != 255) || (_miso != 255) || (_sclk != 255)) {if (!(_pspin->pinIsMOSI(_mosi)) || !(_pspin->pinIsMISO(_miso)) || !(_pspin->pinIsSCK(_sclk))) {#ifdef SPIN1_OBJECT_CREATEDif (SPIN1.pinIsMOSI(_mosi) && SPIN1.pinIsMISO(_miso) && SPIN1.pinIsSCK(_sclk)) {_pspin = &SPIN1;#ifdef KINETISK_pkinetisk_spi = _pspin->kinetisk_spi();#else_pkinetisl_spi = _pspin->kinetisl_spi();#endifSerial.println("ILI9341_t3n: SPIN1 automatically selected");} else {#ifdef SPIN2_OBJECT_CREATEDif (SPIN2.pinIsMOSI(_mosi) && SPIN2.pinIsMISO(_miso) && SPIN2.pinIsSCK(_sclk)) {_pspin = &SPIN2;_pkinetisk_spi = _pspin->kinetisk_spi();Serial.println("ILI9341_t3n: SPIN2 automatically selected");} else {#endif#endifuint8_t mosi_sck_bad = false;Serial.print("ILI9341_t3n: Error not valid SPI pins:");if(!(_pspin->pinIsMOSI(_mosi))) {Serial.print(" MOSI");mosi_sck_bad = true;}if (!_pspin->pinIsSCK(_sclk)) {Serial.print(" SCLK");mosi_sck_bad = true;}// Maybe allow us to limp with only MISO badif(!(_pspin->pinIsMISO(_miso))) {Serial.print(" MISO");_miso = 0xff;// set miso to 255 as flag it is bad}Serial.println();if (mosi_sck_bad) {return; // not valid pins...}#ifdef SPIN2_OBJECT_CREATED}#endif#ifdef SPIN1_OBJECT_CREATED}#endif}//Serial.printf("MOSI:%d MISO:%d SCK:%d\n\r", _mosi, _miso, _sclk);_pspin->setMOSI(_mosi);if (_miso != 0xff) _pspin->setMISO(_miso);_pspin->setSCK(_sclk);}_pspin->begin();#ifdef KINETISKif (_pspin->pinIsChipSelect(_cs, _dc)) {pcs_data = _pspin->setCS(_cs);pcs_command = pcs_data | _pspin->setCS(_dc);} else {// See if at least DC is on chipselect pin, if so try to limp along...if (_pspin->pinIsChipSelect(_dc)) {pcs_data = 0;pcs_command = pcs_data | _pspin->setCS(_dc);pinMode(_cs, OUTPUT);_csport = portOutputRegister(digitalPinToPort(_cs));_cspinmask = digitalPinToBitMask(_cs);*_csport |= _cspinmask;} else {pcs_data = 0;pcs_command = 0;Serial.println("ILI9341_t3n: Error not DC is not valid hardware CS pin");return;}}#else// TLCpcs_data = 0;pcs_command = 0;pinMode(_cs, OUTPUT);_csport = portOutputRegister(digitalPinToPort(_cs));_cspinmask = digitalPinToBitMask(_cs);*_csport |= _cspinmask;pinMode(_dc, OUTPUT);_dcport = portOutputRegister(digitalPinToPort(_dc));_dcpinmask = digitalPinToBitMask(_dc);*_dcport |= _dcpinmask;_dcpinAsserted = 0;#endif// toggle RST low to resetif (_rst < 255) {Serial.println("reset ILI9341");pinMode(_rst, OUTPUT);digitalWrite(_rst, HIGH);delay(5);digitalWrite(_rst, LOW);delay(20);digitalWrite(_rst, HIGH);delay(150);}/*uint8_t x = readcommand8(ILI9341_RDMODE);Serial.print("\nDisplay Power Mode: 0x"); Serial.println(x, HEX);x = readcommand8(ILI9341_RDMADCTL);Serial.print("\nMADCTL Mode: 0x"); Serial.println(x, HEX);x = readcommand8(ILI9341_RDPIXFMT);Serial.print("\nPixel Format: 0x"); Serial.println(x, HEX);x = readcommand8(ILI9341_RDIMGFMT);Serial.print("\nImage Format: 0x"); Serial.println(x, HEX);x = readcommand8(ILI9341_RDSELFDIAG);Serial.print("\nSelf Diagnostic: 0x"); Serial.println(x, HEX);*/beginSPITransaction();const uint8_t *addr = init_commands;while (1) {uint8_t count = *addr++;if (count-- == 0) break;writecommand_cont(*addr++);while (count-- > 0) {writedata8_cont(*addr++);}}writecommand_last(ILI9341_SLPOUT); // Exit SleependSPITransaction();delay(120);beginSPITransaction();writecommand_last(ILI9341_DISPON); // Display onendSPITransaction();}

author: phil from seattle
author_rank: Super Contributor
timestamp: January 17, 2018, 12:34:28 am
content: Hmmm, good call on SPI timings! Based on the min clock periods for write and read in the data sheet, the driver was running the display out of spec - especially for reads. Write min clock period is 100 nS and read is 150 nS. I slowed the SPI clock down to a 12 MHz setting (cause it was easy in the code) but the LA trace shows it just a bit faster than 10 MHz (10.67 MHz) which is probably ok for now. I don't use commands that read the display yet but will need to understand the SPI driver a little better to get both read and write timings within spec.I'm hoping this is the solution. Will certainly run with it for a while.