spi_lcd: maximum transfer size should respect bus configuration

Also this commit added the SPI_TRANS_CS_KEEP_ACTIVE flag for io_tx_color
This commit is contained in:
morris 2023-04-11 19:01:09 +08:00
parent 09ecb70cb8
commit 640ec57014

View File

@ -21,8 +21,7 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_check.h" #include "esp_check.h"
#include "esp_lcd_common.h" #include "esp_lcd_common.h"
#include "esp_private/spi_common_internal.h"
#define LCD_SPI_MAX_DATA_SIZE (SPI_LL_DATA_MAX_BIT_LEN / 8)
static const char *TAG = "lcd_panel.io.spi"; static const char *TAG = "lcd_panel.io.spi";
@ -45,6 +44,7 @@ typedef struct {
typedef struct { typedef struct {
esp_lcd_panel_io_t base; // Base class of generic lcd panel io esp_lcd_panel_io_t base; // Base class of generic lcd panel io
spi_device_handle_t spi_dev; // SPI device handle spi_device_handle_t spi_dev; // SPI device handle
size_t spi_trans_max_bytes; // Maximum bytes that can be transmitted in one spi transaction
int dc_gpio_num; // D/C line GPIO number int dc_gpio_num; // D/C line GPIO number
esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // User register's callback, invoked when color data trans done esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // User register's callback, invoked when color data trans done
void *user_ctx; // User's private data, passed directly to callback on_color_trans_done void *user_ctx; // User's private data, passed directly to callback on_color_trans_done
@ -107,6 +107,7 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p
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;
spi_panel_io->base.register_event_callbacks = panel_io_spi_register_event_callbacks; spi_panel_io->base.register_event_callbacks = panel_io_spi_register_event_callbacks;
spi_panel_io->spi_trans_max_bytes = spi_bus_get_attr((spi_host_device_t)bus)->max_transfer_sz;
*ret_io = &(spi_panel_io->base); *ret_io = &(spi_panel_io->base);
ESP_LOGD(TAG, "new spi lcd panel io @%p", spi_panel_io); ESP_LOGD(TAG, "new spi lcd panel io @%p", spi_panel_io);
@ -305,8 +306,11 @@ 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; 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);
ESP_RETURN_ON_ERROR(spi_device_acquire_bus(spi_panel_io->spi_dev, portMAX_DELAY), TAG, "acquire spi bus failed");
bool send_cmd = (lcd_cmd >= 0);
if (send_cmd) {
// before issue a polling transaction, need to wait queued transactions finished // before issue a polling transaction, need to wait queued transactions finished
size_t num_trans_inflight = spi_panel_io->num_trans_inflight; size_t num_trans_inflight = spi_panel_io->num_trans_inflight;
for (size_t i = 0; i < num_trans_inflight; i++) { for (size_t i = 0; i < num_trans_inflight; i++) {
@ -317,7 +321,6 @@ 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]; 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));
if (send_cmd) {
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->flags.dc_gpio_level = !spi_panel_io->flags.dc_data_level; // set D/C line to command mode
@ -332,8 +335,7 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed"); ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed");
} }
// split to chunks if required: // if the color buffer is big, we want to split it into chunks, and queue the chunks one by one
// the SPI bus has a maximum transaction size determined by SPI_LL_DATA_MAX_BIT_LEN
do { do {
size_t chunk_size = color_size; size_t chunk_size = color_size;
@ -349,13 +351,15 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
} }
memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t)); memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t));
// SPI per-transfer size has its limitation, if the color buffer is too big, we need to split it into multiple trunks // SPI per-transfer size has its limitation, if the color buffer is too big, we need to split it into multiple chunks
if (chunk_size > LCD_SPI_MAX_DATA_SIZE) { if (chunk_size > spi_panel_io->spi_trans_max_bytes) {
// cap the transfer size to the maximum supported by the bus // cap the transfer size to the maximum supported by the bus
chunk_size = LCD_SPI_MAX_DATA_SIZE; chunk_size = spi_panel_io->spi_trans_max_bytes;
lcd_trans->base.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
} else { } else {
// mark en_trans_done_cb only at the last round to avoid premature completion callback // mark en_trans_done_cb only at the last round to avoid premature completion callback
lcd_trans->flags.en_trans_done_cb = 1; lcd_trans->flags.en_trans_done_cb = 1;
lcd_trans->base.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
} }
lcd_trans->base.user = spi_panel_io; lcd_trans->base.user = spi_panel_io;
@ -378,6 +382,7 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
} while (color_size > 0); // continue while we have remaining data to transmit } while (color_size > 0); // continue while we have remaining data to transmit
err: err:
spi_device_release_bus(spi_panel_io->spi_dev);
return ret; return ret;
} }