Bladeren bron

spi_lcd: maximum transfer size should respect bus configuration

Also this commit added the SPI_TRANS_CS_KEEP_ACTIVE flag for io_tx_color
morris 2 jaren geleden
bovenliggende
commit
640ec57014
1 gewijzigde bestanden met toevoegingen van 22 en 17 verwijderingen
  1. 22 17
      components/esp_lcd/src/esp_lcd_panel_io_spi.c

+ 22 - 17
components/esp_lcd/src/esp_lcd_panel_io_spi.c

@@ -21,8 +21,7 @@
 #include "esp_log.h"
 #include "esp_check.h"
 #include "esp_lcd_common.h"
-
-#define LCD_SPI_MAX_DATA_SIZE (SPI_LL_DATA_MAX_BIT_LEN / 8)
+#include "esp_private/spi_common_internal.h"
 
 static const char *TAG = "lcd_panel.io.spi";
 
@@ -45,6 +44,7 @@ typedef struct {
 typedef struct {
     esp_lcd_panel_io_t base;     // Base class of generic lcd panel io
     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
     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
@@ -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.del = panel_io_spi_del;
     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);
     ESP_LOGD(TAG, "new spi lcd panel io @%p", spi_panel_io);
 
@@ -305,19 +306,21 @@ 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;
-    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));
+    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
+        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->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");
     }
 
-    // split to chunks if required:
-    // the SPI bus has a maximum transaction size determined by SPI_LL_DATA_MAX_BIT_LEN
+    // if the color buffer is big, we want to split it into chunks, and queue the chunks one by one
     do {
         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));
 
-        // SPI per-transfer size has its limitation, if the color buffer is too big, we need to split it into multiple trunks
-        if (chunk_size > LCD_SPI_MAX_DATA_SIZE) {
+        // 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 > spi_panel_io->spi_trans_max_bytes) {
             // 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 {
             // 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->base.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
         }
 
         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
 
 err:
+    spi_device_release_bus(spi_panel_io->spi_dev);
     return ret;
 }