From 39d2a2e0bdb4b0cc5d107808651df5f6e6afcd13 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 10 Oct 2022 14:42:47 +0800 Subject: [PATCH 1/5] spi_lcd: support CS active high Closes https://github.com/espressif/esp-idf/issues/9881 --- components/esp_lcd/include/esp_lcd_panel_io.h | 1 + components/esp_lcd/src/esp_lcd_panel_io_spi.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index f702a9251e50..95ff1232ed48 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/components/esp_lcd/include/esp_lcd_panel_io.h @@ -117,6 +117,7 @@ typedef struct { unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */ unsigned int octal_mode: 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */ unsigned int lsb_first: 1; /*!< transmit LSB bit first */ + unsigned int cs_high_active: 1; /*!< CS line is high active */ } flags; /*!< Extra flags to fine-tune the SPI device */ } esp_lcd_panel_io_spi_config_t; 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 d63d9e1b6d23..058e22c70797 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -73,7 +73,9 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p ESP_GOTO_ON_FALSE(spi_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for spi panel io"); spi_device_interface_config_t devcfg = { - .flags = SPI_DEVICE_HALFDUPLEX | (io_config->flags.lsb_first ? SPI_DEVICE_TXBIT_LSBFIRST : 0), + .flags = SPI_DEVICE_HALFDUPLEX | + (io_config->flags.lsb_first ? SPI_DEVICE_TXBIT_LSBFIRST : 0) | + (io_config->flags.cs_high_active ? SPI_DEVICE_POSITIVE_CS : 0), .clock_speed_hz = io_config->pclk_hz, .mode = io_config->spi_mode, .spics_io_num = io_config->cs_gpio_num, From e518e3efd3d75a7875e5db782a0213f1224fcdac Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 10 Oct 2022 14:57:17 +0800 Subject: [PATCH 2/5] spi_lcd: allow dc gpio set to -1 Closes https://github.com/espressif/esp-idf/issues/9881 --- components/esp_lcd/include/esp_lcd_panel_io.h | 2 +- components/esp_lcd/src/esp_lcd_panel_io_spi.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index 95ff1232ed48..9fdbbf4dc6bf 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/components/esp_lcd/include/esp_lcd_panel_io.h @@ -105,7 +105,7 @@ typedef bool (*esp_lcd_panel_io_color_trans_done_cb_t)(esp_lcd_panel_io_handle_t */ typedef struct { int cs_gpio_num; /*!< GPIO used for CS line */ - int dc_gpio_num; /*!< GPIO used to select the D/C line, set this to -1 if the D/C line not controlled by manually pulling high/low GPIO */ + int dc_gpio_num; /*!< GPIO used to select the D/C line, set this to -1 if the D/C line is not used */ int spi_mode; /*!< Traditional SPI mode (0~3) */ unsigned int pclk_hz; /*!< Frequency of pixel clock */ size_t trans_queue_depth; /*!< Size of internal transaction queue */ 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 058e22c70797..677a14ca9d1f 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -66,9 +66,6 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p esp_err_t ret = ESP_OK; esp_lcd_panel_io_spi_t *spi_panel_io = NULL; ESP_GOTO_ON_FALSE(bus && io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - // at the moment, the hardware doesn't support 9-bit SPI LCD, but in the future, there will be such a feature - // so for now, we will force the user to use the GPIO to control the LCD's D/C line. - ESP_GOTO_ON_FALSE(io_config->dc_gpio_num >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid DC mode"); spi_panel_io = calloc(1, sizeof(esp_lcd_panel_io_spi_t) + sizeof(lcd_spi_trans_descriptor_t) * io_config->trans_queue_depth); ESP_GOTO_ON_FALSE(spi_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for spi panel io"); From 4c3c23562c315578c6708d784e53621d556208f1 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 10 Oct 2022 16:30:52 +0800 Subject: [PATCH 3/5] spi_lcd: panel_io_spi_tx_color without cmd Closes https://github.com/espressif/esp-idf/issues/9881 --- components/esp_lcd/include/esp_lcd_panel_io.h | 14 ++++---- components/esp_lcd/src/esp_lcd_panel_io_spi.c | 32 +++++++++++-------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index 9fdbbf4dc6bf..035864b36a3f 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/components/esp_lcd/include/esp_lcd_panel_io.h @@ -23,7 +23,7 @@ typedef struct esp_lcd_i80_bus_t *esp_lcd_i80_bus_handle_t; /*!< Type of LCD i * @brief Transmit LCD command and receive corresponding parameters * * @note Commands sent by this function are short, so they are sent using polling transactions. - * The function does not return before the command tranfer is completed. + * The function does not return before the command transfer is completed. * If any queued transactions sent by `esp_lcd_panel_io_tx_color()` are still pending when this function is called, * this function will wait until they are finished and the queue is empty before sending the command(s). * @@ -42,7 +42,7 @@ esp_err_t esp_lcd_panel_io_rx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, v * @brief Transmit LCD command and corresponding parameters * * @note Commands sent by this function are short, so they are sent using polling transactions. - * The function does not return before the command tranfer is completed. + * The function does not return before the command transfer is completed. * If any queued transactions sent by `esp_lcd_panel_io_tx_color()` are still pending when this function is called, * this function will wait until they are finished and the queue is empty before sending the command(s). * @@ -65,7 +65,7 @@ esp_err_t esp_lcd_panel_io_tx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, c * Recycling of color buffer should be done in the callback `on_color_trans_done()`. * * @param[in] io LCD panel IO handle, which is created by factory API like `esp_lcd_new_panel_io_spi()` - * @param[in] lcd_cmd The specific LCD command + * @param[in] lcd_cmd The specific LCD command, set to -1 if no command needed * @param[in] color Buffer that holds the RGB color data * @param[in] color_size Size of `color` in memory, in bytes * @return @@ -75,7 +75,7 @@ esp_err_t esp_lcd_panel_io_tx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, c esp_err_t esp_lcd_panel_io_tx_color(esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *color, size_t color_size); /** - * @brief Destory LCD panel IO handle (deinitialize panel and free all corresponding resource) + * @brief Destroy LCD panel IO handle (deinitialize panel and free all corresponding resource) * * @param[in] io LCD panel IO handle, which is created by factory API like `esp_lcd_new_panel_io_spi()` * @return @@ -142,7 +142,7 @@ typedef struct { uint32_t dev_addr; /*!< I2C device address */ esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ - size_t control_phase_bytes; /*!< I2C LCD panel will encode control information (e.g. D/C seclection) into control phase, in several bytes */ + size_t control_phase_bytes; /*!< I2C LCD panel will encode control information (e.g. D/C selection) into control phase, in several bytes */ unsigned int dc_bit_offset; /*!< Offset of the D/C selection bit in control phase */ int lcd_cmd_bits; /*!< Bit-width of LCD command */ int lcd_param_bits; /*!< Bit-width of LCD parameter */ @@ -194,7 +194,7 @@ typedef struct { esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lcd_i80_bus_handle_t *ret_bus); /** - * @brief Destory Intel 8080 bus handle + * @brief Destroy Intel 8080 bus handle * * @param[in] bus Intel 8080 bus handle, created by `esp_lcd_new_i80_bus()` * @return @@ -211,7 +211,7 @@ typedef struct { int cs_gpio_num; /*!< GPIO used for CS line, set to -1 will declaim exclusively use of I80 bus */ uint32_t pclk_hz; /*!< Frequency of pixel clock */ size_t trans_queue_depth; /*!< Transaction queue size, larger queue, higher throughput */ - esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data was tranferred done */ + esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data was transferred done */ void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ int lcd_cmd_bits; /*!< Bit-width of LCD command */ int lcd_param_bits; /*!< Bit-width of LCD parameter */ 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 677a14ca9d1f..10b9f055af8b 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -190,7 +190,7 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons } 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->base.flags |= SPI_TRANS_CS_KEEP_ACTIVE; if (spi_panel_io->flags.octal_mode) { @@ -199,6 +199,7 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons } if (send_cmd) { + spi_lcd_prepare_cmd_buffer(spi_panel_io, &lcd_cmd); 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; lcd_trans->base.tx_buffer = &lcd_cmd; @@ -243,7 +244,7 @@ static esp_err_t panel_io_spi_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void } 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->base.flags |= SPI_TRANS_CS_KEEP_ACTIVE; if (spi_panel_io->flags.octal_mode) { @@ -252,6 +253,7 @@ static esp_err_t panel_io_spi_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void } if (send_cmd) { + spi_lcd_prepare_cmd_buffer(spi_panel_io, &lcd_cmd); 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; lcd_trans->base.tx_buffer = &lcd_cmd; @@ -284,6 +286,7 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons spi_transaction_t *spi_trans = NULL; lcd_spi_trans_descriptor_t *lcd_trans = NULL; esp_lcd_panel_io_spi_t *spi_panel_io = __containerof(io, esp_lcd_panel_io_spi_t, base); + bool send_cmd = (lcd_cmd >= 0); // before issue a polling transaction, need to wait queued transactions finished size_t num_trans_inflight = spi_panel_io->num_trans_inflight; @@ -294,18 +297,21 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons } 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; - lcd_trans->base.tx_buffer = &lcd_cmd; - if (spi_panel_io->flags.octal_mode) { - // use 8 lines for transmitting command, address and data - lcd_trans->base.flags |= (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MODE_OCT); + + if (send_cmd) { + 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; + lcd_trans->base.tx_buffer = &lcd_cmd; + if (spi_panel_io->flags.octal_mode) { + // use 8 lines for transmitting command, address and data + lcd_trans->base.flags |= (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MODE_OCT); + } + // command is short, using polling mode + ret = spi_device_polling_transmit(spi_panel_io->spi_dev, &lcd_trans->base); + ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed"); } - // command is short, using polling mode - ret = spi_device_polling_transmit(spi_panel_io->spi_dev, &lcd_trans->base); - ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed"); // split to chunks if required: // the SPI bus has a maximum transaction size determined by SPI_LL_DATA_MAX_BIT_LEN From 313700e2854ac643a66c834af14e15cc69ebfcf8 Mon Sep 17 00:00:00 2001 From: Liu Zhongwei Date: Mon, 14 Nov 2022 16:33:36 +0800 Subject: [PATCH 4/5] esp_lcd: support sio mode for spi LCD --- components/esp_lcd/include/esp_lcd_panel_io.h | 1 + components/esp_lcd/src/esp_lcd_panel_io_spi.c | 1 + 2 files changed, 2 insertions(+) diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index 035864b36a3f..b7e4ab2e2f19 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/components/esp_lcd/include/esp_lcd_panel_io.h @@ -116,6 +116,7 @@ typedef struct { struct { unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */ unsigned int octal_mode: 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */ + unsigned int sio_mode: 1; /*!< Read and write through a single data line (MOSI) */ unsigned int lsb_first: 1; /*!< transmit LSB bit first */ unsigned int cs_high_active: 1; /*!< CS line is high active */ } flags; /*!< Extra flags to fine-tune the SPI device */ 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 10b9f055af8b..76692b99e356 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -72,6 +72,7 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p spi_device_interface_config_t devcfg = { .flags = SPI_DEVICE_HALFDUPLEX | (io_config->flags.lsb_first ? SPI_DEVICE_TXBIT_LSBFIRST : 0) | + (io_config->flags.sio_mode ? SPI_DEVICE_3WIRE : 0) | (io_config->flags.cs_high_active ? SPI_DEVICE_POSITIVE_CS : 0), .clock_speed_hz = io_config->pclk_hz, .mode = io_config->spi_mode, From 69b9b0b7a69b133bdf19cc5b28ce508fd6afd566 Mon Sep 17 00:00:00 2001 From: Liu Zhongwei Date: Mon, 14 Nov 2022 17:55:27 +0800 Subject: [PATCH 5/5] esp_lcd: add condition for spi to keep cs low --- components/esp_lcd/src/esp_lcd_panel_io_spi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 76692b99e356..ab359090418b 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -193,7 +193,9 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t)); lcd_trans->base.user = spi_panel_io; - lcd_trans->base.flags |= SPI_TRANS_CS_KEEP_ACTIVE; + if (param && param_size) { + lcd_trans->base.flags |= SPI_TRANS_CS_KEEP_ACTIVE; + } if (spi_panel_io->flags.octal_mode) { // use 8 lines for transmitting command, address and data lcd_trans->base.flags |= (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MODE_OCT);