From 6edf48d2535948e9557c1f32d7ac708b116cc804 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Thu, 24 Apr 2025 13:51:49 +0800 Subject: [PATCH] feat(parlio_tx): support cs signal on esp32c5 v1.0 --- .../include/driver/parlio_tx.h | 2 + components/esp_driver_parlio/src/parlio_tx.c | 32 ++++++++- .../test_apps/parlio/main/test_parlio_tx.c | 69 +++++++++++++++++++ .../parlio_lcd/main/test_parlio_board.h | 22 ++++-- .../hal/esp32c5/include/hal/parlio_ll.h | 31 ++++++--- .../hal/esp32c6/include/hal/parlio_ll.h | 17 +++++ .../hal/esp32h2/include/hal/parlio_ll.h | 21 +++++- .../hal/esp32p4/include/hal/parlio_ll.h | 17 +++++ .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 ++ components/soc/esp32c5/include/soc/soc_caps.h | 1 + components/soc/esp32c5/parlio_periph.c | 1 + components/soc/esp32c6/parlio_periph.c | 1 + components/soc/esp32h2/parlio_periph.c | 1 + components/soc/esp32p4/parlio_periph.c | 1 + components/soc/include/soc/parlio_periph.h | 1 + .../peripherals/parlio/parlio_tx.rst | 6 +- .../peripherals/parlio/parlio_tx.rst | 6 +- .../parlio_simulate/main/Kconfig.projbuild | 1 + .../sdkconfig.defaults.esp32c5 | 19 +++-- 19 files changed, 221 insertions(+), 32 deletions(-) diff --git a/components/esp_driver_parlio/include/driver/parlio_tx.h b/components/esp_driver_parlio/include/driver/parlio_tx.h index fa7ea93cdd..867f55822d 100644 --- a/components/esp_driver_parlio/include/driver/parlio_tx.h +++ b/components/esp_driver_parlio/include/driver/parlio_tx.h @@ -30,6 +30,8 @@ typedef struct { gpio_num_t clk_out_gpio_num; /*!< GPIO number of the output clock signal, the clock is synced with TX data */ gpio_num_t valid_gpio_num; /*!< GPIO number of the valid signal, which stays high when transferring data. Note that, the valid signal will always occupy the MSB data bit */ + uint16_t valid_start_delay; /*!< The clock cycles that the valid signal becomes active before data start */ + uint16_t valid_stop_delay; /*!< The clock cycles that the valid signal keeps active after data end */ size_t trans_queue_depth; /*!< Depth of internal transaction queue */ size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */ size_t dma_burst_size; /*!< DMA burst size, in bytes */ diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index be68bc8eff..bc85ea4d0e 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -130,7 +130,7 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[i], false, false); } } - // Note: the valid signal will override TXD[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG] + if (config->valid_gpio_num >= 0) { gpio_func_sel(config->valid_gpio_num, PIN_FUNC_GPIO); @@ -138,11 +138,20 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const if (config->flags.io_loop_back) { gpio_input_enable(config->valid_gpio_num); } - +#if !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG + // Configure CS signal if supported + // Note: the default value of CS signal is low, so we need to invert the CS to keep compatible with the default value // connect the signal to the GPIO by matrix, it will also enable the output path properly + esp_rom_gpio_connect_out_signal(config->valid_gpio_num, + parlio_periph_signals.groups[group_id].tx_units[unit_id].cs_sig, + !config->flags.invert_valid_out, false); +#else + // connect the signal to the GPIO by matrix, it will also enable the output path properly + // Note: the valid signal will override TXD[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG] esp_rom_gpio_connect_out_signal(config->valid_gpio_num, parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG], config->flags.invert_valid_out, false); +#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG } if (config->clk_out_gpio_num >= 0) { gpio_func_sel(config->clk_out_gpio_num, PIN_FUNC_GPIO); @@ -295,11 +304,16 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un // data_width must be power of 2 and less than or equal to SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH ESP_RETURN_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0), ESP_ERR_INVALID_ARG, TAG, "invalid data width"); + + // No need to check data width conflict with valid signal when CS is supported +#if PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG // data_width must not conflict with the valid signal ESP_RETURN_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG), ESP_ERR_INVALID_ARG, TAG, "valid signal conflicts with data signal"); +#endif // PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG + #if SOC_PARLIO_TX_CLK_SUPPORT_GATING - // clock gating is controlled by either the MSB bit of data bus or the valid signal + // clock gating is controlled by either the MSB bit of data bus or the valid signal(or CS signal when supported) ESP_RETURN_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE), ESP_ERR_INVALID_ARG, TAG, "no gpio can control the clock gating"); #else @@ -351,13 +365,25 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un // set data width parlio_ll_tx_set_bus_width(hal->regs, data_width); unit->idle_value_mask = (1 << data_width) - 1; + // set valid delay + ESP_GOTO_ON_FALSE(parlio_ll_tx_set_valid_delay(hal->regs, config->valid_start_delay, config->valid_stop_delay), ESP_ERR_INVALID_ARG, err, TAG, "invalid valid delay"); // whether to use the valid signal +#if !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG + // the clock gating source is actual selectable, it doesn't rely on the available of valid GPIO. + // but there is no use case that valid signal is used, but clocking gating is still controlled by data. + if (config->valid_gpio_num >= 0) { + parlio_ll_tx_clock_gating_from_valid(hal->regs, true); + } else { + parlio_ll_tx_clock_gating_from_valid(hal->regs, false); + } +#else if (config->valid_gpio_num >= 0) { parlio_ll_tx_treat_msb_as_valid(hal->regs, true); unit->idle_value_mask &= ~(1 << PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG); } else { parlio_ll_tx_treat_msb_as_valid(hal->regs, false); } +#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG // set data byte packing order if (data_width < 8) { parlio_ll_tx_set_bit_pack_order(hal->regs, config->bit_pack_order); diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c index 9911088e2d..e32472f4ec 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c @@ -50,8 +50,10 @@ TEST_CASE("parallel_tx_unit_install_uninstall", "[parlio_tx]") config.input_clk_src_freq_hz = 1000000; config.valid_gpio_num = 0; +#if PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG // failed because of data line conflict with valid signal TEST_ESP_ERR(ESP_ERR_INVALID_ARG, parlio_new_tx_unit(&config, &units[0])); +#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG config.data_width = 4; TEST_ESP_OK(parlio_new_tx_unit(&config, &units[0])); @@ -288,6 +290,73 @@ TEST_CASE("parallel_tx_clock_gating", "[paralio_tx]") TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); TEST_ESP_OK(gpio_reset_pin(TEST_CLK_GPIO)); } + +#if !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG +TEST_CASE("parallel_tx_clock_gating_and_msb_coexist", "[paralio_tx]") +{ + printf("init a gpio to read parlio_tx clk output\r\n"); + gpio_config_t test_gpio_conf = { + .mode = GPIO_MODE_INPUT, + .pin_bit_mask = BIT64(TEST_CLK_GPIO) | BIT64(TEST_DATA7_GPIO), + }; + TEST_ESP_OK(gpio_config(&test_gpio_conf)); + + printf("install parlio tx unit\r\n"); + parlio_tx_unit_handle_t tx_unit = NULL; + parlio_tx_unit_config_t config = { + .clk_src = PARLIO_CLK_SRC_DEFAULT, + .data_width = 8, + .clk_in_gpio_num = -1, // use internal clock source + .valid_gpio_num = TEST_VALID_GPIO, // generate the valid signal + .clk_out_gpio_num = TEST_CLK_GPIO, + .data_gpio_nums = { + TEST_DATA0_GPIO, + TEST_DATA1_GPIO, + TEST_DATA2_GPIO, + TEST_DATA3_GPIO, + TEST_DATA4_GPIO, + TEST_DATA5_GPIO, + TEST_DATA6_GPIO, + TEST_DATA7_GPIO, + }, + .output_clk_freq_hz = 1 * 1000 * 1000, + .trans_queue_depth = 4, + .max_transfer_size = 256, + .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB, + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .valid_start_delay = 5, + .valid_stop_delay = 5, + .flags.clk_gate_en = true, // enable clock gating, controlled by the CS signal + }; + TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit)); + TEST_ESP_OK(parlio_tx_unit_enable(tx_unit)); + + printf("send packets and see if the clock is gated when there's no transaction on line\r\n"); + parlio_transmit_config_t transmit_config = { + // set the idle value to 0x80, so that the MSB is high when there's no transaction + .idle_value = 0x80, + }; + uint32_t size = 256; + __attribute__((aligned(64))) uint8_t payload[size]; + for (int i = 0; i < size; i++) { + payload[i] = i; + } + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, size * sizeof(uint8_t) * 8, &transmit_config)); + TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1)); + // check if the level on the clock line is low + TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO)); + TEST_ASSERT_EQUAL(1, gpio_get_level(TEST_DATA7_GPIO)); + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, size * sizeof(uint8_t) * 8, &transmit_config)); + TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1)); + TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO)); + TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO)); + TEST_ASSERT_EQUAL(1, gpio_get_level(TEST_DATA7_GPIO)); + + TEST_ESP_OK(parlio_tx_unit_disable(tx_unit)); + TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); + TEST_ESP_OK(gpio_reset_pin(TEST_CLK_GPIO)); +} +#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING #if SOC_PSRAM_DMA_CAPABLE diff --git a/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h b/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h index 5942434147..72147b3a75 100644 --- a/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h +++ b/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,12 +34,20 @@ extern "C" { #define TEST_LCD_PCLK_GPIO (5) #define TEST_LCD_DATA0_GPIO (4) #elif CONFIG_IDF_TARGET_ESP32C5 -#define TEST_LCD_BK_LIGHT_GPIO (1) -#define TEST_LCD_RST_GPIO (7) -#define TEST_LCD_CS_GPIO (27) -#define TEST_LCD_DC_GPIO (6) -#define TEST_LCD_PCLK_GPIO (25) -#define TEST_LCD_DATA0_GPIO (26) +#define TEST_LCD_BK_LIGHT_GPIO (5) +#define TEST_LCD_RST_GPIO (2) +#define TEST_LCD_CS_GPIO (0) +#define TEST_LCD_DC_GPIO (3) +#define TEST_LCD_PCLK_GPIO (1) +#define TEST_LCD_DATA0_GPIO (4) +#define TEST_LCD_DATA1_GPIO (9) +#define TEST_LCD_DATA2_GPIO (28) +#define TEST_LCD_DATA3_GPIO (24) +#define TEST_LCD_DATA4_GPIO (14) +#define TEST_LCD_DATA5_GPIO (23) +#define TEST_LCD_DATA6_GPIO (13) +#define TEST_LCD_DATA7_GPIO (27) + #endif #define TEST_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000) diff --git a/components/hal/esp32c5/include/hal/parlio_ll.h b/components/hal/esp32c5/include/hal/parlio_ll.h index c800e952ee..26f714c693 100644 --- a/components/hal/esp32c5/include/hal/parlio_ll.h +++ b/components/hal/esp32c5/include/hal/parlio_ll.h @@ -32,11 +32,8 @@ #define PARLIO_LL_EVENT_TX_MASK (PARLIO_LL_EVENT_TX_FIFO_EMPTY | PARLIO_LL_EVENT_TX_EOF) #define PARLIO_LL_EVENT_RX_MASK (PARLIO_LL_EVENT_RX_FIFO_FULL) -#define PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG 7 // TXD[7] can be used a valid signal #define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 7 // TXD[7] can be used as clock gate signal - -#define PARLIO_LL_CLK_DIVIDER_MAX (0) // Not support fractional divider - +#define PARLIO_LL_TX_VALID_MAX_DELAY 32767 #ifdef __cplusplus extern "C" { #endif @@ -526,18 +523,34 @@ static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en) } /** - * @brief Whether to treat the MSB of TXD as the valid signal - * - * @note If enabled, TXD[7] will work as valid signal, which stay high during data transmission. + * @brief Set the clock gating from the valid signal * * @param dev Parallel IO register base address - * @param en True to enable, False to disable + * @param en If set to true, the clock is gated by the valid signal, otherwise it is gated by the MSB of the data line. */ -static inline void parlio_ll_tx_treat_msb_as_valid(parl_io_dev_t *dev, bool en) +static inline void parlio_ll_tx_clock_gating_from_valid(parl_io_dev_t *dev, bool en) { dev->tx_genrl_cfg.tx_valid_output_en = en; } +/** + * @brief Set TX valid signal delay + * + * @param dev Parallel IO register base address + * @param start_delay Number of clock cycles to delay + * @param stop_delay Number of clock cycles to delay + * @return true: success, false: valid delay is not supported + */ +static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay) +{ + if (start_delay > PARLIO_LL_TX_VALID_MAX_DELAY || stop_delay > PARLIO_LL_TX_VALID_MAX_DELAY) { + return false; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_cs_cfg, tx_cs_start_delay, start_delay); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_cs_cfg, tx_cs_stop_delay, stop_delay); + return true; +} + /** * @brief Set the sample clock edge * diff --git a/components/hal/esp32c6/include/hal/parlio_ll.h b/components/hal/esp32c6/include/hal/parlio_ll.h index 66a0f5e5b0..f53724e62f 100644 --- a/components/hal/esp32c6/include/hal/parlio_ll.h +++ b/components/hal/esp32c6/include/hal/parlio_ll.h @@ -509,6 +509,23 @@ static inline void parlio_ll_tx_treat_msb_as_valid(parl_io_dev_t *dev, bool en) dev->tx_cfg0.tx_hw_valid_en = en; } +/** + * @brief Set TX valid signal delay + * + * @param dev Parallel IO register base address + * @param start_delay Number of clock cycles to delay + * @param stop_delay Number of clock cycles to delay + * @return true: success, false: valid delay is not supported + */ +static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay) +{ + (void)dev; + if (start_delay == 0 && stop_delay == 0) { + return true; + } + return false; +} + /** * @brief Set the sample clock edge * diff --git a/components/hal/esp32h2/include/hal/parlio_ll.h b/components/hal/esp32h2/include/hal/parlio_ll.h index 42172b4909..e8964cc00c 100644 --- a/components/hal/esp32h2/include/hal/parlio_ll.h +++ b/components/hal/esp32h2/include/hal/parlio_ll.h @@ -37,8 +37,6 @@ #define PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG 7 // TXD[7] can be used a valid signal #define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 7 // TXD[7] can be used as clock gate signal -#define PARLIO_LL_CLK_DIVIDER_MAX (0) // Not support fractional divider - #ifdef __cplusplus extern "C" { #endif @@ -534,7 +532,7 @@ static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en) /** * @brief Whether to treat the MSB of TXD as the valid signal * - * @note If enabled, TXD[15] will work as valid signal, which stay high during data transmission. + * @note If enabled, TXD[7] will work as valid signal, which stay high during data transmission. * * @param dev Parallel IO register base address * @param en True to enable, False to disable @@ -544,6 +542,23 @@ static inline void parlio_ll_tx_treat_msb_as_valid(parl_io_dev_t *dev, bool en) dev->tx_genrl_cfg.tx_valid_output_en = en; } +/** + * @brief Set TX valid signal delay + * + * @param dev Parallel IO register base address + * @param start_delay Number of clock cycles to delay + * @param stop_delay Number of clock cycles to delay + * @return true: success, false: valid delay is not supported + */ +static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay) +{ + (void)dev; + if (start_delay == 0 && stop_delay == 0) { + return true; + } + return false; +} + /** * @brief Set the sample clock edge * diff --git a/components/hal/esp32p4/include/hal/parlio_ll.h b/components/hal/esp32p4/include/hal/parlio_ll.h index 016ca79b36..b7c323c9bc 100644 --- a/components/hal/esp32p4/include/hal/parlio_ll.h +++ b/components/hal/esp32p4/include/hal/parlio_ll.h @@ -523,6 +523,23 @@ static inline void parlio_ll_tx_set_trans_bit_len(parl_io_dev_t *dev, uint32_t b dev->tx_data_cfg.tx_bitlen = bitlen; } +/** + * @brief Set TX valid signal delay + * + * @param dev Parallel IO register base address + * @param start_delay Number of clock cycles to delay + * @param stop_delay Number of clock cycles to delay + * @return true: success, false: valid delay is not supported + */ +static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay) +{ + (void)dev; + if (start_delay == 0 && stop_delay == 0) { + return true; + } + return false; +} + /** * @brief Check if tx size can be determined by DMA * diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index cb1e80430a..052ad8d1d7 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -991,6 +991,10 @@ config SOC_PARLIO_SUPPORT_SPI_LCD bool default y +config SOC_PARLIO_SUPPORT_I80_LCD + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 4cc70e312b..f0268d7f38 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -389,6 +389,7 @@ #define SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION 1 /*!< Support loop transmission */ #define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ #define SOC_PARLIO_SUPPORT_SPI_LCD 1 /*!< Support to drive SPI interfaced LCD */ +#define SOC_PARLIO_SUPPORT_I80_LCD 1 /*!< Support to drive I80 interfaced LCD */ /*--------------------------- MPI CAPS ---------------------------------------*/ #define SOC_MPI_MEM_BLOCKS_NUM (4) diff --git a/components/soc/esp32c5/parlio_periph.c b/components/soc/esp32c5/parlio_periph.c index 3d323084ba..06fba084db 100644 --- a/components/soc/esp32c5/parlio_periph.c +++ b/components/soc/esp32c5/parlio_periph.c @@ -27,6 +27,7 @@ const parlio_signal_conn_t parlio_periph_signals = { }, .clk_out_sig = PARL_TX_CLK_OUT_IDX, .clk_in_sig = PARL_TX_CLK_IN_IDX, + .cs_sig = PARL_TX_CS_O_IDX, } }, .rx_units = { diff --git a/components/soc/esp32c6/parlio_periph.c b/components/soc/esp32c6/parlio_periph.c index 202b44a289..08c85e516c 100644 --- a/components/soc/esp32c6/parlio_periph.c +++ b/components/soc/esp32c6/parlio_periph.c @@ -35,6 +35,7 @@ const parlio_signal_conn_t parlio_periph_signals = { }, .clk_out_sig = PARL_TX_CLK_OUT_IDX, .clk_in_sig = PARL_TX_CLK_IN_IDX, + .cs_sig = -1, } }, .rx_units = { diff --git a/components/soc/esp32h2/parlio_periph.c b/components/soc/esp32h2/parlio_periph.c index 3d323084ba..7a0fe71762 100644 --- a/components/soc/esp32h2/parlio_periph.c +++ b/components/soc/esp32h2/parlio_periph.c @@ -27,6 +27,7 @@ const parlio_signal_conn_t parlio_periph_signals = { }, .clk_out_sig = PARL_TX_CLK_OUT_IDX, .clk_in_sig = PARL_TX_CLK_IN_IDX, + .cs_sig = -1, } }, .rx_units = { diff --git a/components/soc/esp32p4/parlio_periph.c b/components/soc/esp32p4/parlio_periph.c index b5f823986a..fe3f99a739 100644 --- a/components/soc/esp32p4/parlio_periph.c +++ b/components/soc/esp32p4/parlio_periph.c @@ -35,6 +35,7 @@ const parlio_signal_conn_t parlio_periph_signals = { }, .clk_out_sig = PARLIO_TX_CLK_PAD_OUT_IDX, .clk_in_sig = PARLIO_TX_CLK_PAD_IN_IDX, + .cs_sig = -1, } }, .rx_units = { diff --git a/components/soc/include/soc/parlio_periph.h b/components/soc/include/soc/parlio_periph.h index 3bb4de72b0..5e567f5cc4 100644 --- a/components/soc/include/soc/parlio_periph.h +++ b/components/soc/include/soc/parlio_periph.h @@ -29,6 +29,7 @@ typedef struct { const int data_sigs[SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH]; const int clk_out_sig; const int clk_in_sig; + const int cs_sig; } tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; struct { const int data_sigs[SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH]; diff --git a/docs/en/api-reference/peripherals/parlio/parlio_tx.rst b/docs/en/api-reference/peripherals/parlio/parlio_tx.rst index 37a197111e..c0198b43d8 100644 --- a/docs/en/api-reference/peripherals/parlio/parlio_tx.rst +++ b/docs/en/api-reference/peripherals/parlio/parlio_tx.rst @@ -68,7 +68,9 @@ The following are the configuration parameters of the :cpp:type:`parlio_tx_unit_ - :cpp:member:`parlio_tx_unit_config_t::clk_out_gpio_num` The GPIO number for the output clock signal. - :cpp:member:`parlio_tx_unit_config_t::data_width` The data bus width of the TX unit, must be a power of 2 and not greater than {IDF_TARGET_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH}. - :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` The GPIO numbers for TX data, unused GPIOs should be set to -1. - - :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` The GPIO number for the valid signal, set to -1 if not used. The valid signal stays high level when the TX unit is transmitting data. Note that enabling the valid signal will occupy the MSB data bit, reducing the maximum data width of the TX unit by 1 bit. In this case, the maximum configurable data bus width is :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2. + - :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` The GPIO number for the valid signal, set to -1 if not used. The valid signal stays high level when the TX unit is transmitting data. Note that enabling the valid signal in some specific chips will occupy the MSB data bit, reducing the maximum data width of the TX unit by 1 bit. In this case, the maximum configurable data bus width is :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2. Please check the return value of :cpp:func:`parlio_new_tx_unit`. + - :cpp:member:`parlio_tx_unit_config_t::valid_start_delay` The number of clock cycles the valid signal will stay high level before the TX unit starts transmitting data. This configuration option depends on specific hardware features, and if enabled on unsupported chips or configured with invalid values, you will see an error message like ``invalid valid delay``. + - :cpp:member:`parlio_tx_unit_config_t::valid_stop_delay` The number of clock cycles the valid signal will stay high level after the TX unit finishes transmitting data. This configuration option depends on specific hardware features, and if enabled on unsupported chips or configured with invalid values, you will see an error message like ``invalid valid delay``. - :cpp:member:`parlio_tx_unit_config_t::trans_queue_depth` The depth of the internal transaction queue. The deeper the queue, the more transactions can be prepared in the pending queue. - :cpp:member:`parlio_tx_unit_config_t::max_transfer_size` The maximum transfer size per transaction (in bytes). - :cpp:member:`parlio_tx_unit_config_t::dma_burst_size` The DMA burst transfer size (in bytes), must be a power of 2. @@ -76,7 +78,7 @@ The following are the configuration parameters of the :cpp:type:`parlio_tx_unit_ - :cpp:member:`parlio_tx_unit_config_t::bit_pack_order` Sets the order of data bits within a byte (valid only when data width < 8). - :cpp:member:`parlio_tx_unit_config_t::flags` Usually used to fine-tune some behaviors of the driver, including the following options - :cpp:member:`parlio_tx_unit_config_t::flags::invert_valid_out` Determines whether to invert the valid signal before sending it to the GPIO pin. - :SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` Enables TX unit clock gating, the output clock will be controlled by the MSB bit of the data bus, i.e., by writing a high level to :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] to enable clock output, and a low level to disable it. Note that if both the valid signal output and clock gating are enabled, clock gating can come from the valid signal occupying the MSB data bit, in which case the data bus width can be as long as it is not greater than :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2. Otherwise, the data bus width needs to be configured as :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`. + :SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` Enables TX unit clock gating, the output clock will be controlled by the MSB bit of the data bus, i.e., by writing a high level to :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] to enable clock output, and a low level to disable it. In this case, the data bus width needs to be configured as :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`. Note that if both the valid signal output and clock gating are enabled, clock gating can come from the valid signal. there is no limit on the data bus width. (Note that in some chips, the valid signal occupies the MSB data bit, so the maximum configurable data bus width is :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2) :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - :cpp:member:`parlio_tx_unit_config_t::flags::allow_pd` Configures whether the driver allows the system to turn off the peripheral power in sleep mode. Before entering sleep, the system will back up the TX unit register context, and these contexts will be restored when the system exits sleep mode. Turning off the peripheral can save more power, but at the cost of consuming more memory to save the register context. You need to balance power consumption and memory usage. This configuration option depends on specific hardware features, and if enabled on unsupported chips, you will see an error message like ``register back up is not supported``. .. note:: diff --git a/docs/zh_CN/api-reference/peripherals/parlio/parlio_tx.rst b/docs/zh_CN/api-reference/peripherals/parlio/parlio_tx.rst index 48b0f68f33..96a742445d 100644 --- a/docs/zh_CN/api-reference/peripherals/parlio/parlio_tx.rst +++ b/docs/zh_CN/api-reference/peripherals/parlio/parlio_tx.rst @@ -68,7 +68,9 @@ - :cpp:member:`parlio_tx_unit_config_t::clk_out_gpio_num` 输出时钟信号的 GPIO 编号。 - :cpp:member:`parlio_tx_unit_config_t::data_width` TX 单元数据总线宽度,必须为 2 的幂次方,且不能大于 {IDF_TARGET_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH}。 - :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` TX 数据 GPIO 编号,未使用的 GPIO 设置为 -1。 - - :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` 有效信号的 GPIO 编号,未使用则设置为 -1。有效信号会在 TX 传输数据时保持高电平。注意,启用有效信号会占用 MSB 数据位,导致 TX 单元的最大数据宽度减少 1 位,此时数据总线宽度的最大可配置为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2。 + - :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` 有效信号的 GPIO 编号,未使用则设置为 -1。有效信号会在 TX 传输数据时保持高电平。注意,在部分芯片上启用有效信号会占用 MSB 数据位,导致 TX 单元的最大数据宽度减少 1 位,此时数据总线宽度的最大可配置为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2, 因此请检查 :cpp:func:`parlio_new_tx_unit` 的返回值。 + - :cpp:member:`parlio_tx_unit_config_t::valid_start_delay` 有效信号将在数据发送之前保持“有效”状态的时钟周期。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,或配置了无效的值,你将看到类似 ``invalid valid delay`` 的错误消息。 + - :cpp:member:`parlio_tx_unit_config_t::valid_stop_delay` 有效信号将在数据发送完成之后保持“有效”状态的时钟周期。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,或配置了无效的值,你将看到类似 ``invalid valid delay`` 的错误消息。 - :cpp:member:`parlio_tx_unit_config_t::trans_queue_depth` 内部事务队列深度。队列越深,在待处理队列中可以准备的事务越多。 - :cpp:member:`parlio_tx_unit_config_t::max_transfer_size` 一次传输的最大传输大小(以字节为单位)。 - :cpp:member:`parlio_tx_unit_config_t::dma_burst_size` DMA 突发传输大小(以字节为单位),必须为 2 的幂次方。 @@ -76,7 +78,7 @@ - :cpp:member:`parlio_tx_unit_config_t::bit_pack_order` 设置字节内数据位出现的顺序(仅当数据宽度 < 8 时有效)。 - :cpp:member:`parlio_tx_unit_config_t::flags` 通常用来微调驱动的一些行为,包括以下选项 - :cpp:member:`parlio_tx_unit_config_t::flags::invert_valid_out` 决定是否在将 TX 单元有效信号发送到 GPIO 管脚前反转信号。 - :SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` 启用 TX 单元时钟门控,输出时钟将由数据总线的 MSB 位控制,即通过向 :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] 写入高电平使能时钟输出,低电平禁用。注意,若有效信号输出和时钟门控同时启用,时钟门控可以来自占用 MSB 数据位的有效信号,此时数据总线宽只要不大于:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2 即可,否则需要配置数据总线宽度为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`。 + :SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` 启用 TX 单元时钟门控,输出时钟默认由数据总线的 MSB 位控制,即通过向 :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] 写入高电平使能时钟输出,低电平禁用,此时需要配置数据总线宽度为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`。注意,若有效信号输出和时钟门控同时启用,时钟门控则来自有效信号,对数据总线宽度没有额外要求(部分芯片上有效信号会占用 MSB 数据位,总线宽度的最大可配置为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2)。 :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - :cpp:member:`parlio_tx_unit_config_t::flags::allow_pd` 配置驱动程序是否允许系统在睡眠模式下关闭外设电源。在进入睡眠之前,系统将备份 TX 单元寄存器上下文,当系统退出睡眠模式时,这些上下文将被恢复。关闭外设可以节省更多功耗,但代价是消耗更多内存来保存寄存器上下文。你需要在功耗和内存消耗之间做权衡。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,你将看到类似 ``register back up is not supported`` 的错误消息。 .. note:: diff --git a/examples/peripherals/lcd/parlio_simulate/main/Kconfig.projbuild b/examples/peripherals/lcd/parlio_simulate/main/Kconfig.projbuild index e1da84169c..93de272aa6 100644 --- a/examples/peripherals/lcd/parlio_simulate/main/Kconfig.projbuild +++ b/examples/peripherals/lcd/parlio_simulate/main/Kconfig.projbuild @@ -9,6 +9,7 @@ menu "Example Configuration" choice EXAMPLE_LCD_PARLIO_SIMULATE_INTERFACE prompt "LCD interface" + default EXAMPLE_LCD_PARLIO_SIMULATE_I80 if SOC_PARLIO_SUPPORT_I80_LCD default EXAMPLE_LCD_PARLIO_SIMULATE_SPI help Select LCD controller model diff --git a/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32c5 b/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32c5 index 7ff95b8d51..492c21f549 100644 --- a/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32c5 +++ b/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32c5 @@ -4,9 +4,16 @@ CONFIG_SPIRAM_SPEED_80M=y # the Frame Buffer is allocated from the PSRAM and fetched by EDMA CONFIG_SPIRAM_XIP_FROM_PSRAM=y -CONFIG_EXAMPLE_PIN_NUM_BK_LIGHT=1 -CONFIG_EXAMPLE_PIN_NUM_RST=7 -CONFIG_EXAMPLE_PIN_NUM_PCLK=25 -CONFIG_EXAMPLE_PIN_NUM_CS=27 -CONFIG_EXAMPLE_PIN_NUM_DC=6 -CONFIG_EXAMPLE_PIN_NUM_DATA0=26 +CONFIG_EXAMPLE_PIN_NUM_BK_LIGHT=5 +CONFIG_EXAMPLE_PIN_NUM_RST=2 +CONFIG_EXAMPLE_PIN_NUM_PCLK=1 +CONFIG_EXAMPLE_PIN_NUM_CS=0 +CONFIG_EXAMPLE_PIN_NUM_DC=3 +CONFIG_EXAMPLE_PIN_NUM_DATA0=4 +CONFIG_EXAMPLE_PIN_NUM_DATA1=9 +CONFIG_EXAMPLE_PIN_NUM_DATA2=28 +CONFIG_EXAMPLE_PIN_NUM_DATA3=24 +CONFIG_EXAMPLE_PIN_NUM_DATA4=14 +CONFIG_EXAMPLE_PIN_NUM_DATA5=23 +CONFIG_EXAMPLE_PIN_NUM_DATA6=13 +CONFIG_EXAMPLE_PIN_NUM_DATA7=27