diff --git a/components/esp_lcd/src/esp_lcd_panel_io_spi.c b/components/esp_lcd/src/esp_lcd_panel_io_spi.c index 049220a101..1e9a5e0683 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -15,6 +15,7 @@ #include "driver/gpio.h" #include "esp_log.h" #include "esp_check.h" +#include "esp_lcd_common.h" static const char *TAG = "lcd_panel.io.spi"; @@ -131,6 +132,34 @@ err: return ret; } +static void spi_lcd_prepare_cmd_buffer(esp_lcd_panel_io_spi_t *panel_io, const void *cmd) +{ + uint8_t *from = (uint8_t *)cmd; + // LCD is big-endian, e.g. to send command 0x1234, byte 0x12 should appear on the bus first + // However, the SPI peripheral will send 0x34 first, so we reversed the order below + if (panel_io->lcd_cmd_bits > 8) { + int start = 0; + int end = panel_io->lcd_cmd_bits / 8 - 1; + lcd_com_reverse_buffer_bytes(from, start, end); + } +} + +static void spi_lcd_prepare_param_buffer(esp_lcd_panel_io_spi_t *panel_io, const void *param, size_t param_size) +{ + uint8_t *from = (uint8_t *)param; + int param_width = panel_io->lcd_param_bits / 8; + size_t param_num = param_size / param_width; + // LCD is big-endian, e.g. to send command 0x1234, byte 0x12 should appear on the bus first + // However, the SPI peripheral will send 0x34 first, so we reversed the order below + if (panel_io->lcd_param_bits > 8) { + for (size_t i = 0; i < param_num; i++) { + int start = i * param_width; + int end = start + param_width - 1; + lcd_com_reverse_buffer_bytes(from, start, end); + } + } +} + static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size) { esp_err_t ret = ESP_OK; @@ -146,6 +175,7 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons spi_panel_io->num_trans_inflight = 0; lcd_trans = &spi_panel_io->trans_pool[0]; memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t)); + spi_lcd_prepare_cmd_buffer(spi_panel_io, &lcd_cmd); lcd_trans->base.user = spi_panel_io; lcd_trans->flags.dc_gpio_level = !spi_panel_io->flags.dc_data_level; // set D/C line to command mode lcd_trans->base.length = spi_panel_io->lcd_cmd_bits; @@ -162,6 +192,7 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed"); if (param && param_size) { + spi_lcd_prepare_param_buffer(spi_panel_io, param, param_size); lcd_trans->flags.dc_gpio_level = spi_panel_io->flags.dc_data_level; // set D/C line to data mode lcd_trans->base.length = param_size * 8; // transaction length is in bits lcd_trans->base.tx_buffer = param; @@ -192,6 +223,7 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons spi_panel_io->num_trans_inflight = 0; lcd_trans = &spi_panel_io->trans_pool[0]; memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t)); + spi_lcd_prepare_cmd_buffer(spi_panel_io, &lcd_cmd); lcd_trans->base.user = spi_panel_io; lcd_trans->flags.dc_gpio_level = !spi_panel_io->flags.dc_data_level; // set D/C line to command mode lcd_trans->base.length = spi_panel_io->lcd_cmd_bits; diff --git a/components/esp_lcd/test/test_rgb_panel.c b/components/esp_lcd/test/test_rgb_panel.c index 6aa1da2969..36c182ee06 100644 --- a/components/esp_lcd/test/test_rgb_panel.c +++ b/components/esp_lcd/test/test_rgb_panel.c @@ -8,27 +8,28 @@ #define TEST_LCD_H_RES (480) #define TEST_LCD_V_RES (272) -#define TEST_LCD_VSYNC_GPIO (1) -#define TEST_LCD_HSYNC_GPIO (2) -#define TEST_LCD_DE_GPIO (-1) -#define TEST_LCD_PCLK_GPIO (3) -#define TEST_LCD_DATA0_GPIO (4) // B0 -#define TEST_LCD_DATA1_GPIO (5) // B1 -#define TEST_LCD_DATA2_GPIO (6) // B2 -#define TEST_LCD_DATA3_GPIO (7) // B3 -#define TEST_LCD_DATA4_GPIO (8) // B4 -#define TEST_LCD_DATA5_GPIO (9) // G0 -#define TEST_LCD_DATA6_GPIO (10) // G1 -#define TEST_LCD_DATA7_GPIO (11) // G2 -#define TEST_LCD_DATA8_GPIO (12) // G3 -#define TEST_LCD_DATA9_GPIO (13) // G4 -#define TEST_LCD_DATA10_GPIO (14) // G5 -#define TEST_LCD_DATA11_GPIO (15) // R0 -#define TEST_LCD_DATA12_GPIO (16) // R1 -#define TEST_LCD_DATA13_GPIO (17) // R2 -#define TEST_LCD_DATA14_GPIO (18) // R3 -#define TEST_LCD_DATA15_GPIO (19) // R4 -#define TEST_LCD_DISP_EN_GPIO (-1) + +#define TEST_LCD_VSYNC_GPIO (48) +#define TEST_LCD_HSYNC_GPIO (47) +#define TEST_LCD_DE_GPIO (45) +#define TEST_LCD_PCLK_GPIO (21) +#define TEST_LCD_DATA0_GPIO (3) // B0 +#define TEST_LCD_DATA1_GPIO (4) // B1 +#define TEST_LCD_DATA2_GPIO (5) // B2 +#define TEST_LCD_DATA3_GPIO (6) // B3 +#define TEST_LCD_DATA4_GPIO (7) // B4 +#define TEST_LCD_DATA5_GPIO (8) // G0 +#define TEST_LCD_DATA6_GPIO (9) // G1 +#define TEST_LCD_DATA7_GPIO (10) // G2 +#define TEST_LCD_DATA8_GPIO (11) // G3 +#define TEST_LCD_DATA9_GPIO (12) // G4 +#define TEST_LCD_DATA10_GPIO (13) // G5 +#define TEST_LCD_DATA11_GPIO (14) // R0 +#define TEST_LCD_DATA12_GPIO (15) // R1 +#define TEST_LCD_DATA13_GPIO (16) // R2 +#define TEST_LCD_DATA14_GPIO (17) // R3 +#define TEST_LCD_DATA15_GPIO (18) // R4 +#define TEST_LCD_DISP_EN_GPIO (39) #if SOC_LCD_RGB_SUPPORTED // RGB driver consumes a huge memory to save frame buffer, only test it with PSRAM enabled @@ -66,7 +67,7 @@ TEST_CASE("lcd rgb lcd panel", "[lcd]") TEST_LCD_DATA15_GPIO, }, .timings = { - .pclk_hz = 6000000, + .pclk_hz = 12000000, .h_res = TEST_LCD_H_RES, .v_res = TEST_LCD_V_RES, .hsync_back_porch = 43, diff --git a/components/esp_lcd/test/test_spi_lcd_panel.c b/components/esp_lcd/test/test_spi_lcd_panel.c index eebb688db9..1a46ff1c9b 100644 --- a/components/esp_lcd/test/test_spi_lcd_panel.c +++ b/components/esp_lcd/test/test_spi_lcd_panel.c @@ -17,7 +17,7 @@ typedef bool (*trans_done_callback_t)(esp_lcd_panel_io_handle_t, void *, void *); -static void lcd_initialize_spi(esp_lcd_panel_io_handle_t *io_handle, esp_lcd_panel_handle_t *panel_handle, trans_done_callback_t on_color_trans_done, void *user_data, bool oct_mode) +static void lcd_initialize_spi(esp_lcd_panel_io_handle_t *io_handle, trans_done_callback_t on_color_trans_done, void *user_data, int cmd_bits, int param_bits, bool oct_mode) { gpio_config_t bk_gpio_config = { .mode = GPIO_MODE_OUTPUT, @@ -51,8 +51,8 @@ static void lcd_initialize_spi(esp_lcd_panel_io_handle_t *io_handle, esp_lcd_pan .pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ, .spi_mode = 0, .trans_queue_depth = 10, - .lcd_cmd_bits = 8, - .lcd_param_bits = 8, + .lcd_cmd_bits = cmd_bits, + .lcd_param_bits = param_bits, .on_color_trans_done = on_color_trans_done, .user_data = user_data }; @@ -61,13 +61,6 @@ static void lcd_initialize_spi(esp_lcd_panel_io_handle_t *io_handle, esp_lcd_pan io_config.spi_mode = 3; } TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_SPI_HOST_ID, &io_config, io_handle)); - - esp_lcd_panel_dev_config_t panel_config = { - .reset_gpio_num = TEST_LCD_RST_GPIO, - .color_space = ESP_LCD_COLOR_SPACE_RGB, - .bits_per_pixel = 16, - }; - TEST_ESP_OK(esp_lcd_new_panel_st7789(*io_handle, &panel_config, panel_handle)); } static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle) @@ -103,12 +96,74 @@ static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_ha #undef TEST_IMG_SIZE } +TEST_CASE("lcd panel spi io test", "[lcd]") +{ + esp_lcd_panel_io_handle_t io_handle = NULL; + lcd_initialize_spi(&io_handle, NULL, NULL, 8, 8, false); + esp_lcd_panel_io_tx_param(io_handle, 0x1A, NULL, 0); + esp_lcd_panel_io_tx_param(io_handle, 0x1B, (uint8_t[]) { + 0x11, 0x22, 0x33 + }, 3); + esp_lcd_panel_io_tx_param(io_handle, 0x1C, NULL, 0); + TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); + TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID)); + + lcd_initialize_spi(&io_handle, NULL, NULL, 16, 16, false); + esp_lcd_panel_io_tx_param(io_handle, 0x1A01, NULL, 0); + esp_lcd_panel_io_tx_param(io_handle, 0x1B02, (uint16_t[]) { + 0x11, 0x22, 0x33 + }, 6); + esp_lcd_panel_io_tx_param(io_handle, 0x1C03, NULL, 0); + TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); + TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID)); + +#if SOC_SPI_SUPPORT_OCT + lcd_initialize_spi(&io_handle, NULL, NULL, 8, 8, true); + esp_lcd_panel_io_tx_param(io_handle, 0x1A, NULL, 0); + esp_lcd_panel_io_tx_param(io_handle, 0x1B, (uint8_t[]) { + 0x11, 0x22, 0x33 + }, 3); + esp_lcd_panel_io_tx_param(io_handle, 0x1C, NULL, 0); + TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); + TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID)); + + lcd_initialize_spi(&io_handle, NULL, NULL, 16, 16, true); + esp_lcd_panel_io_tx_param(io_handle, 0x1A01, NULL, 0); + esp_lcd_panel_io_tx_param(io_handle, 0x1B02, (uint16_t[]) { + 0x11, 0x22, 0x33 + }, 6); + esp_lcd_panel_io_tx_param(io_handle, 0x1C03, NULL, 0); + TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); + TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID)); +#endif // SOC_SPI_SUPPORT_OCT +} + #if SOC_SPI_SUPPORT_OCT TEST_CASE("lcd panel with 8-line spi interface (st7789)", "[lcd]") { esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_handle_t panel_handle = NULL; - lcd_initialize_spi(&io_handle, &panel_handle, NULL, NULL, true); + lcd_initialize_spi(&io_handle, NULL, NULL, 8, 8, true); + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_LCD_RST_GPIO, + .color_space = ESP_LCD_COLOR_SPACE_RGB, + .bits_per_pixel = 16, + }; + TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); + lcd_panel_test(io_handle, panel_handle); +} + +TEST_CASE("lcd panel with 8-line spi interface (nt35510)", "[lcd]") +{ + esp_lcd_panel_io_handle_t io_handle = NULL; + esp_lcd_panel_handle_t panel_handle = NULL; + lcd_initialize_spi(&io_handle, NULL, NULL, 16, 16, true); + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_LCD_RST_GPIO, + .color_space = ESP_LCD_COLOR_SPACE_RGB, + .bits_per_pixel = 16, + }; + TEST_ESP_OK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle)); lcd_panel_test(io_handle, panel_handle); } #endif // SOC_SPI_SUPPORT_OCT @@ -117,7 +172,13 @@ TEST_CASE("lcd panel with 1-line spi interface (st7789)", "[lcd]") { esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_handle_t panel_handle = NULL; - lcd_initialize_spi(&io_handle, &panel_handle, NULL, NULL, false); + lcd_initialize_spi(&io_handle, NULL, NULL, 8, 8, false); + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_LCD_RST_GPIO, + .color_space = ESP_LCD_COLOR_SPACE_RGB, + .bits_per_pixel = 16, + }; + TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); lcd_panel_test(io_handle, panel_handle); } @@ -156,8 +217,28 @@ TEST_CASE("lvgl gui with 8-line spi interface (st7789)", "[lcd][lvgl][ignore]") lv_disp_t *disp = NULL; esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_handle_t panel_handle = NULL; - lcd_initialize_spi(&io_handle, &panel_handle, notify_lvgl_ready_to_flush, &disp, true); + lcd_initialize_spi(&io_handle, notify_lvgl_ready_to_flush, &disp, 8, 8, true); + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_LCD_RST_GPIO, + .color_space = ESP_LCD_COLOR_SPACE_RGB, + .bits_per_pixel = 16, + }; + TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); + lvgl_gui_test(io_handle, panel_handle, &disp); +} +TEST_CASE("lvgl gui with 8-line spi interface (nt35510)", "[lcd][lvgl][ignore]") +{ + lv_disp_t *disp = NULL; + esp_lcd_panel_io_handle_t io_handle = NULL; + esp_lcd_panel_handle_t panel_handle = NULL; + lcd_initialize_spi(&io_handle, notify_lvgl_ready_to_flush, &disp, 16, 16, true); + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_LCD_RST_GPIO, + .color_space = ESP_LCD_COLOR_SPACE_RGB, + .bits_per_pixel = 16, + }; + TEST_ESP_OK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle)); lvgl_gui_test(io_handle, panel_handle, &disp); } #endif // SOC_SPI_SUPPORT_OCT @@ -167,8 +248,13 @@ TEST_CASE("lvgl gui with 1-line spi interface (st7789)", "[lcd][lvgl][ignore]") lv_disp_t *disp = NULL; esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_handle_t panel_handle = NULL; - lcd_initialize_spi(&io_handle, &panel_handle, notify_lvgl_ready_to_flush, &disp, false); - + lcd_initialize_spi(&io_handle, notify_lvgl_ready_to_flush, &disp, 8, 8, false); + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_LCD_RST_GPIO, + .color_space = ESP_LCD_COLOR_SPACE_RGB, + .bits_per_pixel = 16, + }; + TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); lvgl_gui_test(io_handle, panel_handle, &disp); } diff --git a/docs/en/api-reference/peripherals/spi_master.rst b/docs/en/api-reference/peripherals/spi_master.rst index ca1cd44e81..2e6ffe15da 100644 --- a/docs/en/api-reference/peripherals/spi_master.rst +++ b/docs/en/api-reference/peripherals/spi_master.rst @@ -158,49 +158,49 @@ Supported line modes for {IDF_TARGET_NAME} are listed as follows, to make use of .. only:: not SOC_SPI_SUPPORT_OCT -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Mode name | Command Line Width | Address Line Width | Data Line Width | Transaction Flag | Bus IO setting Flag | -+==============+====================+====================+=================+============================+=========================+ -| Normal SPI | 1 | 1 | 1 | 0 | 0 | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Dual Output | 1 | 1 | 2 | SPI_TRANS_MODE_DIO | | -| | | | | | | -| | | | | | SPICOMMON_BUSFLAG_DUAL | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Dual I/O | 1 | 2 | 2 | SPI_TRANS_MODE_DIO | | | -| | | | | SPI_TRANS_MULTILINE_ADDR | | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Quad Output | 1 | 1 | 4 | SPI_TRANS_MODE_QIO | | -+--------------+--------------------+--------------------+-----------------+----------------------------+ | -| Quad I/O | 1 | 4 | 4 | SPI_TRANS_MODE_QIO | | SPICOMMON_BUSFLAG_QUAD | -| | | | | SPI_TRANS_MULTILINE_ADDR | | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Mode name | Command Line Width | Address Line Width | Data Line Width | Transaction Flag | Bus IO setting Flag | + +==============+====================+====================+=================+============================+=========================+ + | Normal SPI | 1 | 1 | 1 | 0 | 0 | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Dual Output | 1 | 1 | 2 | SPI_TRANS_MODE_DIO | | + | | | | | | | + | | | | | | SPICOMMON_BUSFLAG_DUAL | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Dual I/O | 1 | 2 | 2 | SPI_TRANS_MODE_DIO | | | + | | | | | SPI_TRANS_MULTILINE_ADDR | | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Quad Output | 1 | 1 | 4 | SPI_TRANS_MODE_QIO | | + +--------------+--------------------+--------------------+-----------------+----------------------------+ | + | Quad I/O | 1 | 4 | 4 | SPI_TRANS_MODE_QIO | | SPICOMMON_BUSFLAG_QUAD | + | | | | | SPI_TRANS_MULTILINE_ADDR | | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ .. only:: SOC_SPI_SUPPORT_OCT -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Mode name | Command Line Width | Address Line Width | Data Line Width | Transaction Flag | Bus IO setting Flag | -+==============+====================+====================+=================+============================+=========================+ -| Normal SPI | 1 | 1 | 1 | 0 | 0 | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Dual Output | 1 | 1 | 2 | SPI_TRANS_MODE_DIO | | -| | | | | | | -| | | | | | SPICOMMON_BUSFLAG_DUAL | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Dual I/O | 1 | 2 | 2 | SPI_TRANS_MODE_DIO | | | -| | | | | SPI_TRANS_MULTILINE_ADDR | | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Quad Output | 1 | 1 | 4 | SPI_TRANS_MODE_QIO | | -+--------------+--------------------+--------------------+-----------------+----------------------------+ | -| Quad I/O | 1 | 4 | 4 | SPI_TRANS_MODE_QIO | | SPICOMMON_BUSFLAG_QUAD | -| | | | | SPI_TRANS_MULTILINE_ADDR | | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ -| Octal Output | 1 | 1 | 8 | SPI_TRANS_MODE_OCT | | -+--------------+--------------------+--------------------+-----------------+----------------------------+ | -| OPI | 8 | 8 | 8 | SPI_TRANS_MODE_OCT | | SPICOMMON_BUSFLAG_OCTAL | -| | | | | SPI_TRANS_MULTILINE_ADDR | | | -| | | | | SPI_TRANS_MULTILINE_CMD | | -+--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Mode name | Command Line Width | Address Line Width | Data Line Width | Transaction Flag | Bus IO setting Flag | + +==============+====================+====================+=================+============================+=========================+ + | Normal SPI | 1 | 1 | 1 | 0 | 0 | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Dual Output | 1 | 1 | 2 | SPI_TRANS_MODE_DIO | | + | | | | | | | + | | | | | | SPICOMMON_BUSFLAG_DUAL | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Dual I/O | 1 | 2 | 2 | SPI_TRANS_MODE_DIO | | | + | | | | | SPI_TRANS_MULTILINE_ADDR | | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Quad Output | 1 | 1 | 4 | SPI_TRANS_MODE_QIO | | + +--------------+--------------------+--------------------+-----------------+----------------------------+ | + | Quad I/O | 1 | 4 | 4 | SPI_TRANS_MODE_QIO | | SPICOMMON_BUSFLAG_QUAD | + | | | | | SPI_TRANS_MULTILINE_ADDR | | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ + | Octal Output | 1 | 1 | 8 | SPI_TRANS_MODE_OCT | | + +--------------+--------------------+--------------------+-----------------+----------------------------+ | + | OPI | 8 | 8 | 8 | SPI_TRANS_MODE_OCT | | SPICOMMON_BUSFLAG_OCTAL | + | | | | | SPI_TRANS_MULTILINE_ADDR | | | + | | | | | SPI_TRANS_MULTILINE_CMD | | + +--------------+--------------------+--------------------+-----------------+----------------------------+-------------------------+ Command and Address Phases ^^^^^^^^^^^^^^^^^^^^^^^^^^