Эх сурвалжийг харах

Merge branch 'feature/esp_lcd_spi_support_quad_mode' into 'master'

esp_lcd: spi support quad mode

Closes IDFGH-10543 and IDF-5538

See merge request espressif/esp-idf!25390
morris 2 жил өмнө
parent
commit
fc4fcb5519

+ 1 - 0
components/esp_lcd/include/esp_lcd_panel_io.h

@@ -138,6 +138,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 quad_mode: 1;       /*!< transmit with quad mode (4 data lines), this mode is useful when transmitting LCD parameters (Only use one line for command) */
         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 */

+ 13 - 2
components/esp_lcd/include/esp_lcd_panel_rgb.h

@@ -99,14 +99,25 @@ typedef bool (*esp_lcd_rgb_panel_vsync_cb_t)(esp_lcd_panel_handle_t panel, const
  */
 typedef bool (*esp_lcd_rgb_panel_bounce_buf_fill_cb_t)(esp_lcd_panel_handle_t panel, void *bounce_buf, int pos_px, int len_bytes, void *user_ctx);
 
+/**
+ * @brief Prototype for the function to be called when the bounce buffer finish copying the entire frame.
+ *
+ * @param[in] panel LCD panel handle, returned from `esp_lcd_new_rgb_panel`
+ * @param[in] edata Panel event data, fed by driver
+ * @param[in] user_ctx User data, passed from `esp_lcd_rgb_panel_register_event_callbacks()`
+ * @return Whether a high priority task has been waken up by this function
+ */
+typedef bool (*esp_lcd_rgb_panel_bounce_buf_finish_cb_t)(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx);
+
 /**
  * @brief Group of supported RGB LCD panel callbacks
  * @note The callbacks are all running under ISR environment
  * @note When CONFIG_LCD_RGB_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
  */
 typedef struct {
-    esp_lcd_rgb_panel_vsync_cb_t on_vsync;                  /*!< VSYNC event callback */
-    esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty; /*!< Bounce buffer empty callback. */
+    esp_lcd_rgb_panel_vsync_cb_t on_vsync;                      /*!< VSYNC event callback */
+    esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty;     /*!< Bounce buffer empty callback. */
+    esp_lcd_rgb_panel_bounce_buf_finish_cb_t on_bounce_frame_finish;  /*!< Bounce buffer finish callback. */
 } esp_lcd_rgb_panel_event_callbacks_t;
 
 /**

+ 8 - 0
components/esp_lcd/src/esp_lcd_panel_io_spi.c

@@ -53,6 +53,7 @@ typedef struct {
     struct {
         unsigned int dc_data_level: 1;   // Indicates the level of DC line when tranfering data
         unsigned int octal_mode: 1;      // Indicates whether the transmitting is enabled with octal mode (8 data lines)
+        unsigned int quad_mode: 1;       // Indicates whether the transmitting is enabled with quad mode (4 data lines)
     } flags;
     lcd_spi_trans_descriptor_t trans_pool[]; // Transaction pool
 } esp_lcd_panel_io_spi_t;
@@ -94,6 +95,7 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p
 
     spi_panel_io->flags.dc_data_level = !io_config->flags.dc_low_on_data;
     spi_panel_io->flags.octal_mode = io_config->flags.octal_mode;
+    spi_panel_io->flags.quad_mode = io_config->flags.quad_mode;
     spi_panel_io->on_color_trans_done = io_config->on_color_trans_done;
     spi_panel_io->user_ctx = io_config->user_ctx;
     spi_panel_io->lcd_cmd_bits = io_config->lcd_cmd_bits;
@@ -328,6 +330,9 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
         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(color && color_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);
@@ -371,6 +376,9 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
         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);
+        } else if (spi_panel_io->flags.quad_mode) {
+            // use 4 lines only for transmitting data
+            lcd_trans->base.flags |= SPI_TRANS_MODE_QIO;
         }
 
         // color data is usually large, using queue+blocking mode

+ 13 - 1
components/esp_lcd/src/esp_lcd_panel_rgb.c

@@ -110,6 +110,7 @@ struct esp_rgb_panel_t {
     gdma_channel_handle_t dma_chan; // DMA channel handle
     esp_lcd_rgb_panel_vsync_cb_t on_vsync; // VSYNC event callback
     esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty; // callback used to fill a bounce buffer rather than copying from the frame buffer
+    esp_lcd_rgb_panel_bounce_buf_finish_cb_t on_bounce_frame_finish; // callback used to notify when the bounce buffer finish copying the entire frame
     void *user_ctx;                 // Reserved user's data of callback functions
     int x_gap;                      // Extra gap in x coordinate, it's used when calculate the flush window
     int y_gap;                      // Extra gap in y coordinate, it's used when calculate the flush window
@@ -364,12 +365,16 @@ esp_err_t esp_lcd_rgb_panel_register_event_callbacks(esp_lcd_panel_handle_t pane
     if (callbacks->on_bounce_empty) {
         ESP_RETURN_ON_FALSE(esp_ptr_in_iram(callbacks->on_bounce_empty), ESP_ERR_INVALID_ARG, TAG, "on_bounce_empty callback not in IRAM");
     }
+    if (callbacks->on_bounce_frame_finish) {
+        ESP_RETURN_ON_FALSE(esp_ptr_in_iram(callbacks->on_bounce_frame_finish), ESP_ERR_INVALID_ARG, TAG, "on_bounce_frame_finish callback not in IRAM");
+    }
     if (user_ctx) {
         ESP_RETURN_ON_FALSE(esp_ptr_internal(user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
     }
 #endif // CONFIG_LCD_RGB_ISR_IRAM_SAFE
     rgb_panel->on_vsync = callbacks->on_vsync;
     rgb_panel->on_bounce_empty = callbacks->on_bounce_empty;
+    rgb_panel->on_bounce_frame_finish = callbacks->on_bounce_frame_finish;
     rgb_panel->user_ctx = user_ctx;
     return ESP_OK;
 }
@@ -886,7 +891,9 @@ static IRAM_ATTR bool lcd_rgb_panel_fill_bounce_buffer(esp_rgb_panel_t *panel, u
     if (panel->num_fbs == 0) {
         if (panel->on_bounce_empty) {
             // We don't have a frame buffer here; we need to call a callback to refill the bounce buffer
-            need_yield = panel->on_bounce_empty(&panel->base, buffer, panel->bounce_pos_px, panel->bb_size, panel->user_ctx);
+            if (panel->on_bounce_empty(&panel->base, buffer, panel->bounce_pos_px, panel->bb_size, panel->user_ctx)) {
+                need_yield = true;
+            }
         }
     } else {
         // We do have frame buffer; copy from there.
@@ -903,6 +910,11 @@ static IRAM_ATTR bool lcd_rgb_panel_fill_bounce_buffer(esp_rgb_panel_t *panel, u
     if (panel->bounce_pos_px >= panel->fb_size / bytes_per_pixel) {
         panel->bounce_pos_px = 0;
         panel->bb_fb_index = panel->cur_fb_index;
+        if (panel->on_bounce_frame_finish) {
+            if (panel->on_bounce_frame_finish(&panel->base, NULL, panel->user_ctx)) {
+                need_yield = true;
+            }
+        }
     }
     if (panel->num_fbs > 0) {
         // Preload the next bit of buffer from psram