Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32-WROVER ILI9341: LCD suddenly inverts colors #27

Closed
mtojek opened this issue Aug 31, 2022 · 13 comments
Closed

ESP32-WROVER ILI9341: LCD suddenly inverts colors #27

mtojek opened this issue Aug 31, 2022 · 13 comments

Comments

@mtojek
Copy link
Contributor

mtojek commented Aug 31, 2022

Follow-up on #25

Hi,

I'm trying to find the root cause of the color inversion that happens at random times while playing. It happens only once, it doesn't come back to the proper color palette.

More information:

  1. Current pinout. LCD MISO pin is connected to GND.
  2. I had to invert colors on startup.
  3. I tried to use the power from the USB charger, batteries, and laptop. Always the same results.
  4. It's only a gut feeling, but sometimes it looks like the problem happens when the in-game screen starts scrolling.
  5. I don't see any other glitches, or corrupted graphics. I assume that the breadboard and wires are fine.
  6. Once the color bug happens, we can only wait until the screen goes white (random moment). In this case, we have to reset the ESP32.
  7. Now, I'm thinking that it isn't really inverted, but rather only B (blue) part is rendered?
See photos

301732635_751017679341512_808025239104929634_n
301456839_376194494537573_6161497735981213556_n
300330443_500205648609245_1141412462760150898_n

Thank you for any help and guidance!

@ducalex
Copy link
Owner

ducalex commented Sep 1, 2022

It's only a gut feeling, but sometimes it looks like the problem happens when the in-game screen starts scrolling.

I have two ideas:

  • Something is interfering with RG_GPIO_LCD_DC or switching doesn't occur fast enough (causing it to process data as commands such as RGB/BGR/on/off/reset). Check that nothing else in your circuit is touching it, also check if the GPIO you picked isn't special or if it needs to have its pullup/pulldown modified. You can try adding small delays in spi_pre_transfer_cb as well.
  • SPI is too fast for your display or wiring, try changing SPI_MASTER_FREQ_40M in rg_display to SPI_MASTER_FREQ_20M or even SPI_MASTER_FREQ_8M. This won't be very playable but it would help narrow down the issue.

@mtojek
Copy link
Contributor Author

mtojek commented Sep 1, 2022

SPI is too fast for your display or wiring, try changing SPI_MASTER_FREQ_40M in rg_display to SPI_MASTER_FREQ_20M or even SPI_MASTER_FREQ_8M. This won't be very playable but it would help narrow down the issue.

Switching to 8M caused a funny effect. Colors got inverted 1 sec after Bill and Lance landed on the ground (Contra, lvl 1), after the next 2 seconds the screen went white. It's reproducible. The gameplay was lagging while scrolling the stage. It looks like it works better with higher frequency.

@ducalex
Copy link
Owner

ducalex commented Sep 2, 2022

Then it must be the data/command line. I see in your config that it conflicts with the LED. You should either comment the RG_GPIO_LED line or use another gpio.

@mtojek
Copy link
Contributor Author

mtojek commented Sep 2, 2022

Thanks, @ducalex. Good catch.

I spotted also another gpio conflict with audio, so I adjusted it too (new pinout git-pushed). Unfortunately, it didn't solve the problem. Maybe it is a hardware issue indeed. Whenever there are too many changes on the screen or there is a need to redraw the full screen, the LCD struggles.

EDIT:

I was thinking about writing a ILI9341 command interpreter to find out which data is interpreted as instructions.

@ducalex
Copy link
Owner

ducalex commented Sep 2, 2022

You can always try disabling partial updates, it will result in a lot less command/data context switching.

It's in the options menu but you can also hardcode it, look for config.update in rg_display.c.

@mtojek
Copy link
Contributor Author

mtojek commented Sep 4, 2022

Status update: I'm still battling this issue, and haven't surrendered yet.

I tried to run a small benchmark to see how my LCD behaves while I'm constantly redrawing the whole screen (two colors interchangeably). I noticed the best results and no issues for SPI configured to operate on 80Mhz and usleep 10ms. At 40 Mhz, I could reproduce the behavior by switching colors 0x2021 and 0x2120. Bytes 0x21 and 0x20 correspond to "Invert colors" commands. I confirm that it works well with 80Mhz. It just needs some slag time after an operation :)

Once I figured out the required "sleep" value, I tried to set it in the write_rect. Unfortunately, the emulator failed with a white screen (possibly a pixel is interpreted as a 0x28 command?). I also discovered that if you place a "usleep 100ms" operation at lcd_set_window before sending commands, the screen won't glitch (at least for a few minutes running). Of course, this is unplayable.

I'm thinking now if there isn't an issue in the rg_display. Is there a chance that SPI buffer is being acquired by multiple tasks and gets altered accidentally? My benchmark uses rg_display_write directly and runs without any issues.

@ducalex
Copy link
Owner

ducalex commented Sep 5, 2022

From your benchmark code I see you've got rid of the data/command line entirely. I doubt that your display is a 3-line model because I can't imagine you'd get an image at all in that case, but if that is correct then I'm afraid retro-go doesn't support that.

You'll have to do more extensive changes to get it working because, in this mode, the d/c signal is sent as an extra bit before every byte instead (section 7.1.8 in the datasheet). Esp-idf might have functionality built-in to help you with that, though.

@ducalex
Copy link
Owner

ducalex commented Sep 5, 2022

Wow nevermind I'm dumb, it was a post_cb that you added and removed. Sorry!

So my guess at this point, because you suspect pixel data 0x2021/0x2120 is interpreted as commands, is still a gpio conflict in your design.

Since the pre_cb is called from ISR you can't do classic delays in it (I think), but you could try adding busy loops before and after the set_level, like:

unsigned sleep_until = xthal_get_ccount() + 240000; // 1ms
while (xthal_get_ccount()  < sleep_until());

Is there a chance that SPI buffer is being acquired by multiple tasks and gets altered accidentally?

SPI transactions are sequentially handled so the possibility of a race is fairly small. It's also the same queue taking care of rg_display_write() and write_rect(), everything goes through spi_queue_transaction() in the end.

But it's possible for transactions to be sent in the wrong order and it happened a few times in the past. For example if the display task is still busy and you invoke the menu (that's why we now have rg_display_sync()).

But it will result in garbage, not data interpreted as commands (because individual transactions are still intact).

@ducalex
Copy link
Owner

ducalex commented Sep 5, 2022

You might have tried already, but if you're still suspicious of the multi-tasking sanity here's an example to remove the display task entirely: 5b01f2f?diff=split

@mtojek
Copy link
Contributor Author

mtojek commented Sep 9, 2022

Hey @ducalex,

sorry for the delay in responding, work duties ;)

You might have tried already, but if you're still suspicious of the multi-tasking sanity here's an example to remove the display task entirely: 5b01f2f?diff=split

Guess what?! It works! The number of glitches dropped by 99%. Of course, the rendering is much slower as it's full render now, but the screen behaves correctly. Do you have an idea what might be wrong with multi-tasked code? The SPI must run at 80Mhz, otherwise glitches again (<= 40MHz).

EDIT:

If I use this snippet, it makes the problem much worse. The nearly immediate color invention, and white screen a few seconds later:

IRAM_ATTR
static void spi_pre_transfer_cb(spi_transaction_t *t)
{
    unsigned sleep_until = xthal_get_ccount() + 240000; // 1ms
    while (xthal_get_ccount()  < sleep_until);

    // Set the data/command line accordingly
    gpio_set_level(RG_GPIO_LCD_DC, (int)t->user & 1);

    sleep_until = xthal_get_ccount() + 240000; // 1ms
    while (xthal_get_ccount()  < sleep_until);
}

@ducalex
Copy link
Owner

ducalex commented Sep 10, 2022

Do you have an idea what might be wrong with multi-tasked code?

I'm not really sure. The branch I shared removed two things: the partial updating and the display task, so it could be either one (unless you tried disabling partial updating before and saw no improvements). But the fact that it still glitches 1% indicates they're not the root cause.

Just to be 100% sure the issue is in code and not hardware, I would suggest trying:

  • Use another GPIO for DC
  • Swap the SD Card and the LCD GPIOs in config and on your breadboard, see if SD then fails instead of LCD
  • Run SPIRAM at 40Mhz, change base.sdkconfig and make sure to delete */sdkconfig after:
    CONFIG_SPIRAM_SPEED_40M=y
    CONFIG_SPIRAM_SPEED_80M=n
    

If all that fails then I will order the exact same LCD and module and try to replicate on my side but they will take a while to arrive :).

@mtojek
Copy link
Contributor Author

mtojek commented Sep 19, 2022

It looks like the problem is gone with replacing a few wires. LCD works great at 80Mhz. Lessons learned: read the characteristics of the devkit. For instance, I could notice the conflict with the LED pin much earlier.

I'm moving forward with plugging in the next components like the gamepad and audio. Audio worked out of the box (external DAC - max9357a). Regarding the gamepad, there is a problem with the limited number of pins of my ESP32 DevkitC v4. I decided to use SN74HC165N to build a simple controller. Actually, the implementation is missing in the original source, so here is what I used.

EDIT:

Thank you for your help, @ducalex! I guess that this issue can be resolved now.

@ducalex
Copy link
Owner

ducalex commented Sep 20, 2022

Happy that it works now!

Thanks for the shift register code, it looks good to me :) . Do you want to submit a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants