-
Notifications
You must be signed in to change notification settings - Fork 916
Description
Answers checklist.
- I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
- I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
- I have searched the issue tracker for a similar issue and not found a similar issue.
IDF version.
v5.5.1-1-g129cd0d247
Espressif SoC revision.
ESP32-S3 (QFN56) (revision v0.2)
Operating System used.
Windows
How did you build your project?
VS Code IDE
If you are using Windows, please specify command line type.
PowerShell
Development Kit.
ESP32-S3-Touch-LCD-3.5B (from Waveshare)
Power Supply used.
USB
What is the expected behavior?
When using esp_lcd_panel_swap_xy(panel_handle, true) it's expected to swap the x and y axes of the LCD. And combining this with esp_lcd_panel_mirror I can achieve hardware screen rotation. The following code in this issue, draws a rectangle in the corner of the screen which goes from black to red repeatedly.
What is the actual behavior?
While normally it's fine, there's just a black screen when using the swap function.
Steps to reproduce.
- Wire a AXS15231B drived display to an ESP32 microcontroller (QSPI interface)
- Use the following code
#include <stdio.h>
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_interface.h"
#include "esp_lcd_axs15231b.h"
#define LCD_PIN_CS 12
#define LCD_PIN_SCLK 5
#define LCD_PIN_DATA0 1
#define LCD_PIN_DATA1 2
#define LCD_PIN_DATA2 3
#define LCD_PIN_DATA3 4
#define LCD_PIN_RST -1
#define LCD_PIN_BL 6
#define DISPLAY_HEIGHT 480
#define DISPLAY_WIDTH 320
esp_lcd_panel_io_handle_t lcd_io_handle = NULL;
esp_lcd_panel_handle_t lcd_panel_handle = NULL;
static const axs15231b_lcd_init_cmd_t lcd_init_cmds[] = {
{0xBB, (uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5}, 8, 0},
{0xA0, (uint8_t[]){0xC0, 0x10, 0x00, 0x02, 0x00, 0x00, 0x04, 0x3F, 0x20, 0x05, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00}, 17, 0},
{0xA2, (uint8_t[]){0x30, 0x3C, 0x24, 0x14, 0xD0, 0x20, 0xFF, 0xE0, 0x40, 0x19, 0x80, 0x80, 0x80, 0x20, 0xf9, 0x10, 0x02, 0xff, 0xff, 0xF0, 0x90, 0x01, 0x32, 0xA0, 0x91, 0xE0, 0x20, 0x7F, 0xFF, 0x00, 0x5A}, 31, 0},
{0xD0, (uint8_t[]){0xE0, 0x40, 0x51, 0x24, 0x08, 0x05, 0x10, 0x01, 0x20, 0x15, 0x42, 0xC2, 0x22, 0x22, 0xAA, 0x03, 0x10, 0x12, 0x60, 0x14, 0x1E, 0x51, 0x15, 0x00, 0x8A, 0x20, 0x00, 0x03, 0x3A, 0x12}, 30, 0},
{0xA3, (uint8_t[]){0xA0, 0x06, 0xAa, 0x00, 0x08, 0x02, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x55, 0x55}, 22, 0},
{0xC1, (uint8_t[]){0x31, 0x04, 0x02, 0x02, 0x71, 0x05, 0x24, 0x55, 0x02, 0x00, 0x41, 0x00, 0x53, 0xFF, 0xFF, 0xFF, 0x4F, 0x52, 0x00, 0x4F, 0x52, 0x00, 0x45, 0x3B, 0x0B, 0x02, 0x0d, 0x00, 0xFF, 0x40}, 30, 0},
{0xC3, (uint8_t[]){0x00, 0x00, 0x00, 0x50, 0x03, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01}, 11, 0},
{0xC4, (uint8_t[]){0x00, 0x24, 0x33, 0x80, 0x00, 0xea, 0x64, 0x32, 0xC8, 0x64, 0xC8, 0x32, 0x90, 0x90, 0x11, 0x06, 0xDC, 0xFA, 0x00, 0x00, 0x80, 0xFE, 0x10, 0x10, 0x00, 0x0A, 0x0A, 0x44, 0x50}, 29, 0},
{0xC5, (uint8_t[]){0x18, 0x00, 0x00, 0x03, 0xFE, 0x3A, 0x4A, 0x20, 0x30, 0x10, 0x88, 0xDE, 0x0D, 0x08, 0x0F, 0x0F, 0x01, 0x3A, 0x4A, 0x20, 0x10, 0x10, 0x00}, 23, 0},
{0xC6, (uint8_t[]){0x05, 0x0A, 0x05, 0x0A, 0x00, 0xE0, 0x2E, 0x0B, 0x12, 0x22, 0x12, 0x22, 0x01, 0x03, 0x00, 0x3F, 0x6A, 0x18, 0xC8, 0x22}, 20, 0},
{0xC7, (uint8_t[]){0x50, 0x32, 0x28, 0x00, 0xa2, 0x80, 0x8f, 0x00, 0x80, 0xff, 0x07, 0x11, 0x9c, 0x67, 0xff, 0x24, 0x0c, 0x0d, 0x0e, 0x0f}, 20, 0},
{0xC9, (uint8_t[]){0x33, 0x44, 0x44, 0x01}, 4, 0},
{0xCF, (uint8_t[]){0x2C, 0x1E, 0x88, 0x58, 0x13, 0x18, 0x56, 0x18, 0x1E, 0x68, 0x88, 0x00, 0x65, 0x09, 0x22, 0xC4, 0x0C, 0x77, 0x22, 0x44, 0xAA, 0x55, 0x08, 0x08, 0x12, 0xA0, 0x08}, 27, 0},
{0xD5, (uint8_t[]){0x40, 0x8E, 0x8D, 0x01, 0x35, 0x04, 0x92, 0x74, 0x04, 0x92, 0x74, 0x04, 0x08, 0x6A, 0x04, 0x46, 0x03, 0x03, 0x03, 0x03, 0x82, 0x01, 0x03, 0x00, 0xE0, 0x51, 0xA1, 0x00, 0x00, 0x00}, 30, 0},
{0xD6, (uint8_t[]){0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, 0x93, 0x00, 0x01, 0x83, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x84, 0x00, 0x20, 0x01, 0x00}, 30, 0},
{0xD7, (uint8_t[]){0x03, 0x01, 0x0b, 0x09, 0x0f, 0x0d, 0x1E, 0x1F, 0x18, 0x1d, 0x1f, 0x19, 0x40, 0x8E, 0x04, 0x00, 0x20, 0xA0, 0x1F}, 19, 0},
{0xD8, (uint8_t[]){0x02, 0x00, 0x0a, 0x08, 0x0e, 0x0c, 0x1E, 0x1F, 0x18, 0x1d, 0x1f, 0x19}, 12, 0},
{0xD9, (uint8_t[]){0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}, 12, 0},
{0xDD, (uint8_t[]){0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}, 12, 0},
{0xDF, (uint8_t[]){0x44, 0x73, 0x4B, 0x69, 0x00, 0x0A, 0x02, 0x90}, 8, 0},
{0xE0, (uint8_t[]){0x3B, 0x28, 0x10, 0x16, 0x0c, 0x06, 0x11, 0x28, 0x5c, 0x21, 0x0D, 0x35, 0x13, 0x2C, 0x33, 0x28, 0x0D}, 17, 0},
{0xE1, (uint8_t[]){0x37, 0x28, 0x10, 0x16, 0x0b, 0x06, 0x11, 0x28, 0x5C, 0x21, 0x0D, 0x35, 0x14, 0x2C, 0x33, 0x28, 0x0F}, 17, 0},
{0xE2, (uint8_t[]){0x3B, 0x07, 0x12, 0x18, 0x0E, 0x0D, 0x17, 0x35, 0x44, 0x32, 0x0C, 0x14, 0x14, 0x36, 0x3A, 0x2F, 0x0D}, 17, 0},
{0xE3, (uint8_t[]){0x37, 0x07, 0x12, 0x18, 0x0E, 0x0D, 0x17, 0x35, 0x44, 0x32, 0x0C, 0x14, 0x14, 0x36, 0x32, 0x2F, 0x0F}, 17, 0},
{0xE4, (uint8_t[]){0x3B, 0x07, 0x12, 0x18, 0x0E, 0x0D, 0x17, 0x39, 0x44, 0x2E, 0x0C, 0x14, 0x14, 0x36, 0x3A, 0x2F, 0x0D}, 17, 0},
{0xE5, (uint8_t[]){0x37, 0x07, 0x12, 0x18, 0x0E, 0x0D, 0x17, 0x39, 0x44, 0x2E, 0x0C, 0x14, 0x14, 0x36, 0x3A, 0x2F, 0x0F}, 17, 0},
{0xA4, (uint8_t[]){0x85, 0x85, 0x95, 0x82, 0xAF, 0xAA, 0xAA, 0x80, 0x10, 0x30, 0x40, 0x40, 0x20, 0xFF, 0x60, 0x30}, 16, 0},
{0xA4, (uint8_t[]){0x85, 0x85, 0x95, 0x85}, 4, 0},
{0xBB, (uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, 0},
{0x13, (uint8_t[]){0x00}, 0, 0},
{0x11, (uint8_t[]){0x00}, 0, 120},
{0x2C, (uint8_t[]){0x00, 0x00, 0x00, 0x00}, 4, 0},
};
void lcd_init()
{
spi_bus_config_t bus_config = {
.sclk_io_num = LCD_PIN_SCLK,
.data0_io_num = LCD_PIN_DATA0,
.data1_io_num = LCD_PIN_DATA1,
.data2_io_num = LCD_PIN_DATA2,
.data3_io_num = LCD_PIN_DATA3,
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus_config, SPI_DMA_CH_AUTO));
// esp_lcd_panel_io_spi_config_t io_config = AXS15231B_PANEL_IO_QSPI_CONFIG(LCD_PIN_CS, NULL, NULL);
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = LCD_PIN_CS,
.dc_gpio_num = -1,
.spi_mode = 3,
.pclk_hz = 40 * 1000 * 1000,
.trans_queue_depth = 10,
.on_color_trans_done = NULL,
.user_ctx = NULL,
.lcd_cmd_bits = 32,
.lcd_param_bits = 8,
.flags = {
.quad_mode = true,
},
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &lcd_io_handle));
axs15231b_vendor_config_t vendor_config = {
.init_cmds = lcd_init_cmds,
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.flags = {
.use_qspi_interface = true,
},
};
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = LCD_PIN_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.data_endian = LCD_RGB_DATA_ENDIAN_BIG,
.vendor_config = &vendor_config,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_axs15231b(lcd_io_handle, &panel_config, &lcd_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(lcd_panel_handle, false));
esp_lcd_panel_mirror(lcd_panel_handle, true, false);
esp_lcd_panel_swap_xy(lcd_panel_handle, true); // This line ruins everything
}
void bitmap(color_pixel_rgb565_data_t *color_data, uint16_t color)
{
int w = 100;
int h = 20;
int x = 0;
int y = 0;
for (int i = 0; i < w * h; i++)
{
// color_data[i].r = 0b00000;
// color_data[i].g = 0b111111;
// color_data[i].b = 0b00000;
color_data[i].val = color;
}
esp_lcd_panel_draw_bitmap(lcd_panel_handle, x, y, x + w, y + h, color_data);
}
void app_main(void)
{
lcd_init();
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LCD_PIN_BL),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE};
gpio_config(&io_conf);
gpio_set_level(LCD_PIN_BL, 1);
int w = 100;
int h = 20;
color_pixel_rgb565_data_t color_data[w * h];
// uint16_t color = 0b1111100000000000;
color_pixel_rgb565_data_t color;
color.r = 0b11111;
color.g = 0;
color.b = 0;
while (1)
{
bitmap(color_data, (color.val >> 8) | (color.val << 8));
// color.val = (color.val << 1) | ((color.val >> (sizeof(color) * CHAR_BIT - 1)) & 1);
color.r++;
vTaskDelay(pdMS_TO_TICKS(100));
}
}Debug Logs.
I (941) esp_psram: SPI SRAM memory test OK
I (950) cpu_start: Pro cpu start user code
I (950) cpu_start: cpu freq: 240000000 Hz
I (950) app_init: Application information:
I (950) app_init: Project name: esp32s3_axs15231b
I (955) app_init: App version: 1
I (958) app_init: Compile time: Sep 10 2025 19:00:46
I (963) app_init: ELF file SHA256: fbb9545b3...
I (968) app_init: ESP-IDF: v5.5.1-1-g129cd0d247
I (973) efuse_init: Min chip rev: v0.0
I (976) efuse_init: Max chip rev: v0.99
I (980) efuse_init: Chip rev: v0.2
I (984) heap_init: Initializing. RAM available for dynamic allocation:
I (991) heap_init: At 3FC996D0 len 00050040 (320 KiB): RAM
I (996) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (1001) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (1006) heap_init: At 600FE000 len 00001FE8 (7 KiB): RTCRAM
I (1012) esp_psram: Adding pool of 8192K of PSRAM memory to heap allocator
I (1019) spi_flash: detected chip: winbond
I (1022) spi_flash: flash io: qio
I (1025) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (1031) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (1038) main_task: Started on CPU0
I (1048) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations
I (1048) main_task: Calling app_main()
I (1048) lcd_panel.axs15231b: LCD panel create success, version: 1.0.1
I (1398) lcd_panel.axs15231b: send init commands success
More Information.
I tried reading the datasheet of the driver but it seems like it doesn't contain all the information, or perhaps, a knowledge that I don't have (I checked other display drivers' datasheets and it seemed like they contain more information).
The only relative piece of information I found was:
The commands 10h, 20h, 21h, 28h, 29h, 36h will be updated only during V-sync periods while the module is in the “Sleep Out” mode to avoid abnormal visual effects, and will be updated immediately in the “Sleep In” mode.
In this case, swaping of axes is determined by the MADCTL command (36h). But I don't think it's the cause of the resulting black screen. I've seen many other problems with this driver which I couldn't solve but I cannot ignore this one since my purpose depends on it.
Some other problems:
- Inverstion function doesn't work
- 18-bit color depth doesn't work
- When drawing a bitmap using
esp_lcd_panel_draw_bitmap, specifying x and y coordinates doesn't have any effect at all; it just draws the bitmap starting from origin which causes partial refreshing useless.
Another question I have is about the initializing commands sequence; I copied these commands from another code but I wasn't able to find them in the datasheet to study them. Another possibility for these flaws might be wrong initializing commands.