ST7796 SPI display: correct RGB565 data on MCU side, but color channel mis-mapping and smearing with esp_lcd
Posted: Mon Jan 19, 2026 7:54 pm
Hi all,
I am currently debugging a very specific ST7796 display behavior and would like to get some feedback from people who have experience with esp_lcd and ST77xx panel variants.
Hardware / Software setup:
- ST7796-based 320x480 SPI display (common China modules, e.g. from vendors like QDtech, etc.)
- Interface: 4-wire SPI
- MCU: ESP32-S3
- ESP-IDF: 5.5.x
- Stack: esp_lcd + esp_lvgl_port + LVGL v8
Important reference:
- The SAME display works perfectly with TFT_eSPI (Arduino) using the same hardware.
- I extracted and integrated the TFT_eSPI ST7796 init sequence into our esp_lcd setup.
- On the MCU side, color values are verified to be correct.
Verification on MCU side:
- LVGL color generation is correct:
- lv_color_make(255,0,0) logs as 0xF800
- lv_color_make(0,255,0) logs as 0x07E0
- lv_color_make(0,0,255) logs as 0x001F
- First by before MCU write operation ist correct
- Flush callback is correct (area handling with +1, correct buffer type, no repacking).
- SPI mode (0–3), SPI frequency, and endianness changes do NOT resolve the issue.
Observed problem (key point):
1) There is a clear COLOR CHANNEL MIS-MAPPING at full color values:
- Full GREEN and full BLUE are swapped or mixed.
- Full RED is not isolated cleanly either.
- This is NOT a simple RGB/BGR or a byte swap.
- The mapping error is reproducible and systematic.
2) In addition to the channel swap, colors are NOT mapped cleanly:
- Pure colors are “smeared” into other channels.
- Example: green appears yellowish, blue appears washed out or cyan-like.
- This happens even with full-scale RGB565 values.
This strongly suggests:
- The panel internally interprets color data differently than expected.
- Possibly an internal RGB565 → RGB666 / RGB888 mapping issue.
- Or undocumented ST7796 register bits required for certain panel variants.
- Or a column/row or internal color pipeline difference not covered by standard COLMOD/MADCTL settings.
What I already tried:
- Using the TFT_eSPI init sequence in esp_lcd (no improvement)
- MADCTL RGB/BGR toggling (changes colors but never results in correct mapping)
- COLMOD = 0x55 (RGB565)
- SPI mode and clock changes
- DC polarity experiments (affects colors, but unstable and never correct)
Key question:
- Are there known ST7796 panel variants that internally expect 18-bit color or use a non-standard RGB565 mapping, even when COLMOD=0x55?
- Is anyone aware of undocumented ST7796 register settings needed for such panels?
- Has anyone successfully driven similar ST7796 SPI panels with esp_lcd and can share init details?
Any hints, documentation gaps, or real-world experience would be highly appreciated.
We can provide init sequences, photos of test patterns, and full esp_lcd configuration if needed.
Thanks in advance!
I am currently debugging a very specific ST7796 display behavior and would like to get some feedback from people who have experience with esp_lcd and ST77xx panel variants.
Hardware / Software setup:
- ST7796-based 320x480 SPI display (common China modules, e.g. from vendors like QDtech, etc.)
- Interface: 4-wire SPI
- MCU: ESP32-S3
- ESP-IDF: 5.5.x
- Stack: esp_lcd + esp_lvgl_port + LVGL v8
Important reference:
- The SAME display works perfectly with TFT_eSPI (Arduino) using the same hardware.
- I extracted and integrated the TFT_eSPI ST7796 init sequence into our esp_lcd setup.
- On the MCU side, color values are verified to be correct.
Verification on MCU side:
- LVGL color generation is correct:
- lv_color_make(255,0,0) logs as 0xF800
- lv_color_make(0,255,0) logs as 0x07E0
- lv_color_make(0,0,255) logs as 0x001F
- First by before MCU write operation ist correct
- Flush callback is correct (area handling with +1, correct buffer type, no repacking).
- SPI mode (0–3), SPI frequency, and endianness changes do NOT resolve the issue.
Observed problem (key point):
1) There is a clear COLOR CHANNEL MIS-MAPPING at full color values:
- Full GREEN and full BLUE are swapped or mixed.
- Full RED is not isolated cleanly either.
- This is NOT a simple RGB/BGR or a byte swap.
- The mapping error is reproducible and systematic.
2) In addition to the channel swap, colors are NOT mapped cleanly:
- Pure colors are “smeared” into other channels.
- Example: green appears yellowish, blue appears washed out or cyan-like.
- This happens even with full-scale RGB565 values.
This strongly suggests:
- The panel internally interprets color data differently than expected.
- Possibly an internal RGB565 → RGB666 / RGB888 mapping issue.
- Or undocumented ST7796 register bits required for certain panel variants.
- Or a column/row or internal color pipeline difference not covered by standard COLMOD/MADCTL settings.
What I already tried:
- Using the TFT_eSPI init sequence in esp_lcd (no improvement)
- MADCTL RGB/BGR toggling (changes colors but never results in correct mapping)
- COLMOD = 0x55 (RGB565)
- SPI mode and clock changes
- DC polarity experiments (affects colors, but unstable and never correct)
Key question:
- Are there known ST7796 panel variants that internally expect 18-bit color or use a non-standard RGB565 mapping, even when COLMOD=0x55?
- Is anyone aware of undocumented ST7796 register settings needed for such panels?
- Has anyone successfully driven similar ST7796 SPI panels with esp_lcd and can share init details?
Any hints, documentation gaps, or real-world experience would be highly appreciated.
We can provide init sequences, photos of test patterns, and full esp_lcd configuration if needed.
Thanks in advance!