diff --git a/components/esp_lcd/include/esp_lcd_panel_rgb.h b/components/esp_lcd/include/esp_lcd_panel_rgb.h index 583ef9c53a..7b0960af78 100644 --- a/components/esp_lcd/include/esp_lcd_panel_rgb.h +++ b/components/esp_lcd/include/esp_lcd_panel_rgb.h @@ -76,26 +76,26 @@ typedef struct { } esp_lcd_rgb_panel_event_data_t; /** - * @brief Declare the prototype of the function that will be invoked when panel IO finishes transferring color data + * @brief RGB LCD VSYNC event callback prototype * * @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_config_t` + * @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_frame_trans_done_cb_t)(esp_lcd_panel_handle_t panel, esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx); +typedef bool (*esp_lcd_rgb_panel_vsync_cb_t)(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx); /** - * @brief Prototype for function to re-fill a bounce buffer. Note this is called in ISR context. + * @brief Prototype for function to re-fill a bounce buffer, rather than copying from the frame buffer * - * @param bounce_buf Bounce buffer to write data into - * @param pos_px How many pixels already were sent to the display this frame, in other words, at what pixel - * the routine should start putting data into bounce_buf - * @param len_bytes Length, in bytes, of the bounce buffer. Routine should fill this length fully. - * @param user_ctx Opaque pointer that was passed as bounce_buffer_cb_user_ctx to esp_lcd_new_rgb_panel - * @return True if the callback woke up a higher-priority task, false otherwise. + * @param[in] bounce_buf Bounce buffer to write data into + * @param[in] pos_px How many pixels already were sent to the display in this frame, in other words, + * at what pixel the routine should start putting data into bounce_buf + * @param[in] len_bytes Length, in bytes, of the bounce buffer. Routine should fill this length fully. + * @param[in] user_ctx Opaque pointer that was 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_fill_cb_t)(void *bounce_buf, int pos_px, int len_bytes, void *user_ctx); +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 LCD RGB framebuffer operation modes @@ -152,7 +152,14 @@ typedef bool (*esp_lcd_rgb_panel_bounce_buf_fill_cb_t)(void *bounce_buf, int pos * an 16-bit LCD, or even procedurally-generated framebuffer-less graphics. This option is selected * by not setting the ``fb_in_psram`` flag but supplying both a ``bounce_buffer_size_px`` value as well * as a ``on_bounce_empty`` callback. + * @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_event_callbacks_t; /** * @brief LCD RGB panel configuration structure @@ -169,11 +176,7 @@ typedef struct { int pclk_gpio_num; /*!< GPIO used for PCLK signal */ int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; /*!< GPIOs used for data lines */ int disp_gpio_num; /*!< GPIO used for display control signal, set to -1 if it's not used */ - esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; /*!< Callback invoked when one frame buffer has transferred done */ int bounce_buffer_size_px; /*!< If not-zero, the driver uses a bounce buffer in internal memory to DMA from. Value is in pixels. */ - esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty; /*!< If we use a bounce buffer, this function gets called to fill that, rather than copying from the framebuffer */ - void *bounce_buffer_cb_user_ctx; /*!< Opaque parameter to pass to the on_bounce_empty function */ - void *user_ctx; /*!< User data which would be passed to on_frame_trans_done's user_ctx */ struct { unsigned int disp_active_low: 1; /*!< If this flag is enabled, a low level of display control signal can turn the screen on; vice versa */ unsigned int relax_on_idle: 1; /*!< If this flag is enabled, the host won't refresh the LCD if nothing changed in host's frame buffer (this is usefull for LCD with built-in GRAM) */ @@ -195,6 +198,19 @@ typedef struct { */ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_config, esp_lcd_panel_handle_t *ret_panel); +/** + * @brief Register LCD RGB panel event callbacks + * + * @param[in] panel LCD panel handle, returned from `esp_lcd_new_rgb_panel()` + * @param[in] callbacks Group of callback functions + * @param[in] user_ctx User data, which will be passed to the callback functions directly + * @return + * - ESP_OK: Set event callbacks successfully + * - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument + * - ESP_FAIL: Set event callbacks failed because of other error + */ +esp_err_t esp_lcd_rgb_panel_register_event_callbacks(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_callbacks_t *callbacks, void *user_ctx); + /** * @brief Set frequency of PCLK for RGB LCD panel * diff --git a/components/esp_lcd/src/esp_lcd_rgb_panel.c b/components/esp_lcd/src/esp_lcd_rgb_panel.c index cb83ec4828..214c717d68 100644 --- a/components/esp_lcd/src/esp_lcd_rgb_panel.c +++ b/components/esp_lcd/src/esp_lcd_rgb_panel.c @@ -83,14 +83,13 @@ struct esp_rgb_panel_t { uint32_t src_clk_hz; // Peripheral source clock resolution esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width) gdma_channel_handle_t dma_chan; // DMA channel handle - esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done int bounce_buffer_size_bytes; //If not-zero, the driver uses a bounce buffer in internal memory to DMA from. It's in bytes here. uint8_t *bounce_buffer[2]; //Pointer to the bounce buffers int bounce_buf_frame_start; //If frame restarts, which bb has the initial frame data? - esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty; // If we use a bounce buffer, this function gets called to fill it rather than copying from the framebuffer - void *bounce_buffer_cb_user_ctx; //Callback data pointer - void *user_ctx; // Reserved user's data of callback functions int bounce_pos_px; // Position in whatever source material is used for the bounce buffer, in pixels + 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 + 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 portMUX_TYPE spinlock; // to protect panel specific resource from concurrent access (e.g. between task and ISR) @@ -303,6 +302,27 @@ err: } esp_err_t esp_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq_hz) +esp_err_t esp_lcd_rgb_panel_register_event_callbacks(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_callbacks_t *callbacks, void *user_ctx) +{ + ESP_RETURN_ON_FALSE(panel && callbacks, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base); +#if CONFIG_LCD_RGB_ISR_IRAM_SAFE + if (callbacks->on_vsync) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(callbacks->on_vsync), ESP_ERR_INVALID_ARG, TAG, "on_vsync callback not in IRAM"); + } + 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 (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->user_ctx = user_ctx; + return ESP_OK; +} + { ESP_RETURN_ON_FALSE(panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base); diff --git a/docs/en/migration-guides/peripherals.rst b/docs/en/migration-guides/peripherals.rst index b050656700..13a8fde2dd 100644 --- a/docs/en/migration-guides/peripherals.rst +++ b/docs/en/migration-guides/peripherals.rst @@ -267,6 +267,7 @@ LCD - The LCD panel initialization flow is slightly changed. Now the :cpp:func:`esp_lcd_panel_init` won't turn on the display automatically. User needs to call :cpp:func:`esp_lcd_panel_disp_on_off` to manually turn on the display. Note, this is different from turning on backlight. With this breaking change, user can flush a predefined pattern to the screen before turning on the screen. This can help avoid random noise on the screen after a power on reset. - :cpp:func:`esp_lcd_panel_disp_off` is deprecated, please use :cpp:func:`esp_lcd_panel_disp_on_off` instead. - ``dc_as_cmd_phase`` is removed. The SPI LCD driver currently doesn't support a 9bit SPI LCD. Please always use a dedicated GPIO to control the LCD D/C line. +- The way to register RGB panel event callbacks has been moved from the :cpp:type:`esp_lcd_rgb_panel_config_t` into a separate API :cpp:func:`esp_lcd_rgb_panel_register_event_callbacks`. However, the event callback signature is not changed. .. only:: SOC_MCPWM_SUPPORTED