mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
esp_lcd: Add RX into SPI lcd panel.
This commit is contained in:
@@ -47,7 +47,7 @@ esp_err_t esp_lcd_panel_io_rx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, v
|
|||||||
* this function will wait until they are finished and the queue is empty before sending the command(s).
|
* this function will wait until they are finished and the queue is empty before sending the command(s).
|
||||||
*
|
*
|
||||||
* @param[in] io LCD panel IO handle, which is created by other factory API like `esp_lcd_new_panel_io_spi()`
|
* @param[in] io LCD panel IO handle, which is created by other 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 - only in SPI and I2C)
|
||||||
* @param[in] param Buffer that holds the command specific parameters, set to NULL if no parameter is needed for the command
|
* @param[in] param Buffer that holds the command specific parameters, set to NULL if no parameter is needed for the command
|
||||||
* @param[in] param_size Size of `param` in memory, in bytes, set to zero if no parameter is needed for the command
|
* @param[in] param_size Size of `param` in memory, in bytes, set to zero if no parameter is needed for the command
|
||||||
* @return
|
* @return
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
static const char *TAG = "lcd_panel.io.spi";
|
static const char *TAG = "lcd_panel.io.spi";
|
||||||
|
|
||||||
|
static esp_err_t panel_io_spi_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void *param, size_t param_size);
|
||||||
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);
|
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);
|
||||||
static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
|
static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
|
||||||
static esp_err_t panel_io_spi_del(esp_lcd_panel_io_t *io);
|
static esp_err_t panel_io_spi_del(esp_lcd_panel_io_t *io);
|
||||||
@@ -65,7 +66,6 @@ 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");
|
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 = {
|
spi_device_interface_config_t devcfg = {
|
||||||
// currently the driver only supports TX path, so half duplex is enough
|
|
||||||
.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),
|
||||||
.clock_speed_hz = io_config->pclk_hz,
|
.clock_speed_hz = io_config->pclk_hz,
|
||||||
.mode = io_config->spi_mode,
|
.mode = io_config->spi_mode,
|
||||||
@@ -96,6 +96,7 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p
|
|||||||
spi_panel_io->lcd_param_bits = io_config->lcd_param_bits;
|
spi_panel_io->lcd_param_bits = io_config->lcd_param_bits;
|
||||||
spi_panel_io->dc_gpio_num = io_config->dc_gpio_num;
|
spi_panel_io->dc_gpio_num = io_config->dc_gpio_num;
|
||||||
spi_panel_io->queue_size = io_config->trans_queue_depth;
|
spi_panel_io->queue_size = io_config->trans_queue_depth;
|
||||||
|
spi_panel_io->base.rx_param = panel_io_spi_rx_param;
|
||||||
spi_panel_io->base.tx_param = panel_io_spi_tx_param;
|
spi_panel_io->base.tx_param = panel_io_spi_tx_param;
|
||||||
spi_panel_io->base.tx_color = panel_io_spi_tx_color;
|
spi_panel_io->base.tx_color = panel_io_spi_tx_color;
|
||||||
spi_panel_io->base.del = panel_io_spi_del;
|
spi_panel_io->base.del = panel_io_spi_del;
|
||||||
@@ -170,36 +171,45 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons
|
|||||||
spi_transaction_t *spi_trans = NULL;
|
spi_transaction_t *spi_trans = NULL;
|
||||||
lcd_spi_trans_descriptor_t *lcd_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);
|
esp_lcd_panel_io_spi_t *spi_panel_io = __containerof(io, esp_lcd_panel_io_spi_t, base);
|
||||||
|
bool send_cmd = (lcd_cmd >= 0);
|
||||||
|
|
||||||
|
spi_device_acquire_bus(spi_panel_io->spi_dev, portMAX_DELAY);
|
||||||
|
|
||||||
// before issue a polling transaction, need to wait queued transactions finished
|
// before issue a polling transaction, need to wait queued transactions finished
|
||||||
for (size_t i = 0; i < spi_panel_io->num_trans_inflight; i++) {
|
size_t num_trans_inflight = spi_panel_io->num_trans_inflight;
|
||||||
|
for (size_t i = 0; i < num_trans_inflight; i++) {
|
||||||
ret = spi_device_get_trans_result(spi_panel_io->spi_dev, &spi_trans, portMAX_DELAY);
|
ret = spi_device_get_trans_result(spi_panel_io->spi_dev, &spi_trans, portMAX_DELAY);
|
||||||
ESP_GOTO_ON_ERROR(ret, err, TAG, "recycle spi transactions failed");
|
ESP_GOTO_ON_ERROR(ret, err, TAG, "recycle spi transactions failed");
|
||||||
|
spi_panel_io->num_trans_inflight--;
|
||||||
}
|
}
|
||||||
spi_panel_io->num_trans_inflight = 0;
|
|
||||||
lcd_trans = &spi_panel_io->trans_pool[0];
|
lcd_trans = &spi_panel_io->trans_pool[0];
|
||||||
memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t));
|
memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t));
|
||||||
spi_lcd_prepare_cmd_buffer(spi_panel_io, &lcd_cmd);
|
spi_lcd_prepare_cmd_buffer(spi_panel_io, &lcd_cmd);
|
||||||
lcd_trans->base.user = spi_panel_io;
|
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.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
|
||||||
lcd_trans->base.length = spi_panel_io->lcd_cmd_bits;
|
|
||||||
lcd_trans->base.tx_buffer = &lcd_cmd;
|
|
||||||
if (spi_panel_io->flags.octal_mode) {
|
if (spi_panel_io->flags.octal_mode) {
|
||||||
// use 8 lines for transmitting command, address and data
|
// 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);
|
lcd_trans->base.flags |= (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MODE_OCT);
|
||||||
}
|
}
|
||||||
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
|
||||||
lcd_trans->base.cmd = !spi_panel_io->flags.dc_data_level;
|
if (send_cmd) {
|
||||||
|
lcd_trans->flags.dc_gpio_level = !spi_panel_io->flags.dc_data_level; // set D/C line to command mode
|
||||||
|
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
||||||
|
lcd_trans->base.cmd = !spi_panel_io->flags.dc_data_level;
|
||||||
|
}
|
||||||
|
lcd_trans->base.length = spi_panel_io->lcd_cmd_bits;
|
||||||
|
lcd_trans->base.tx_buffer = &lcd_cmd;
|
||||||
|
// 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");
|
|
||||||
|
|
||||||
if (param && param_size) {
|
if (param && param_size) {
|
||||||
spi_lcd_prepare_param_buffer(spi_panel_io, 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->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.length = param_size * 8; // transaction length is in bits
|
||||||
lcd_trans->base.tx_buffer = param;
|
lcd_trans->base.tx_buffer = param;
|
||||||
|
lcd_trans->base.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
|
||||||
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
||||||
lcd_trans->base.cmd = spi_panel_io->flags.dc_data_level;
|
lcd_trans->base.cmd = spi_panel_io->flags.dc_data_level;
|
||||||
}
|
}
|
||||||
@@ -209,6 +219,68 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
spi_device_release_bus(spi_panel_io->spi_dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_io_spi_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void *param, size_t param_size)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
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);
|
||||||
|
|
||||||
|
spi_device_acquire_bus(spi_panel_io->spi_dev, portMAX_DELAY);
|
||||||
|
|
||||||
|
// before issue a polling transaction, need to wait queued transactions finished
|
||||||
|
size_t num_trans_inflight = spi_panel_io->num_trans_inflight;
|
||||||
|
for (size_t i = 0; i < num_trans_inflight; i++) {
|
||||||
|
ret = spi_device_get_trans_result(spi_panel_io->spi_dev, &spi_trans, portMAX_DELAY);
|
||||||
|
ESP_GOTO_ON_ERROR(ret, err, TAG, "recycle spi transactions failed");
|
||||||
|
spi_panel_io->num_trans_inflight--;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
// 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) {
|
||||||
|
lcd_trans->flags.dc_gpio_level = !spi_panel_io->flags.dc_data_level; // set D/C line to command mode
|
||||||
|
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
||||||
|
lcd_trans->base.cmd = !spi_panel_io->flags.dc_data_level;
|
||||||
|
}
|
||||||
|
lcd_trans->base.length = spi_panel_io->lcd_cmd_bits;
|
||||||
|
lcd_trans->base.tx_buffer = &lcd_cmd;
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (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 = 0;
|
||||||
|
lcd_trans->base.tx_buffer = NULL;
|
||||||
|
lcd_trans->base.rxlength = param_size * 8; // Read length in bits
|
||||||
|
lcd_trans->base.rx_buffer = param;
|
||||||
|
lcd_trans->base.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
|
||||||
|
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
||||||
|
lcd_trans->base.cmd = spi_panel_io->flags.dc_data_level;
|
||||||
|
}
|
||||||
|
// parameter is usually 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) param failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
spi_device_release_bus(spi_panel_io->spi_dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user