rgb_lcd: support update pclk at runtime

pull/9179/head
morris 2022-06-01 11:00:00 +08:00
rodzic 843279d287
commit b2bb8fd3c4
4 zmienionych plików z 49 dodań i 2 usunięć

Wyświetl plik

@ -78,7 +78,7 @@ typedef struct {
/**
* @brief Declare the prototype of the function that will be invoked when panel IO finishes transferring color data
*
* @param[in] panel LCD panel handle, returned from `esp_lcd_new_rgb_panel`
* @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`
* @return Whether a high priority task has been waken up by this function
@ -122,6 +122,24 @@ 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 Set frequency of PCLK for RGB LCD panel
*
* @note The PCLK frequency is set in the `esp_lcd_rgb_timing_t` and gets configured during LCD panel initialization.
* Usually you don't need to call this function to set the PCLK again, but in some cases, you may need to change the PCLK frequency.
* e.g. to slow down the PCLK frequency to reduce power consumption or to reduce the memory throughput.
* @note This function doesn't cause the hardware to update the PCLK immediately but to record the new frequency and set a flag internally.
* Next time when start a new transaction, the driver will update the PCLK automatically.
*
* @param panel LCD panel handle, returned from `esp_lcd_new_rgb_panel()`
* @param freq_hz Frequency of pixel clock, in Hz
* @return
* - ESP_ERR_NOT_SUPPORTED if frequency is unreachable
* - ESP_ERR_INVALID_ARG if parameter panel is invalid
* - ESP_OK on success
*/
esp_err_t esp_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq_hz);
#endif // SOC_LCD_RGB_SUPPORTED
#ifdef __cplusplus

Wyświetl plik

@ -88,10 +88,12 @@ struct esp_rgb_panel_t {
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)
struct {
unsigned int disp_en_level: 1; // The level which can turn on the screen by `disp_gpio_num`
unsigned int stream_mode: 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done
unsigned int fb_in_psram: 1; // Whether the frame buffer is in PSRAM
unsigned int need_update_pclk: 1; // Whether to update the PCLK before start a new transaction
} flags;
dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes`
};
@ -187,6 +189,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
rgb_panel->flags.disp_en_level = !rgb_panel_config->flags.disp_active_low;
rgb_panel->on_frame_trans_done = rgb_panel_config->on_frame_trans_done;
rgb_panel->user_ctx = rgb_panel_config->user_ctx;
rgb_panel->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
// fill function table
rgb_panel->base.del = rgb_panel_del;
rgb_panel->base.reset = rgb_panel_reset;
@ -227,6 +230,18 @@ err:
return ret;
}
esp_err_t esp_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq_hz)
{
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);
// the pclk frequency will be updated in `lcd_rgb_panel_start_transmission()`
portENTER_CRITICAL(&rgb_panel->spinlock);
rgb_panel->flags.need_update_pclk = true;
rgb_panel->timings.pclk_hz = freq_hz;
portEXIT_CRITICAL(&rgb_panel->spinlock);
return ESP_OK;
}
static esp_err_t rgb_panel_del(esp_lcd_panel_t *panel)
{
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
@ -499,6 +514,15 @@ static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel)
// reset FIFO of DMA and LCD, incase there remains old frame data
gdma_reset(rgb_panel->dma_chan);
lcd_ll_stop(rgb_panel->hal.dev);
// check whether to update the PCLK frequency
portENTER_CRITICAL_SAFE(&rgb_panel->spinlock);
if (unlikely(rgb_panel->flags.need_update_pclk)) {
rgb_panel->flags.need_update_pclk = false;
rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz);
}
portEXIT_CRITICAL_SAFE(&rgb_panel->spinlock);
lcd_ll_fifo_reset(rgb_panel->hal.dev);
gdma_start(rgb_panel->dma_chan, (intptr_t)rgb_panel->dma_nodes);
// delay 1us is sufficient for DMA to pass data to LCD FIFO

Wyświetl plik

@ -85,6 +85,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "emac_hal.c")
endif()
if(CONFIG_SOC_LCDCAM_SUPPORTED)
list(APPEND srcs "lcd_hal.c")
endif()
if(${target} STREQUAL "esp32")
list(APPEND srcs
"dac_hal.c"
@ -119,7 +123,6 @@ if(NOT BOOTLOADER_BUILD)
if(${target} STREQUAL "esp32s3")
list(APPEND srcs
"ds_hal.c"
"lcd_hal.c"
"spi_flash_hal_gpspi.c"
"spi_slave_hd_hal.c"
"touch_sensor_hal.c"

Wyświetl plik

@ -28,3 +28,5 @@ entries:
timer_hal_iram (noflash)
if GPIO_CTRL_FUNC_IN_IRAM = y:
gpio_hal: gpio_hal_intr_disable (noflash)
if LCD_RGB_ISR_IRAM_SAFE = y:
lcd_hal: lcd_hal_cal_pclk_freq (noflash)