From 1ff5e64acd75989587ce78b389275f461061819c Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Thu, 19 Dec 2024 14:50:36 +0800 Subject: [PATCH 1/4] fix(parlio_tx): add clock and fifo reset in disable function --- components/esp_driver_parlio/src/parlio_tx.c | 15 +++++++++++++-- .../test_apps/parlio/main/test_parlio_tx.c | 12 ++++++------ components/hal/esp32c6/include/hal/parlio_ll.h | 11 +++++++---- components/hal/esp32h2/include/hal/parlio_ll.h | 5 ++++- components/hal/esp32p4/include/hal/parlio_ll.h | 5 ++++- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index 5e9862e32f..916fe9365a 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -432,11 +432,13 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio } }; gdma_link_mount_buffers(tx_unit->dma_link, 0, &mount_config, 1, NULL); - parlio_ll_tx_reset_fifo(hal->regs); PARLIO_RCC_ATOMIC() { parlio_ll_tx_reset_clock(hal->regs); } + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_enable_clock(hal->regs, false); + } parlio_ll_tx_set_idle_data_value(hal->regs, t->idle_value); parlio_ll_tx_set_trans_bit_len(hal->regs, t->payload_bits); @@ -506,9 +508,18 @@ esp_err_t parlio_tx_unit_disable(parlio_tx_unit_handle_t tx_unit) } ESP_RETURN_ON_FALSE(valid_state, ESP_ERR_INVALID_STATE, TAG, "unit can't be disabled in state %d", expected_fsm); - // stop the TX engine + // stop the DMA engine, reset the peripheral state parlio_hal_context_t *hal = &tx_unit->base.group->hal; + // to stop the undergoing transaction, disable and reset clock + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_enable_clock(hal->regs, false); + } + PARLIO_RCC_ATOMIC() { + parlio_ll_tx_reset_clock(hal->regs); + } gdma_stop(tx_unit->dma_chan); + gdma_reset(tx_unit->dma_chan); + parlio_ll_tx_reset_fifo(hal->regs); parlio_ll_tx_start(hal->regs, false); parlio_ll_enable_interrupt(hal->regs, PARLIO_LL_EVENT_TX_EOF, false); 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 a1fd71d888..cb24b7a557 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 @@ -143,7 +143,7 @@ TEST_CASE("parallel_tx_unit_enable_disable", "[parlio_tx]") TEST_DATA7_GPIO, }, .output_clk_freq_hz = 1 * 1000 * 1000, - .trans_queue_depth = 64, + .trans_queue_depth = 4, .max_transfer_size = 256, .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB, .sample_edge = PARLIO_SAMPLE_EDGE_POS, @@ -155,19 +155,19 @@ TEST_CASE("parallel_tx_unit_enable_disable", "[parlio_tx]") parlio_transmit_config_t transmit_config = { .idle_value = 0x00, }; - __attribute__((aligned(64))) uint8_t payload[128] = {0}; - for (int i = 0; i < 128; i++) { + __attribute__((aligned(64))) uint8_t payload[256] = {0}; + for (int i = 0; i < 256; i++) { payload[i] = i; } - for (int j = 0; j < 64; j++) { - TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 128 * sizeof(uint8_t) * 8, &transmit_config)); + for (int j = 0; j < 3; j++) { + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 256 * sizeof(uint8_t) * 8, &transmit_config)); } printf("disable the transaction in the middle\r\n"); while (parlio_tx_unit_disable(tx_unit) != ESP_OK) { esp_rom_delay_us(1000); } - vTaskDelay(pdMS_TO_TICKS(100)); + vTaskDelay(pdMS_TO_TICKS(10)); printf("resume the transaction and pending packets should continue\r\n"); TEST_ESP_OK(parlio_tx_unit_enable(tx_unit)); diff --git a/components/hal/esp32c6/include/hal/parlio_ll.h b/components/hal/esp32c6/include/hal/parlio_ll.h index 78d126a33f..3eb277d14f 100644 --- a/components/hal/esp32c6/include/hal/parlio_ll.h +++ b/components/hal/esp32c6/include/hal/parlio_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -30,7 +30,7 @@ #define PARLIO_LL_EVENT_TX_FIFO_EMPTY (1 << 0) #define PARLIO_LL_EVENT_RX_FIFO_FULL (1 << 1) #define PARLIO_LL_EVENT_TX_EOF (1 << 2) -#define PARLIO_LL_EVENT_TX_MASK (PARLIO_LL_EVENT_TX_FIFO_EMPTY | PARLIO_LL_EVENT_TX_EOF) +#define PARLIO_LL_EVENT_TX_MASK (PARLIO_LL_EVENT_TX_EOF) // On C6, TX FIFO EMPTY event always comes with TX EOF event. We don't enable it #define PARLIO_LL_EVENT_RX_MASK (PARLIO_LL_EVENT_RX_FIFO_FULL) #define PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG 15 // TXD[15] can be used a valid signal @@ -450,7 +450,7 @@ static inline void parlio_ll_tx_set_trans_bit_len(parl_io_dev_t *dev, uint32_t b } /** - * @brief Wether to enable the TX clock gating + * @brief Whether to enable the TX clock gating * * @note The TXD[7] will be taken as the gating enable signal * @@ -465,8 +465,11 @@ static inline void parlio_ll_tx_enable_clock_gating(parl_io_dev_t *dev, bool en) /** * @brief Start TX unit to transmit data * + * @note The hardware monitors the rising edge of tx_start as the trigger signal. + * Once the transmission starts, it cannot be stopped by clearing tx_start. + * * @param dev Parallel IO register base address - * @param en True to start, False to stop + * @param en True to start, False to reset the reg state (not meaning the TX unit will be stopped) */ __attribute__((always_inline)) static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en) diff --git a/components/hal/esp32h2/include/hal/parlio_ll.h b/components/hal/esp32h2/include/hal/parlio_ll.h index ac3f5d7470..dd284cb900 100644 --- a/components/hal/esp32h2/include/hal/parlio_ll.h +++ b/components/hal/esp32h2/include/hal/parlio_ll.h @@ -472,8 +472,11 @@ static inline void parlio_ll_tx_enable_clock_gating(parl_io_dev_t *dev, bool en) /** * @brief Start TX unit to transmit data * + * @note The hardware monitors the rising edge of tx_start as the trigger signal. + * Once the transmission starts, it cannot be stopped by clearing tx_start. + * * @param dev Parallel IO register base address - * @param en True to start, False to stop + * @param en True to start, False to reset the reg state (not meaning the TX unit will be stopped) */ __attribute__((always_inline)) static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en) diff --git a/components/hal/esp32p4/include/hal/parlio_ll.h b/components/hal/esp32p4/include/hal/parlio_ll.h index f863acf277..db4731b20b 100644 --- a/components/hal/esp32p4/include/hal/parlio_ll.h +++ b/components/hal/esp32p4/include/hal/parlio_ll.h @@ -534,8 +534,11 @@ static inline void parlio_ll_tx_enable_clock_gating(parl_io_dev_t *dev, bool en) /** * @brief Start TX unit to transmit data * + * @note The hardware monitors the rising edge of tx_start as the trigger signal. + * Once the transmission starts, it cannot be stopped by clearing tx_start. + * * @param dev Parallel IO register base address - * @param en True to start, False to stop + * @param en True to start, False to reset the reg state (not meaning the TX unit will be stopped) */ __attribute__((always_inline)) static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en) From 25f35910a716c74424fc7902417687a86ce12ed8 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Wed, 22 Jan 2025 16:42:10 +0800 Subject: [PATCH 2/4] fix(parlio): fix rempty interrupt during resetting fifo Move the fifo reset to after disabling the tx core clock. And add external non-free running clock src test. --- components/esp_driver_parlio/src/parlio_tx.c | 29 ++++- .../test_apps/parlio/main/test_board.h | 45 +++---- .../test_apps/parlio/main/test_parlio_tx.c | 110 +++++++++++++++++- .../hal/esp32c6/include/hal/parlio_ll.h | 1 + .../hal/esp32h2/include/hal/parlio_ll.h | 1 + .../hal/esp32p4/include/hal/parlio_ll.h | 1 + 6 files changed, 161 insertions(+), 26 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index 916fe9365a..a693b02c58 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -59,6 +59,7 @@ typedef struct parlio_tx_unit_t { #endif portMUX_TYPE spinlock; // prevent resource accessing by user and interrupt concurrently uint32_t out_clk_freq_hz; // output clock frequency + parlio_clock_source_t clk_src; // Parallel IO internal clock source size_t max_transfer_bits; // maximum transfer size in bits size_t queue_depth; // size of transaction queue size_t num_trans_inflight; // indicates the number of transactions that are undergoing but not recycled to ready_queue @@ -262,6 +263,7 @@ static esp_err_t parlio_select_periph_clock(parlio_tx_unit_t *tx_unit, const par if (tx_unit->out_clk_freq_hz != config->output_clk_freq_hz) { ESP_LOGW(TAG, "precision loss, real output frequency: %"PRIu32, tx_unit->out_clk_freq_hz); } + tx_unit->clk_src = clk_src; return ESP_OK; } @@ -422,6 +424,18 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio tx_unit->cur_trans = t; + // If the external clock is a non-free-running clock, it needs to be switched to the internal free-running clock first. + // And then switched back to the actual clock after the reset is completed. + bool switch_clk = tx_unit->clk_src == PARLIO_CLK_SRC_EXTERNAL ? true : false; + if (switch_clk) { + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_set_clock_source(hal->regs, PARLIO_CLK_SRC_XTAL); + } + } + PARLIO_RCC_ATOMIC() { + parlio_ll_tx_reset_clock(hal->regs); + } + // DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up gdma_buffer_mount_config_t mount_config = { .buffer = (void *)t->payload, @@ -431,14 +445,21 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio .mark_final = true, // singly link list, mark final descriptor } }; + // Since the threshold of the clock divider counter is not updated simultaneously with the clock source switching. + // The update of the threshold relies on the moment when the counter reaches the threshold each time. + // We place gdma_link_mount_buffers between reset clock and disable clock to ensure enough time for updating the threshold of the clock divider counter. gdma_link_mount_buffers(tx_unit->dma_link, 0, &mount_config, 1, NULL); - parlio_ll_tx_reset_fifo(hal->regs); - PARLIO_RCC_ATOMIC() { - parlio_ll_tx_reset_clock(hal->regs); + + if (switch_clk) { + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_set_clock_source(hal->regs, PARLIO_CLK_SRC_EXTERNAL); + } } PARLIO_CLOCK_SRC_ATOMIC() { parlio_ll_tx_enable_clock(hal->regs, false); } + // reset tx fifo after disabling tx core clk to avoid unexpected rempty interrupt + parlio_ll_tx_reset_fifo(hal->regs); parlio_ll_tx_set_idle_data_value(hal->regs, t->idle_value); parlio_ll_tx_set_trans_bit_len(hal->regs, t->payload_bits); diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h index 931cc957f7..6ca3437189 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,7 @@ extern "C" { #if CONFIG_IDF_TARGET_ESP32C6 #define TEST_CLK_GPIO 10 +#define TEST_EXT_CLK_GPIO 12 #define TEST_VALID_GPIO 11 #define TEST_DATA0_GPIO 0 #define TEST_DATA1_GPIO 1 @@ -32,27 +33,29 @@ extern "C" { #define TEST_DATA6_GPIO 6 #define TEST_DATA7_GPIO 7 #elif CONFIG_IDF_TARGET_ESP32H2 -#define TEST_CLK_GPIO 10 -#define TEST_VALID_GPIO 11 -#define TEST_DATA0_GPIO 0 -#define TEST_DATA1_GPIO 1 -#define TEST_DATA2_GPIO 2 -#define TEST_DATA3_GPIO 3 -#define TEST_DATA4_GPIO 4 -#define TEST_DATA5_GPIO 5 -#define TEST_DATA6_GPIO 8 -#define TEST_DATA7_GPIO 9 +#define TEST_VALID_GPIO 2 +#define TEST_EXT_CLK_GPIO 4 +#define TEST_CLK_GPIO 3 +#define TEST_DATA0_GPIO 8 +#define TEST_DATA1_GPIO 5 +#define TEST_DATA2_GPIO 9 +#define TEST_DATA3_GPIO 10 +#define TEST_DATA4_GPIO 27 +#define TEST_DATA5_GPIO 11 +#define TEST_DATA6_GPIO 26 +#define TEST_DATA7_GPIO 12 #elif CONFIG_IDF_TARGET_ESP32P4 -#define TEST_CLK_GPIO 32 -#define TEST_VALID_GPIO 36 -#define TEST_DATA0_GPIO 20 -#define TEST_DATA1_GPIO 21 -#define TEST_DATA2_GPIO 22 -#define TEST_DATA3_GPIO 23 -#define TEST_DATA4_GPIO 45 -#define TEST_DATA5_GPIO 46 -#define TEST_DATA6_GPIO 47 -#define TEST_DATA7_GPIO 48 +#define TEST_CLK_GPIO 33 +#define TEST_EXT_CLK_GPIO 34 +#define TEST_VALID_GPIO 32 +#define TEST_DATA0_GPIO 24 +#define TEST_DATA1_GPIO 25 +#define TEST_DATA2_GPIO 26 +#define TEST_DATA3_GPIO 27 +#define TEST_DATA4_GPIO 28 +#define TEST_DATA5_GPIO 29 +#define TEST_DATA6_GPIO 30 +#define TEST_DATA7_GPIO 31 #else #error "Unsupported target" #endif 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 cb24b7a557..a71aeebbf6 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 @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,9 +11,11 @@ #include "unity.h" #include "driver/parlio_tx.h" #include "driver/gpio.h" +#include "hal/parlio_ll.h" #include "soc/soc_caps.h" #include "esp_attr.h" #include "test_board.h" +#include "soc/parl_io_struct.h" TEST_CASE("parallel_tx_unit_install_uninstall", "[parlio_tx]") { @@ -274,3 +276,109 @@ TEST_CASE("parallel_tx_clock_gating", "[paralio_tx]") TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); } #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING + +static void test_gpio_simulate_rising_edge(int gpio_sig, size_t times) +{ + while (times--) { + gpio_set_level(gpio_sig, 0); + gpio_set_level(gpio_sig, 1); + gpio_set_level(gpio_sig, 0); + } +} + +static uint8_t test_gpio_get_output_data(gpio_num_t* gpio, size_t gpio_num) +{ + uint8_t result = 0; + for (size_t i = 0; i < gpio_num; i++) { + int level = gpio_get_level(gpio[i]); + result |= level << i; + } + return result; +} + +static void test_use_external_non_free_running_clock(parlio_tx_unit_handle_t tx_unit, parlio_tx_unit_config_t config, int test_round) +{ + uint32_t clock_div = config.input_clk_src_freq_hz / config.output_clk_freq_hz; + TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit)); + TEST_ESP_OK(parlio_tx_unit_enable(tx_unit)); + // let core clock running for a while to update the clock divider threshold + esp_rom_delay_us(100 * 1000); + parlio_transmit_config_t transmit_config = { + .idle_value = 0xAA, + }; + __attribute__((aligned(64))) uint8_t payload[256] = {0}; + for (int i = 0; i < 256; i++) { + payload[i] = i; + } + + for (int round = 0; round < test_round; round++) { + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 256 * sizeof(uint8_t) * 8, &transmit_config)); + for (int i = 0; i < 256; i++) { + // After "clock_div" times external pulses pass through the internal frequency divider, the parlio core clock generates a single pulse. + test_gpio_simulate_rising_edge(TEST_EXT_CLK_GPIO, clock_div); + TEST_ASSERT_EQUAL(i, test_gpio_get_output_data(config.data_gpio_nums, config.data_width)); + } + // In order to update the idle value, an additional rising edge is required + test_gpio_simulate_rising_edge(TEST_EXT_CLK_GPIO, clock_div); + TEST_ASSERT_EQUAL(transmit_config.idle_value, test_gpio_get_output_data(config.data_gpio_nums, config.data_width)); + TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, 100)); + } + TEST_ESP_OK(parlio_tx_unit_disable(tx_unit)); + TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); +} + +TEST_CASE("parallel tx unit use external non-free running clock", "[parlio_tx]") +{ + printf("use gpio as external clock source\r\n"); + // configure the data gpio for loopback test + gpio_config_t gpio_conf = { + .mode = GPIO_MODE_INPUT, + .pin_bit_mask = BIT64(TEST_DATA0_GPIO) | BIT64(TEST_DATA1_GPIO) | BIT64(TEST_DATA2_GPIO) | BIT64(TEST_DATA3_GPIO) | + BIT64(TEST_DATA4_GPIO) | BIT64(TEST_DATA5_GPIO) | BIT64(TEST_DATA6_GPIO) | BIT64(TEST_DATA7_GPIO), + }; + TEST_ESP_OK(gpio_config(&gpio_conf)); + // configure the external clock output gpio + gpio_conf.mode = GPIO_MODE_OUTPUT; + gpio_conf.pin_bit_mask = BIT64(TEST_EXT_CLK_GPIO); + TEST_ESP_OK(gpio_config(&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 = TEST_EXT_CLK_GPIO, + .input_clk_src_freq_hz = 80 * 1000 * 1000, // Note that this is not the real input frequency, we just use it to calculate the clock divider + .valid_gpio_num = -1, // don't generate 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, // For the same reason, this is not the real output frequency + .trans_queue_depth = 8, + .max_transfer_size = 256, + .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB, + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + }; + + uint8_t test_round = 50; + printf("test input clk freq is greater than output clk freq\r\n"); + test_use_external_non_free_running_clock(tx_unit, config, test_round); + + // changes input clk freq + config.input_clk_src_freq_hz = 1 * 1000 * 1000; + printf("test special condition, input clk freq equals to output clk freq\r\n"); + test_use_external_non_free_running_clock(tx_unit, config, test_round); + + TEST_ESP_OK(gpio_reset_pin(TEST_EXT_CLK_GPIO)); + for (int i = 0; i < 8; i++) { + TEST_ESP_OK(gpio_reset_pin(config.data_gpio_nums[i])); + } +}; diff --git a/components/hal/esp32c6/include/hal/parlio_ll.h b/components/hal/esp32c6/include/hal/parlio_ll.h index 3eb277d14f..1679dc35c2 100644 --- a/components/hal/esp32c6/include/hal/parlio_ll.h +++ b/components/hal/esp32c6/include/hal/parlio_ll.h @@ -373,6 +373,7 @@ static inline void parlio_ll_rx_update_config(parl_io_dev_t *dev) * @param dev Parallel IO register base address * @param src Clock source */ +__attribute__((always_inline)) static inline void parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src) { (void)dev; diff --git a/components/hal/esp32h2/include/hal/parlio_ll.h b/components/hal/esp32h2/include/hal/parlio_ll.h index dd284cb900..9cb8180898 100644 --- a/components/hal/esp32h2/include/hal/parlio_ll.h +++ b/components/hal/esp32h2/include/hal/parlio_ll.h @@ -380,6 +380,7 @@ static inline void parlio_ll_rx_update_config(parl_io_dev_t *dev) * @param dev Parallel IO register base address * @param src Clock source */ +__attribute__((always_inline)) static inline void parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src) { (void)dev; diff --git a/components/hal/esp32p4/include/hal/parlio_ll.h b/components/hal/esp32p4/include/hal/parlio_ll.h index db4731b20b..e32ae87e0f 100644 --- a/components/hal/esp32p4/include/hal/parlio_ll.h +++ b/components/hal/esp32p4/include/hal/parlio_ll.h @@ -413,6 +413,7 @@ static inline void parlio_ll_rx_update_config(parl_io_dev_t *dev) * @param dev Parallel IO register base address * @param src Clock source */ +__attribute__((always_inline)) static inline void _parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src) { (void)dev; From f3eec647aaa695883fd5d2262a8b929393704bef Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Fri, 28 Feb 2025 15:03:06 +0800 Subject: [PATCH 3/4] feat(parlio_tx): backport the clock change to v5.3 --- components/esp_driver_parlio/src/parlio_tx.c | 9 +++++---- .../test_apps/parlio/main/test_parlio_tx.c | 18 +----------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index a693b02c58..6c059ca43e 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -475,6 +475,7 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio esp_err_t parlio_tx_unit_enable(parlio_tx_unit_handle_t tx_unit) { + parlio_hal_context_t *hal = &tx_unit->base.group->hal; ESP_RETURN_ON_FALSE(tx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); parlio_tx_fsm_t expected_fsm = PARLIO_TX_FSM_INIT; if (atomic_compare_exchange_strong(&tx_unit->fsm, &expected_fsm, PARLIO_TX_FSM_ENABLE_WAIT)) { @@ -482,13 +483,16 @@ esp_err_t parlio_tx_unit_enable(parlio_tx_unit_handle_t tx_unit) if (tx_unit->pm_lock) { esp_pm_lock_acquire(tx_unit->pm_lock); } - parlio_hal_context_t *hal = &tx_unit->base.group->hal; parlio_ll_enable_interrupt(hal->regs, PARLIO_LL_EVENT_TX_EOF, true); atomic_store(&tx_unit->fsm, PARLIO_TX_FSM_ENABLE); } else { ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "unit not in init state"); } + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_enable_clock(hal->regs, true); + } + // check if we need to start one pending transaction parlio_tx_trans_desc_t *t = NULL; expected_fsm = PARLIO_TX_FSM_ENABLE; @@ -630,9 +634,6 @@ static void IRAM_ATTR parlio_tx_default_isr(void *args) if (status & PARLIO_LL_EVENT_TX_EOF) { parlio_ll_clear_interrupt_status(hal->regs, PARLIO_LL_EVENT_TX_EOF); - PARLIO_CLOCK_SRC_ATOMIC() { - parlio_ll_tx_enable_clock(hal->regs, false); - } parlio_ll_tx_start(hal->regs, false); parlio_tx_trans_desc_t *trans_desc = NULL; 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 a71aeebbf6..5a421cde0f 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 @@ -329,18 +329,6 @@ static void test_use_external_non_free_running_clock(parlio_tx_unit_handle_t tx_ TEST_CASE("parallel tx unit use external non-free running clock", "[parlio_tx]") { - printf("use gpio as external clock source\r\n"); - // configure the data gpio for loopback test - gpio_config_t gpio_conf = { - .mode = GPIO_MODE_INPUT, - .pin_bit_mask = BIT64(TEST_DATA0_GPIO) | BIT64(TEST_DATA1_GPIO) | BIT64(TEST_DATA2_GPIO) | BIT64(TEST_DATA3_GPIO) | - BIT64(TEST_DATA4_GPIO) | BIT64(TEST_DATA5_GPIO) | BIT64(TEST_DATA6_GPIO) | BIT64(TEST_DATA7_GPIO), - }; - TEST_ESP_OK(gpio_config(&gpio_conf)); - // configure the external clock output gpio - gpio_conf.mode = GPIO_MODE_OUTPUT; - gpio_conf.pin_bit_mask = BIT64(TEST_EXT_CLK_GPIO); - TEST_ESP_OK(gpio_config(&gpio_conf)); printf("install parlio tx unit\r\n"); parlio_tx_unit_handle_t tx_unit = NULL; @@ -366,6 +354,7 @@ TEST_CASE("parallel tx unit use external non-free running clock", "[parlio_tx]") .max_transfer_size = 256, .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB, .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .flags.io_loop_back = true, }; uint8_t test_round = 50; @@ -376,9 +365,4 @@ TEST_CASE("parallel tx unit use external non-free running clock", "[parlio_tx]") config.input_clk_src_freq_hz = 1 * 1000 * 1000; printf("test special condition, input clk freq equals to output clk freq\r\n"); test_use_external_non_free_running_clock(tx_unit, config, test_round); - - TEST_ESP_OK(gpio_reset_pin(TEST_EXT_CLK_GPIO)); - for (int i = 0; i < 8; i++) { - TEST_ESP_OK(gpio_reset_pin(config.data_gpio_nums[i])); - } }; From 546b60f6f1eff2e8aff1c5c50402e2371d028906 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Fri, 7 Mar 2025 17:14:09 +0800 Subject: [PATCH 4/4] fix(parlio): fix non-free running test case --- .../test_apps/parlio/main/test_parlio_tx.c | 6 ++++-- .../esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) 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 5a421cde0f..78958e1302 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 @@ -301,8 +301,10 @@ static void test_use_external_non_free_running_clock(parlio_tx_unit_handle_t tx_ uint32_t clock_div = config.input_clk_src_freq_hz / config.output_clk_freq_hz; TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit)); TEST_ESP_OK(parlio_tx_unit_enable(tx_unit)); - // let core clock running for a while to update the clock divider threshold - esp_rom_delay_us(100 * 1000); + // let core clock running for a while to update the clock divider threshold, this is a hardware limitation + // the following rising edge count is not a magic value, we just need it to be larger than the clock divider value in the previous test case + test_gpio_simulate_rising_edge(TEST_EXT_CLK_GPIO, 100); + esp_rom_delay_us(1000); parlio_transmit_config_t transmit_config = { .idle_value = 0xAA, }; diff --git a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release index 91d93f163e..199b0cf97c 100644 --- a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release +++ b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release @@ -1,5 +1,6 @@ CONFIG_PM_ENABLE=y CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_PM_DFS_INIT_AUTO=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y