feat(dsi): add timeout check for lp cmd rx

This commit is contained in:
Chen Jichang
2026-07-07 11:10:57 +08:00
parent 0158ad3d99
commit 7133a54828
7 changed files with 47 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -665,6 +665,17 @@ static inline bool mipi_dsi_host_ll_gen_is_read_cmd_busy(dsi_host_dev_t *dev)
return dev->cmd_pkt_status.gen_rd_cmd_busy;
}
/**
* @brief Has the low-power reception timed out?
*
* @param dev Pointer to the DSI Host controller register base address
* @return True if low-power reception timed out, False otherwise
*/
static inline bool mipi_dsi_host_ll_is_lp_rx_timeout(dsi_host_dev_t *dev)
{
return dev->int_st1.to_lp_rx;
}
/**
* @brief Is the read payload FIFO of the generic interface full?
*

View File

@@ -104,8 +104,9 @@ void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_
* @param command_bytes Number of bytes of the command
* @param ret_param Pointer to the buffer to store the returned parameters
* @param param_buf_size Size of the buffer to store the returned parameters
* @return True if the command response is received, False if LP RX times out
*/
void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc,
bool mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc,
uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size);
/**
@@ -140,8 +141,9 @@ void mipi_dsi_hal_host_gen_write_short_packet(mipi_dsi_hal_context_t *hal, uint8
* @param header_data Data to be filled into the DSI packet header
* @param ret_buffer Pointer to the buffer to store the returned data
* @param buffer_size Size of the buffer to store the returned data
* @return True if the packet response is received, False if LP RX times out
*/
void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc,
bool mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc,
mipi_dsi_data_type_t dt, uint16_t header_data, void *ret_buffer, uint16_t buffer_size);
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,6 +16,18 @@
HAL_LOG_ATTR_TAG(TAG, "dsi_hal");
static inline bool mipi_dsi_hal_host_wait_timeout(mipi_dsi_hal_context_t *hal,
bool (*condition)(mipi_dsi_host_soc_handle_t host),
bool (*timeout)(mipi_dsi_host_soc_handle_t host))
{
while (condition(hal->host)) {
if (timeout(hal->host)) {
return true;
}
}
return timeout(hal->host);
}
void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config)
{
hal->host = MIPI_DSI_LL_GET_HOST(config->bus_id);
@@ -203,7 +215,7 @@ void mipi_dsi_hal_host_gen_write_long_packet(mipi_dsi_hal_context_t *hal, uint8_
mipi_dsi_host_ll_gen_set_packet_header(hal->host, vc, dt, wc_msb, wc_lsb);
}
void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, uint16_t header_data, void *ret_buffer, uint16_t buffer_size)
bool mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, uint16_t header_data, void *ret_buffer, uint16_t buffer_size)
{
uint8_t *receive_buffer = (uint8_t *)ret_buffer;
// set the maximum returned data size, it should equal to the parameter size of the read command
@@ -215,9 +227,13 @@ void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_
// listen to the same virtual channel as the one sent to
mipi_dsi_host_ll_gen_set_rx_vcid(hal->host, vc);
mipi_dsi_hal_host_gen_write_short_packet(hal, vc, dt, header_data);
while (mipi_dsi_host_ll_gen_is_read_cmd_busy(hal->host));
if (mipi_dsi_hal_host_wait_timeout(hal, mipi_dsi_host_ll_gen_is_read_cmd_busy, mipi_dsi_host_ll_is_lp_rx_timeout)) {
return false;
}
// wait data to come into the fifo
while (mipi_dsi_host_ll_gen_is_read_fifo_empty(hal->host));
if (mipi_dsi_hal_host_wait_timeout(hal, mipi_dsi_host_ll_gen_is_read_fifo_empty, mipi_dsi_host_ll_is_lp_rx_timeout)) {
return false;
}
uint32_t temp = 0;
uint32_t counter = 0;
while (!mipi_dsi_host_ll_gen_is_read_fifo_empty(hal->host)) {
@@ -229,12 +245,13 @@ void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_
}
}
}
return true;
}
void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size)
bool mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size)
{
uint16_t header_data = command & ((1U << (8 * command_bytes)) - 1);
mipi_dsi_hal_host_gen_read_short_packet(hal, vc, MIPI_DSI_DT_DCS_READ_0, header_data, ret_param, param_buf_size);
return mipi_dsi_hal_host_gen_read_short_packet(hal, vc, MIPI_DSI_DT_DCS_READ_0, header_data, ret_param, param_buf_size);
}
void mipi_dsi_hal_host_dpi_set_horizontal_timing(mipi_dsi_hal_context_t *hal, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp)

View File

@@ -11,6 +11,7 @@
#define MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ 10
// TxClkEsc frequency must be configured between 2 and 20 MHz
#define MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ 18
#define MIPI_DSI_DEFAULT_HOST_LP_RX_TIMEOUT_COUNT 0x7FFF
esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lcd_dsi_bus_handle_t *ret_bus)
{
@@ -122,9 +123,11 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc
mipi_dsi_host_ll_set_timeout_clock_division(hal->host, (uint32_t)roundf(bus_config->lane_bit_rate_mbps / 8.0f / MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ));
// Set the divider to get the TX Escape clock, clock source is the high-speed byte clock
mipi_dsi_host_ll_set_escape_clock_division(hal->host, (uint32_t)roundf(bus_config->lane_bit_rate_mbps / 8.0f / MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ));
// set the timeout intervals to zero, means to disable the timeout mechanism
mipi_dsi_host_ll_set_timeout_count(hal->host, 0, 0, 0, 0, 0, 0, 0);
// DSI host will wait indefinitely for a read response from the DSI device
// Enable host timeout detection for command mode transactions.
mipi_dsi_host_ll_set_timeout_count(hal->host, 0,
MIPI_DSI_DEFAULT_HOST_LP_RX_TIMEOUT_COUNT,
0, 0, 0, 0, 0);
// Set the maximum time required to perform a read command, measured in lane byte clock cycles.
mipi_dsi_phy_ll_set_max_read_time(hal->host, 6000);
// set how long the DSI host will wait before sending the next transmission
mipi_dsi_phy_ll_set_stop_wait_time(hal->host, 0x3F);

View File

@@ -83,7 +83,8 @@ static esp_err_t panel_io_dbi_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void
esp_lcd_dsi_bus_handle_t bus = dbi_io->bus;
mipi_dsi_hal_context_t *hal = &bus->hal;
mipi_dsi_hal_host_gen_read_dcs_command(hal, dbi_io->virtual_channel, lcd_cmd, dbi_io->lcd_cmd_bits / 8, param, param_size);
ESP_RETURN_ON_FALSE(mipi_dsi_hal_host_gen_read_dcs_command(hal, dbi_io->virtual_channel, lcd_cmd, dbi_io->lcd_cmd_bits / 8, param, param_size),
ESP_ERR_TIMEOUT, TAG, "DSI read command timeout");
return ESP_OK;
}

View File

@@ -29,10 +29,6 @@ components/esp_lcd/test_apps/mipi_dsi_lcd:
- soc
disable:
- if: SOC_MIPI_DSI_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners, DSI can't work without an LCD connected
components/esp_lcd/test_apps/parlio_lcd:
depends_components:

View File

@@ -16,7 +16,6 @@ from pytest_embedded_idf.utils import soc_filtered_targets
indirect=True,
)
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='no runner')
def test_dsi_lcd(dut: Dut) -> None:
dut.run_all_single_board_cases()
@@ -34,7 +33,6 @@ def test_dsi_lcd(dut: Dut) -> None:
soc_filtered_targets('SOC_MIPI_DSI_SUPPORTED == 1 and SOC_FLASH_ENC_SUPPORTED == 1'),
indirect=['target'],
)
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='no runner')
def test_dsi_lcd_with_flash_encryption(dut: Dut) -> None:
dut.run_all_single_board_cases()
@@ -49,6 +47,5 @@ def test_dsi_lcd_with_flash_encryption(dut: Dut) -> None:
indirect=True,
)
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='no runner')
def test_dsi_lcd_esp32p4_rev1(dut: Dut) -> None:
dut.run_all_single_board_cases()