mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
feat(lcd): increase the upper limit of pclk frequency for RGB LCD
This commit is contained in:
parent
25a1ad7e98
commit
00f21c37fe
@ -133,7 +133,6 @@ struct esp_rgb_panel_t {
|
|||||||
int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window
|
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
|
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)
|
portMUX_TYPE spinlock; // to protect panel specific resource from concurrent access (e.g. between task and ISR)
|
||||||
int lcd_clk_flags; // LCD clock calculation flags
|
|
||||||
int rotate_mask; // panel rotate_mask mask, Or'ed of `panel_rotate_mask_t`
|
int rotate_mask; // panel rotate_mask mask, Or'ed of `panel_rotate_mask_t`
|
||||||
struct {
|
struct {
|
||||||
uint32_t disp_en_level: 1; // The level which can turn on the screen by `disp_gpio_num`
|
uint32_t disp_en_level: 1; // The level which can turn on the screen by `disp_gpio_num`
|
||||||
@ -326,11 +325,6 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
|
|||||||
// reset peripheral and FIFO after we select a correct clock source
|
// reset peripheral and FIFO after we select a correct clock source
|
||||||
lcd_ll_fifo_reset(rgb_panel->hal.dev);
|
lcd_ll_fifo_reset(rgb_panel->hal.dev);
|
||||||
lcd_ll_reset(rgb_panel->hal.dev);
|
lcd_ll_reset(rgb_panel->hal.dev);
|
||||||
// set minimal PCLK divider
|
|
||||||
// A limitation in the hardware, if the LCD_PCLK == LCD_CLK, then the PCLK polarity can't be adjustable
|
|
||||||
if (!(rgb_panel_config->timings.flags.pclk_active_neg || rgb_panel_config->timings.flags.pclk_idle_high)) {
|
|
||||||
rgb_panel->lcd_clk_flags |= LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK;
|
|
||||||
}
|
|
||||||
// install interrupt service, (LCD peripheral shares the interrupt source with Camera by different mask)
|
// install interrupt service, (LCD peripheral shares the interrupt source with Camera by different mask)
|
||||||
int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
|
int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
|
||||||
ret = esp_intr_alloc_intrstatus(lcd_periph_rgb_signals.panels[panel_id].irq_id, isr_flags,
|
ret = esp_intr_alloc_intrstatus(lcd_periph_rgb_signals.panels[panel_id].irq_id, isr_flags,
|
||||||
@ -542,7 +536,7 @@ static esp_err_t rgb_panel_init(esp_lcd_panel_t *panel)
|
|||||||
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
|
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
|
||||||
// set pixel clock frequency
|
// set pixel clock frequency
|
||||||
hal_utils_clk_div_t lcd_clk_div = {};
|
hal_utils_clk_div_t lcd_clk_div = {};
|
||||||
rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz, rgb_panel->lcd_clk_flags, &lcd_clk_div);
|
rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz, &lcd_clk_div);
|
||||||
LCD_CLOCK_SRC_ATOMIC() {
|
LCD_CLOCK_SRC_ATOMIC() {
|
||||||
lcd_ll_set_group_clock_coeff(rgb_panel->hal.dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
|
lcd_ll_set_group_clock_coeff(rgb_panel->hal.dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
|
||||||
}
|
}
|
||||||
@ -1112,7 +1106,7 @@ IRAM_ATTR static void lcd_rgb_panel_try_update_pclk(esp_rgb_panel_t *rgb_panel)
|
|||||||
portENTER_CRITICAL_ISR(&rgb_panel->spinlock);
|
portENTER_CRITICAL_ISR(&rgb_panel->spinlock);
|
||||||
if (unlikely(rgb_panel->flags.need_update_pclk)) {
|
if (unlikely(rgb_panel->flags.need_update_pclk)) {
|
||||||
rgb_panel->flags.need_update_pclk = false;
|
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, rgb_panel->lcd_clk_flags, &lcd_clk_div);
|
rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz, &lcd_clk_div);
|
||||||
LCD_CLOCK_SRC_ATOMIC() {
|
LCD_CLOCK_SRC_ATOMIC() {
|
||||||
lcd_ll_set_group_clock_coeff(rgb_panel->hal.dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
|
lcd_ll_set_group_clock_coeff(rgb_panel->hal.dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
|
||||||
}
|
}
|
||||||
|
@ -130,12 +130,8 @@ __attribute__((always_inline))
|
|||||||
static inline void lcd_ll_set_group_clock_coeff(lcd_cam_dev_t *dev, int div_num, int div_a, int div_b)
|
static inline void lcd_ll_set_group_clock_coeff(lcd_cam_dev_t *dev, int div_num, int div_a, int div_b)
|
||||||
{
|
{
|
||||||
// lcd_clk = module_clock_src / (div_num + div_b / div_a)
|
// lcd_clk = module_clock_src / (div_num + div_b / div_a)
|
||||||
HAL_ASSERT(div_num >= 2 && div_num <= LCD_LL_CLK_FRAC_DIV_N_MAX);
|
HAL_ASSERT(div_num > 0 && div_num <= LCD_LL_CLK_FRAC_DIV_N_MAX);
|
||||||
// dic_num == 0 means LCD_LL_CLK_FRAC_DIV_N_MAX divider in hardware
|
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl110, reg_lcd_clk_div_num, div_num - 1);
|
||||||
if (div_num >= LCD_LL_CLK_FRAC_DIV_N_MAX) {
|
|
||||||
div_num = 0;
|
|
||||||
}
|
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl110, reg_lcd_clk_div_num, div_num);
|
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl110, reg_lcd_clk_div_denominator, div_a);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl110, reg_lcd_clk_div_denominator, div_a);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl110, reg_lcd_clk_div_numerator, div_b);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl110, reg_lcd_clk_div_numerator, div_b);
|
||||||
}
|
}
|
||||||
@ -177,7 +173,7 @@ static inline void lcd_ll_set_pixel_clock_edge(lcd_cam_dev_t *dev, bool active_o
|
|||||||
__attribute__((always_inline))
|
__attribute__((always_inline))
|
||||||
static inline void lcd_ll_set_pixel_clock_prescale(lcd_cam_dev_t *dev, uint32_t prescale)
|
static inline void lcd_ll_set_pixel_clock_prescale(lcd_cam_dev_t *dev, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale <= LCD_LL_PCLK_DIV_MAX);
|
HAL_ASSERT(prescale > 0 && prescale <= LCD_LL_PCLK_DIV_MAX);
|
||||||
// Formula: pixel_clk = lcd_clk / (1 + clkcnt_n)
|
// Formula: pixel_clk = lcd_clk / (1 + clkcnt_n)
|
||||||
// clkcnt_n can't be zero
|
// clkcnt_n can't be zero
|
||||||
uint32_t scale = 1;
|
uint32_t scale = 1;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -161,7 +161,7 @@ static inline void lcd_ll_set_pixel_clock_edge(lcd_cam_dev_t *dev, bool active_o
|
|||||||
__attribute__((always_inline))
|
__attribute__((always_inline))
|
||||||
static inline void lcd_ll_set_pixel_clock_prescale(lcd_cam_dev_t *dev, uint32_t prescale)
|
static inline void lcd_ll_set_pixel_clock_prescale(lcd_cam_dev_t *dev, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale <= LCD_LL_PCLK_DIV_MAX);
|
HAL_ASSERT(prescale > 0 && prescale <= LCD_LL_PCLK_DIV_MAX);
|
||||||
// Formula: pixel_clk = lcd_clk / (1 + clkcnt_n)
|
// Formula: pixel_clk = lcd_clk / (1 + clkcnt_n)
|
||||||
// clkcnt_n can't be zero
|
// clkcnt_n can't be zero
|
||||||
uint32_t scale = 1;
|
uint32_t scale = 1;
|
||||||
@ -571,7 +571,7 @@ static inline void lcd_ll_set_command(lcd_cam_dev_t *dev, uint32_t data_width, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wether to enable RGB interface
|
* @brief Whether to enable RGB interface
|
||||||
*
|
*
|
||||||
* @param dev LCD register base address
|
* @param dev LCD register base address
|
||||||
* @param en True to enable RGB interface, False to disable RGB interface
|
* @param en True to enable RGB interface, False to disable RGB interface
|
||||||
@ -594,7 +594,7 @@ static inline void lcd_ll_enable_auto_next_frame(lcd_cam_dev_t *dev, bool en)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wether to output HSYNC signal in porch resion
|
* @brief Whether to output HSYNC signal in porch resion
|
||||||
*
|
*
|
||||||
* @param dev LCD register base address
|
* @param dev LCD register base address
|
||||||
* @param en True to enable, False to disable
|
* @param en True to enable, False to disable
|
||||||
@ -726,7 +726,7 @@ static inline uint32_t lcd_ll_get_interrupt_status(lcd_cam_dev_t *dev)
|
|||||||
* @brief Clear interrupt status by mask
|
* @brief Clear interrupt status by mask
|
||||||
*
|
*
|
||||||
* @param dev LCD register base address
|
* @param dev LCD register base address
|
||||||
* @param mask Interupt status mask
|
* @param mask Interrupt status mask
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline))
|
__attribute__((always_inline))
|
||||||
static inline void lcd_ll_clear_interrupt_status(lcd_cam_dev_t *dev, uint32_t mask)
|
static inline void lcd_ll_clear_interrupt_status(lcd_cam_dev_t *dev, uint32_t mask)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -34,8 +34,6 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
void lcd_hal_init(lcd_hal_context_t *hal, int id);
|
void lcd_hal_init(lcd_hal_context_t *hal, int id);
|
||||||
|
|
||||||
#define LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK (1 << 0)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief LCD PCLK clock calculation
|
* @brief LCD PCLK clock calculation
|
||||||
* @note Currently this function is only used by RGB LCD driver, I80 driver still uses a fixed clock division
|
* @note Currently this function is only used by RGB LCD driver, I80 driver still uses a fixed clock division
|
||||||
@ -43,11 +41,10 @@ void lcd_hal_init(lcd_hal_context_t *hal, int id);
|
|||||||
* @param hal LCD HAL layer context
|
* @param hal LCD HAL layer context
|
||||||
* @param src_freq_hz LCD source clock frequency in Hz
|
* @param src_freq_hz LCD source clock frequency in Hz
|
||||||
* @param expect_pclk_freq_hz Expected LCD PCLK frequency in Hz
|
* @param expect_pclk_freq_hz Expected LCD PCLK frequency in Hz
|
||||||
* @param lcd_clk_flags Extra flags to control LCD PCLK clock calculation, supported flags are prefixed with LCD_HAL_PCLK_FLAG_
|
|
||||||
* @param lcd_clk_div Returned LCD clock divider parameter
|
* @param lcd_clk_div Returned LCD clock divider parameter
|
||||||
* @return Actual LCD PCLK frequency in Hz
|
* @return Actual LCD PCLK frequency in Hz
|
||||||
*/
|
*/
|
||||||
uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, int lcd_clk_flags, hal_utils_clk_div_t* lcd_clk_div);
|
uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, hal_utils_clk_div_t* lcd_clk_div);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -13,14 +13,14 @@ void lcd_hal_init(lcd_hal_context_t *hal, int id)
|
|||||||
hal->dev = LCD_LL_GET_HW(id);
|
hal->dev = LCD_LL_GET_HW(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, int lcd_clk_flags, hal_utils_clk_div_t* lcd_clk_div)
|
uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, hal_utils_clk_div_t* lcd_clk_div)
|
||||||
{
|
{
|
||||||
|
// formula:
|
||||||
// lcd_clk = module_clock_src / (n + b / a)
|
// lcd_clk = module_clock_src / (n + b / a)
|
||||||
// pixel_clk = lcd_clk / mo
|
// pixel_clk = lcd_clk / mo
|
||||||
uint32_t mo = src_freq_hz / expect_pclk_freq_hz / LCD_LL_CLK_FRAC_DIV_N_MAX + 1;
|
|
||||||
if (mo == 1 && !(lcd_clk_flags & LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK)) {
|
// due to some unstable hardware issue, we prefer to start with mo=2 first
|
||||||
mo = 2;
|
uint32_t mo = 2;
|
||||||
}
|
|
||||||
hal_utils_clk_info_t lcd_clk_info = {
|
hal_utils_clk_info_t lcd_clk_info = {
|
||||||
.src_freq_hz = src_freq_hz,
|
.src_freq_hz = src_freq_hz,
|
||||||
.exp_freq_hz = expect_pclk_freq_hz * mo,
|
.exp_freq_hz = expect_pclk_freq_hz * mo,
|
||||||
@ -29,8 +29,15 @@ uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uin
|
|||||||
.max_fract = LCD_LL_CLK_FRAC_DIV_AB_MAX,
|
.max_fract = LCD_LL_CLK_FRAC_DIV_AB_MAX,
|
||||||
};
|
};
|
||||||
uint32_t real_freq = hal_utils_calc_clk_div_frac_fast(&lcd_clk_info, lcd_clk_div);
|
uint32_t real_freq = hal_utils_calc_clk_div_frac_fast(&lcd_clk_info, lcd_clk_div);
|
||||||
HAL_EARLY_LOGD("lcd_hal", "n=%"PRIu32",a=%"PRIu32",b=%"PRIu32",mo=%"PRIu32, lcd_clk_div->integer, lcd_clk_div->denominator, lcd_clk_div->numerator, mo);
|
|
||||||
|
|
||||||
|
if (!real_freq) {
|
||||||
|
// if mo=2 can't achieve the target frequency, try others
|
||||||
|
mo = src_freq_hz / expect_pclk_freq_hz / LCD_LL_CLK_FRAC_DIV_N_MAX + 1;
|
||||||
|
lcd_clk_info.exp_freq_hz = expect_pclk_freq_hz * mo;
|
||||||
|
real_freq = hal_utils_calc_clk_div_frac_fast(&lcd_clk_info, lcd_clk_div);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_EARLY_LOGD("lcd_hal", "n=%"PRIu32",a=%"PRIu32",b=%"PRIu32",mo=%"PRIu32, lcd_clk_div->integer, lcd_clk_div->denominator, lcd_clk_div->numerator, mo);
|
||||||
lcd_ll_set_pixel_clock_prescale(hal->dev, mo);
|
lcd_ll_set_pixel_clock_prescale(hal->dev, mo);
|
||||||
return real_freq / mo;
|
return real_freq / mo;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user