Merge branch 'refactor/parlio_function_placement' into 'master'

refactor(parlio): function placement distinguishes from tx and rx driver

See merge request espressif/esp-idf!37382
This commit is contained in:
morris 2025-03-05 14:58:08 +08:00
commit 3f66b30680
18 changed files with 126 additions and 73 deletions

View File

@ -1,6 +1,5 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
import pytest import pytest
from pytest_embedded import Dut from pytest_embedded import Dut
@ -10,7 +9,7 @@ from pytest_embedded import Dut
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'iram_safe', 'cache_safe',
'release', 'release',
], ],
indirect=True, indirect=True,

View File

@ -1,17 +1,62 @@
menu "ESP-Driver:Parallel IO Configurations" menu "ESP-Driver:Parallel IO Configurations"
depends on SOC_PARLIO_SUPPORTED depends on SOC_PARLIO_SUPPORTED
config PARLIO_ENABLE_DEBUG_LOG config PARLIO_TX_ISR_HANDLER_IN_IRAM
bool "Enable debug log" bool "Place Parallel IO TX ISR handler in IRAM to reduce latency"
default y
select PARLIO_OBJ_CACHE_SAFE
help
Place Parallel IO TX ISR handler in IRAM to reduce latency caused by cache miss.
config PARLIO_RX_ISR_HANDLER_IN_IRAM
bool "Place Parallel IO RX ISR handler in IRAM to reduce latency"
default y
select PARLIO_OBJ_CACHE_SAFE
help
Place Parallel IO RX ISR handler in IRAM to reduce latency caused by cache miss.
config PARLIO_TX_ISR_CACHE_SAFE
bool "Allow Parallel IO TX ISR to execute when cache is disabled"
select PARLIO_TX_ISR_HANDLER_IN_IRAM
select GDMA_ISR_IRAM_SAFE
default n default n
help help
whether to enable the debug log message for parallel IO driver. Enable this option to allow the Parallel IO TX Interrupt Service Routine (ISR)
Note that, this option only controls the parallel IO driver log, won't affect other drivers. to execute even when the cache is disabled. This can be useful in scenarios where the cache
might be turned off, but the Parallel IO TX functionality is still required to operate correctly.
config PARLIO_RX_ISR_CACHE_SAFE
bool "Allow Parallel IO RX ISR to execute when cache is disabled"
select PARLIO_RX_ISR_HANDLER_IN_IRAM
select GDMA_ISR_IRAM_SAFE
default n
help
Enable this option to allow the Parallel IO RX Interrupt Service Routine (ISR)
to execute even when the cache is disabled. This can be useful in scenarios where the cache
might be turned off, but the Parallel IO RX functionality is still required to operate correctly.
config PARLIO_OBJ_CACHE_SAFE
bool
default n
help
This will ensure the driver object will not be allocated from a memory region
where its cache can be disabled.
config PARLIO_ENABLE_DEBUG_LOG
bool "Force enable debug log"
default n
help
If enabled, Parallel IO driver component will:
1. ignore the global logging settings
2. compile all log messages into the binary
3. set the runtime log level to VERBOSE
Please enable this option by caution, as it will increase the binary size.
config PARLIO_ISR_IRAM_SAFE config PARLIO_ISR_IRAM_SAFE
bool "Parallel IO ISR IRAM-Safe" bool "Parallel IO ISR IRAM-Safe (Deprecated)"
default n default n
select GDMA_ISR_IRAM_SAFE select PARLIO_TX_ISR_CACHE_SAFE
select PARLIO_RX_ISR_CACHE_SAFE
help help
Ensure the Parallel IO interrupt is IRAM-Safe by allowing the interrupt handler to be Ensure the Parallel IO interrupt is IRAM-Safe by allowing the interrupt handler to be
executable when the cache is disabled (e.g. SPI Flash write). executable when the cache is disabled (e.g. SPI Flash write).

View File

@ -126,7 +126,7 @@ typedef bool (*parlio_tx_done_callback_t)(parlio_tx_unit_handle_t tx_unit, const
/** /**
* @brief Group of Parallel IO TX callbacks * @brief Group of Parallel IO TX callbacks
* @note The callbacks are all running under ISR environment * @note The callbacks are all running under ISR environment
* @note When CONFIG_PARLIO_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. * @note When CONFIG_PARLIO_TX_ISR_CACHE_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
* The variables used in the function should be in the SRAM as well. * The variables used in the function should be in the SRAM as well.
*/ */
typedef struct { typedef struct {
@ -137,7 +137,7 @@ typedef struct {
* @brief Set event callbacks for Parallel IO TX unit * @brief Set event callbacks for Parallel IO TX unit
* *
* @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL. * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
* @note When CONFIG_PARLIO_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. * @note When CONFIG_PARLIO_TX_ISR_CACHE_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
* The variables used in the function should be in the SRAM as well. The `user_data` should also reside in SRAM. * The variables used in the function should be in the SRAM as well. The `user_data` should also reside in SRAM.
* *
* @param[in] tx_unit Parallel IO TX unit that created by `parlio_new_tx_unit` * @param[in] tx_unit Parallel IO TX unit that created by `parlio_new_tx_unit`

View File

@ -1,7 +1,21 @@
[mapping:parlio_driver]
archive: libesp_driver_parlio.a
entries:
if PARLIO_TX_ISR_HANDLER_IN_IRAM = y:
parlio_tx: parlio_tx_default_isr (noflash)
parlio_tx: parlio_tx_do_transaction (noflash)
if PARLIO_RX_ISR_HANDLER_IN_IRAM = y:
parlio_rx: parlio_rx_default_eof_callback (noflash)
parlio_rx: parlio_rx_default_desc_done_callback (noflash)
parlio_rx: parlio_rx_mount_transaction_buffer (noflash)
parlio_rx: parlio_rx_set_delimiter_config (noflash)
[mapping:parlio_driver_gdma] [mapping:parlio_driver_gdma]
archive: libesp_hw_support.a archive: libesp_hw_support.a
entries: entries:
if PARLIO_ISR_IRAM_SAFE: if PARLIO_TX_ISR_HANDLER_IN_IRAM = y:
gdma_link: gdma_link_mount_buffers (noflash) gdma_link: gdma_link_mount_buffers (noflash)
gdma_link: gdma_link_get_head_addr (noflash) gdma_link: gdma_link_get_head_addr (noflash)
gdma: gdma_start (noflash) gdma: gdma_start (noflash)
if PARLIO_RX_ISR_HANDLER_IN_IRAM = y:
gdma: gdma_start (noflash)

View File

@ -19,7 +19,7 @@
#include "hal/parlio_ll.h" #include "hal/parlio_ll.h"
#include "esp_private/esp_clk.h" #include "esp_private/esp_clk.h"
#include "esp_private/sleep_retention.h" #include "esp_private/sleep_retention.h"
#include "parlio_private.h" #include "parlio_priv.h"
static const char *TAG = "parlio"; static const char *TAG = "parlio";

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -26,11 +26,12 @@
#include "esp_private/gpio.h" #include "esp_private/gpio.h"
#include "esp_private/sleep_retention.h" #include "esp_private/sleep_retention.h"
#if CONFIG_PARLIO_ISR_IRAM_SAFE #if CONFIG_PARLIO_OBJ_CACHE_SAFE
#define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else #else
#define PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #define PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif #endif
#define PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) #define PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#if SOC_PARLIO_TX_RX_SHARE_INTERRUPT #if SOC_PARLIO_TX_RX_SHARE_INTERRUPT
@ -39,10 +40,10 @@
#define PARLIO_INTR_ALLOC_FLAG_SHARED 0 #define PARLIO_INTR_ALLOC_FLAG_SHARED 0
#endif #endif
#if CONFIG_PARLIO_ISR_IRAM_SAFE #if CONFIG_PARLIO_TX_CACHE_SAFE
#define PARLIO_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED | ESP_INTR_FLAG_IRAM) #define PARLIO_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED | ESP_INTR_FLAG_IRAM)
#else #else
#define PARLIO_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED) #define PARLIO_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED)
#endif #endif
// Use retention link only when the target supports sleep retention is enabled // Use retention link only when the target supports sleep retention is enabled
@ -60,14 +61,6 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t;
#endif #endif
#endif // defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS) #endif // defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS)
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED
#else
#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED
#endif
#if SOC_PERIPH_CLK_CTRL_SHARED #if SOC_PERIPH_CLK_CTRL_SHARED
#define PARLIO_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #define PARLIO_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else #else

View File

@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -29,7 +29,7 @@
#include "hal/hal_utils.h" #include "hal/hal_utils.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/parlio_rx.h" #include "driver/parlio_rx.h"
#include "parlio_private.h" #include "parlio_priv.h"
#include "esp_memory_utils.h" #include "esp_memory_utils.h"
#include "esp_clk_tree.h" #include "esp_clk_tree.h"
#include "esp_attr.h" #include "esp_attr.h"
@ -39,6 +39,14 @@
static const char *TAG = "parlio-rx"; static const char *TAG = "parlio-rx";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED
#else
#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED
#endif
/** /**
* @brief Parlio RX transaction * @brief Parlio RX transaction
*/ */
@ -132,7 +140,7 @@ typedef struct parlio_rx_delimiter_t {
static portMUX_TYPE s_rx_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; static portMUX_TYPE s_rx_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans) size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans)
{ {
parlio_dma_desc_t **p_desc = rx_unit->dma_descs; parlio_dma_desc_t **p_desc = rx_unit->dma_descs;
/* Update the current transaction to the next one, and declare the delimiter is under using of the rx unit */ /* Update the current transaction to the next one, and declare the delimiter is under using of the rx unit */
@ -191,7 +199,7 @@ static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_
return offset; return offset;
} }
static IRAM_ATTR void s_parlio_set_delimiter_config(parlio_rx_unit_handle_t rx_unit, parlio_rx_delimiter_handle_t deli) static void parlio_rx_set_delimiter_config(parlio_rx_unit_handle_t rx_unit, parlio_rx_delimiter_handle_t deli)
{ {
parlio_hal_context_t *hal = &(rx_unit->base.group->hal); parlio_hal_context_t *hal = &(rx_unit->base.group->hal);
@ -249,7 +257,7 @@ static IRAM_ATTR void s_parlio_set_delimiter_config(parlio_rx_unit_handle_t rx_u
parlio_ll_rx_update_config(hal->regs); parlio_ll_rx_update_config(hal->regs);
} }
static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, const parlio_rx_unit_config_t *config) static esp_err_t parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, const parlio_rx_unit_config_t *config)
{ {
int group_id = rx_unit->base.group->group_id; int group_id = rx_unit->base.group->group_id;
int unit_id = rx_unit->base.unit_id; int unit_id = rx_unit->base.unit_id;
@ -320,7 +328,7 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
return ESP_OK; return ESP_OK;
} }
static IRAM_ATTR bool s_parlio_rx_default_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) static bool parlio_rx_default_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{ {
parlio_rx_unit_handle_t rx_unit = (parlio_rx_unit_handle_t)user_data; parlio_rx_unit_handle_t rx_unit = (parlio_rx_unit_handle_t)user_data;
BaseType_t high_task_woken = pdFALSE; BaseType_t high_task_woken = pdFALSE;
@ -358,10 +366,10 @@ static IRAM_ATTR bool s_parlio_rx_default_eof_callback(gdma_channel_handle_t dma
} }
/* If the delimiter of the next transaction is not same as the current one, need to re-config the hardware */ /* If the delimiter of the next transaction is not same as the current one, need to re-config the hardware */
if ((next_trans.delimiter != NULL) && (next_trans.delimiter != rx_unit->curr_trans.delimiter)) { if ((next_trans.delimiter != NULL) && (next_trans.delimiter != rx_unit->curr_trans.delimiter)) {
s_parlio_set_delimiter_config(rx_unit, next_trans.delimiter); parlio_rx_set_delimiter_config(rx_unit, next_trans.delimiter);
} }
/* Mount the new transaction buffer and start the new transaction */ /* Mount the new transaction buffer and start the new transaction */
s_parlio_mount_transaction_buffer(rx_unit, &next_trans); parlio_rx_mount_transaction_buffer(rx_unit, &next_trans);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs[0]); gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs[0]);
if (rx_unit->cfg.flags.free_clk) { if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_start(rx_unit->base.group->hal.regs, true); parlio_ll_rx_start(rx_unit->base.group->hal.regs, true);
@ -384,7 +392,7 @@ static IRAM_ATTR bool s_parlio_rx_default_eof_callback(gdma_channel_handle_t dma
return need_yield; return need_yield;
} }
static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{ {
parlio_rx_unit_handle_t rx_unit = (parlio_rx_unit_handle_t)user_data; parlio_rx_unit_handle_t rx_unit = (parlio_rx_unit_handle_t)user_data;
bool need_yield = false; bool need_yield = false;
@ -430,7 +438,7 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle
return need_yield; return need_yield;
} }
static esp_err_t s_parlio_rx_create_dma_descriptors(parlio_rx_unit_handle_t rx_unit, uint32_t max_recv_size) static esp_err_t parlio_rx_create_dma_descriptors(parlio_rx_unit_handle_t rx_unit, uint32_t max_recv_size)
{ {
ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid param"); ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid param");
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
@ -470,7 +478,7 @@ err:
return ret; return ret;
} }
static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit)
{ {
/* Allocate and connect the GDMA channel */ /* Allocate and connect the GDMA channel */
gdma_channel_alloc_config_t dma_chan_config = { gdma_channel_alloc_config_t dma_chan_config = {
@ -488,15 +496,15 @@ static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit)
/* Register callbacks */ /* Register callbacks */
gdma_rx_event_callbacks_t cbs = { gdma_rx_event_callbacks_t cbs = {
.on_recv_eof = s_parlio_rx_default_eof_callback, .on_recv_eof = parlio_rx_default_eof_callback,
.on_recv_done = s_parlio_rx_default_desc_done_callback, .on_recv_done = parlio_rx_default_desc_done_callback,
}; };
gdma_register_rx_event_callbacks(rx_unit->dma_chan, &cbs, rx_unit); gdma_register_rx_event_callbacks(rx_unit->dma_chan, &cbs, rx_unit);
return ESP_OK; return ESP_OK;
} }
static esp_err_t s_parlio_select_periph_clock(parlio_rx_unit_handle_t rx_unit, const parlio_rx_unit_config_t *config) static esp_err_t parlio_select_periph_clock(parlio_rx_unit_handle_t rx_unit, const parlio_rx_unit_config_t *config)
{ {
parlio_hal_context_t *hal = &rx_unit->base.group->hal; parlio_hal_context_t *hal = &rx_unit->base.group->hal;
parlio_clock_source_t clk_src = config->clk_src; parlio_clock_source_t clk_src = config->clk_src;
@ -557,7 +565,7 @@ static esp_err_t s_parlio_select_periph_clock(parlio_rx_unit_handle_t rx_unit, c
return ESP_OK; return ESP_OK;
} }
static esp_err_t s_parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit) static esp_err_t parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit)
{ {
/* Free the transaction queue */ /* Free the transaction queue */
if (rx_unit->trans_que) { if (rx_unit->trans_que) {
@ -643,7 +651,7 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
unit->trans_que = xQueueCreateWithCaps(config->trans_queue_depth, sizeof(parlio_rx_transaction_t), PARLIO_MEM_ALLOC_CAPS); unit->trans_que = xQueueCreateWithCaps(config->trans_queue_depth, sizeof(parlio_rx_transaction_t), PARLIO_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(unit->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue"); ESP_GOTO_ON_FALSE(unit->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue");
ESP_GOTO_ON_ERROR(s_parlio_rx_create_dma_descriptors(unit, config->max_recv_size), err, TAG, "create dma descriptor failed"); ESP_GOTO_ON_ERROR(parlio_rx_create_dma_descriptors(unit, config->max_recv_size), err, TAG, "create dma descriptor failed");
/* Register and attach the rx unit to the group */ /* Register and attach the rx unit to the group */
ESP_GOTO_ON_ERROR(parlio_register_unit_to_group(&unit->base), err, TAG, "failed to register the rx unit to the group"); ESP_GOTO_ON_ERROR(parlio_register_unit_to_group(&unit->base), err, TAG, "failed to register the rx unit to the group");
memcpy(&unit->cfg, config, sizeof(parlio_rx_unit_config_t)); memcpy(&unit->cfg, config, sizeof(parlio_rx_unit_config_t));
@ -655,9 +663,9 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
parlio_group_t *group = unit->base.group; parlio_group_t *group = unit->base.group;
parlio_hal_context_t *hal = &group->hal; parlio_hal_context_t *hal = &group->hal;
/* Initialize GPIO */ /* Initialize GPIO */
ESP_GOTO_ON_ERROR(s_parlio_rx_unit_set_gpio(unit, config), err, TAG, "failed to set GPIO"); ESP_GOTO_ON_ERROR(parlio_rx_unit_set_gpio(unit, config), err, TAG, "failed to set GPIO");
/* Install DMA service */ /* Install DMA service */
ESP_GOTO_ON_ERROR(s_parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed"); ESP_GOTO_ON_ERROR(parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed");
/* Reset RX module */ /* Reset RX module */
PARLIO_RCC_ATOMIC() { PARLIO_RCC_ATOMIC() {
parlio_ll_rx_reset_clock(hal->regs); parlio_ll_rx_reset_clock(hal->regs);
@ -668,7 +676,7 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
} }
parlio_ll_rx_start(hal->regs, false); parlio_ll_rx_start(hal->regs, false);
/* parlio_ll_clock_source_t and parlio_clock_source_t are binary compatible if the clock source is from internal */ /* parlio_ll_clock_source_t and parlio_clock_source_t are binary compatible if the clock source is from internal */
ESP_GOTO_ON_ERROR(s_parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed"); ESP_GOTO_ON_ERROR(parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed");
/* Set the data width */ /* Set the data width */
parlio_ll_rx_set_bus_width(hal->regs, config->data_width); parlio_ll_rx_set_bus_width(hal->regs, config->data_width);
#if SOC_PARLIO_RX_CLK_SUPPORT_GATING #if SOC_PARLIO_RX_CLK_SUPPORT_GATING
@ -694,7 +702,7 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
err: err:
if (unit) { if (unit) {
s_parlio_destroy_rx_unit(unit); parlio_destroy_rx_unit(unit);
} }
return ret; return ret;
} }
@ -706,7 +714,7 @@ esp_err_t parlio_del_rx_unit(parlio_rx_unit_handle_t rx_unit)
ESP_RETURN_ON_FALSE(!rx_unit->is_enabled, ESP_ERR_INVALID_STATE, TAG, "the unit has not disabled"); ESP_RETURN_ON_FALSE(!rx_unit->is_enabled, ESP_ERR_INVALID_STATE, TAG, "the unit has not disabled");
ESP_LOGD(TAG, "del rx unit (%d, %d)", rx_unit->base.group->group_id, rx_unit->base.unit_id); ESP_LOGD(TAG, "del rx unit (%d, %d)", rx_unit->base.group->group_id, rx_unit->base.unit_id);
return s_parlio_destroy_rx_unit(rx_unit); return parlio_destroy_rx_unit(rx_unit);
} }
esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queue) esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queue)
@ -747,8 +755,8 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu
parlio_ll_rx_enable_clock(hal->regs, false); parlio_ll_rx_enable_clock(hal->regs, false);
} }
} }
s_parlio_set_delimiter_config(rx_unit, trans.delimiter); parlio_rx_set_delimiter_config(rx_unit, trans.delimiter);
s_parlio_mount_transaction_buffer(rx_unit, &trans); parlio_rx_mount_transaction_buffer(rx_unit, &trans);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc); gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc);
if (rx_unit->cfg.flags.free_clk) { if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_start(hal->regs, true); parlio_ll_rx_start(hal->regs, true);
@ -919,7 +927,7 @@ esp_err_t parlio_del_rx_delimiter(parlio_rx_delimiter_handle_t delimiter)
return ESP_OK; return ESP_OK;
} }
static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans) static esp_err_t parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans)
{ {
bool is_stopped = false; bool is_stopped = false;
/* Get whether DMA stopped atomically */ /* Get whether DMA stopped atomically */
@ -933,9 +941,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit
} }
} }
if (trans->delimiter != rx_unit->curr_trans.delimiter) { if (trans->delimiter != rx_unit->curr_trans.delimiter) {
s_parlio_set_delimiter_config(rx_unit, trans->delimiter); parlio_rx_set_delimiter_config(rx_unit, trans->delimiter);
} }
s_parlio_mount_transaction_buffer(rx_unit, trans); parlio_rx_mount_transaction_buffer(rx_unit, trans);
// Take semaphore without block time here, only indicate there are transactions on receiving // Take semaphore without block time here, only indicate there are transactions on receiving
xSemaphoreTake(rx_unit->trans_sem, 0); xSemaphoreTake(rx_unit->trans_sem, 0);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc); gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc);
@ -1012,7 +1020,7 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit,
rx_unit->usr_recv_buf = payload; rx_unit->usr_recv_buf = payload;
xSemaphoreTake(rx_unit->mutex, portMAX_DELAY); xSemaphoreTake(rx_unit->mutex, portMAX_DELAY);
esp_err_t ret = s_parlio_rx_unit_do_transaction(rx_unit, &transaction); esp_err_t ret = parlio_rx_unit_do_transaction(rx_unit, &transaction);
xSemaphoreGive(rx_unit->mutex); xSemaphoreGive(rx_unit->mutex);
return ret; return ret;
} }
@ -1037,7 +1045,7 @@ esp_err_t parlio_rx_unit_register_event_callbacks(parlio_rx_unit_handle_t rx_uni
ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
#if CONFIG_PARLIO_ISR_IRAM_SAFE #if CONFIG_PARLIO_RX_ISR_CACHE_SAFE
ESP_RETURN_ON_FALSE(!cbs->on_partial_receive || esp_ptr_in_iram(cbs->on_partial_receive), ESP_ERR_INVALID_ARG, ESP_RETURN_ON_FALSE(!cbs->on_partial_receive || esp_ptr_in_iram(cbs->on_partial_receive), ESP_ERR_INVALID_ARG,
TAG, "on_partial_receive not in IRAM"); TAG, "on_partial_receive not in IRAM");
ESP_RETURN_ON_FALSE(!cbs->on_receive_done || esp_ptr_in_iram(cbs->on_receive_done), ESP_ERR_INVALID_ARG, ESP_RETURN_ON_FALSE(!cbs->on_receive_done || esp_ptr_in_iram(cbs->on_receive_done), ESP_ERR_INVALID_ARG,

View File

@ -32,7 +32,7 @@
#include "hal/parlio_ll.h" #include "hal/parlio_ll.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/parlio_tx.h" #include "driver/parlio_tx.h"
#include "parlio_private.h" #include "parlio_priv.h"
#include "esp_memory_utils.h" #include "esp_memory_utils.h"
#include "esp_clk_tree.h" #include "esp_clk_tree.h"
#include "esp_private/esp_clk_tree_common.h" #include "esp_private/esp_clk_tree_common.h"
@ -344,7 +344,7 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
ESP_GOTO_ON_ERROR(parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed"); ESP_GOTO_ON_ERROR(parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed");
// install interrupt service // install interrupt service
int isr_flags = PARLIO_INTR_ALLOC_FLAG; int isr_flags = PARLIO_TX_INTR_ALLOC_FLAG;
ret = esp_intr_alloc_intrstatus(parlio_periph_signals.groups[group->group_id].tx_irq_id, isr_flags, ret = esp_intr_alloc_intrstatus(parlio_periph_signals.groups[group->group_id].tx_irq_id, isr_flags,
(uint32_t)parlio_ll_get_interrupt_status_reg(hal->regs), (uint32_t)parlio_ll_get_interrupt_status_reg(hal->regs),
PARLIO_LL_EVENT_TX_MASK, parlio_tx_default_isr, unit, &unit->intr); PARLIO_LL_EVENT_TX_MASK, parlio_tx_default_isr, unit, &unit->intr);
@ -442,7 +442,7 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
{ {
ESP_RETURN_ON_FALSE(tx_unit && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(tx_unit && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
#if CONFIG_PARLIO_ISR_IRAM_SAFE #if CONFIG_PARLIO_TX_ISR_CACHE_SAFE
if (cbs->on_trans_done) { if (cbs->on_trans_done) {
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_trans_done callback not in IRAM"); ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_trans_done callback not in IRAM");
} }
@ -456,7 +456,7 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
return ESP_OK; return ESP_OK;
} }
static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_t *t) static void parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_t *t)
{ {
parlio_hal_context_t *hal = &tx_unit->base.group->hal; parlio_hal_context_t *hal = &tx_unit->base.group->hal;
@ -661,7 +661,7 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
return ESP_OK; return ESP_OK;
} }
static void IRAM_ATTR parlio_tx_default_isr(void *args) static void parlio_tx_default_isr(void *args)
{ {
parlio_tx_unit_t *tx_unit = (parlio_tx_unit_t *)args; parlio_tx_unit_t *tx_unit = (parlio_tx_unit_t *)args;
parlio_group_t *group = tx_unit->base.group; parlio_group_t *group = tx_unit->base.group;

View File

@ -3,7 +3,7 @@ set(srcs "test_app_main.c"
"test_parlio_tx.c") "test_parlio_tx.c")
# TODO: IDF-7840, semaphore in 'spi_bus_lock.c' is not IRAM safe # TODO: IDF-7840, semaphore in 'spi_bus_lock.c' is not IRAM safe
if(CONFIG_PARLIO_ISR_IRAM_SAFE) if(CONFIG_PARLIO_RX_ISR_CACHE_SAFE)
list(REMOVE_ITEM srcs "test_parlio_rx.c") list(REMOVE_ITEM srcs "test_parlio_rx.c")
endif() endif()

View File

@ -11,7 +11,7 @@
extern "C" { extern "C" {
#endif #endif
#if CONFIG_PARLIO_ISR_IRAM_SAFE #if CONFIG_PARLIO_TX_ISR_CACHE_SAFE || CONFIG_PARLIO_RX_ISR_CACHE_SAFE
#define TEST_PARLIO_CALLBACK_ATTR IRAM_ATTR #define TEST_PARLIO_CALLBACK_ATTR IRAM_ATTR
#define TEST_PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #define TEST_PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else #else

View File

@ -15,7 +15,6 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "test_board.h" #include "test_board.h"
#include "soc/parl_io_struct.h"
TEST_CASE("parallel_tx_unit_install_uninstall", "[parlio_tx]") TEST_CASE("parallel_tx_unit_install_uninstall", "[parlio_tx]")
{ {

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
import pytest import pytest
from pytest_embedded import Dut from pytest_embedded import Dut
@ -12,7 +12,7 @@ from pytest_embedded import Dut
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'iram_safe', 'cache_safe',
'release', 'release',
], ],
indirect=True, indirect=True,

View File

@ -1,6 +1,7 @@
CONFIG_COMPILER_DUMP_RTL_FILES=y CONFIG_COMPILER_DUMP_RTL_FILES=y
CONFIG_COMPILER_OPTIMIZATION_NONE=y CONFIG_COMPILER_OPTIMIZATION_NONE=y
CONFIG_PARLIO_ISR_IRAM_SAFE=y CONFIG_PARLIO_TX_ISR_CACHE_SAFE=y
CONFIG_PARLIO_RX_ISR_CACHE_SAFE=y
# place non-ISR FreeRTOS functions in Flash # place non-ISR FreeRTOS functions in Flash
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
# silent the error check, as the error string are stored in rodata, causing RTL check failure # silent the error check, as the error string are stored in rodata, causing RTL check failure

View File

@ -166,7 +166,7 @@ static inline void bitscrambler_ll_set_cond_mode(bitscrambler_dev_t *hw, bitscra
*/ */
static inline void bitscrambler_ll_enable_prefetch_on_reset(bitscrambler_dev_t *hw, bitscrambler_direction_t dir, bool en) static inline void bitscrambler_ll_enable_prefetch_on_reset(bitscrambler_dev_t *hw, bitscrambler_direction_t dir, bool en)
{ {
// 0: means do prefetch on reset, 1: means no reset prefetch, user has to load the instruction manually in the assembly code // 0: means do data prefetch on reset, 1: means no reset prefetch, user has to load the data manually in the assembly code
hw->ctrl[dir].fetch_mode = en ? 0 : 1; hw->ctrl[dir].fetch_mode = en ? 0 : 1;
} }

View File

@ -166,7 +166,7 @@ static inline void bitscrambler_ll_set_cond_mode(bitscrambler_dev_t *hw, bitscra
*/ */
static inline void bitscrambler_ll_enable_prefetch_on_reset(bitscrambler_dev_t *hw, bitscrambler_direction_t dir, bool en) static inline void bitscrambler_ll_enable_prefetch_on_reset(bitscrambler_dev_t *hw, bitscrambler_direction_t dir, bool en)
{ {
// 0: means do prefetch on reset, 1: means no reset prefetch, user has to load the instruction manually in the assembly code // 0: means do data prefetch on reset, 1: means no reset prefetch, user has to load the data manually in the assembly code
hw->ctrl[dir].fetch_mode = en ? 0 : 1; hw->ctrl[dir].fetch_mode = en ? 0 : 1;
} }

View File

@ -71,7 +71,6 @@
#define SOC_ASSIST_DEBUG_SUPPORTED 1 #define SOC_ASSIST_DEBUG_SUPPORTED 1
#define SOC_WDT_SUPPORTED 1 #define SOC_WDT_SUPPORTED 1
#define SOC_SPI_FLASH_SUPPORTED 1 // TODO: [ESP32C5] IDF-8715 #define SOC_SPI_FLASH_SUPPORTED 1 // TODO: [ESP32C5] IDF-8715
// #define SOC_BITSCRAMBLER_SUPPORTED 1 // TODO: [ESP32C5] IDF-8711
#define SOC_ECDSA_SUPPORTED 1 #define SOC_ECDSA_SUPPORTED 1
#define SOC_RNG_SUPPORTED 1 #define SOC_RNG_SUPPORTED 1
// #define SOC_KEY_MANAGER_SUPPORTED 1 // TODO: [ESP32C5] IDF-8621 // #define SOC_KEY_MANAGER_SUPPORTED 1 // TODO: [ESP32C5] IDF-8621

View File

@ -336,7 +336,6 @@
// #define SOC_PARLIO_RX_UNITS_PER_GROUP 1U /*!< number of RX units in each group */ // #define SOC_PARLIO_RX_UNITS_PER_GROUP 1U /*!< number of RX units in each group */
// #define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 8 /*!< Number of data lines of the TX unit */ // #define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 8 /*!< Number of data lines of the TX unit */
// #define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 8 /*!< Number of data lines of the RX unit */ // #define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 8 /*!< Number of data lines of the RX unit */
// #define SOC_PARLIO_TX_RX_SHARE_INTERRUPT 1 /*!< TX and RX unit share the same interrupt source number */
/*--------------------------- MPI CAPS ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/
// #define SOC_MPI_MEM_BLOCKS_NUM (4) // #define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@ -26,11 +26,7 @@ extern "C" {
#else #else
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) #define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED)
#endif #endif
#if CONFIG_PARLIO_ISR_IRAM_SAFE
#define ESP_PROBE_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #define ESP_PROBE_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else
#define ESP_PROBE_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif
#define ESP_PROBE_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) #define ESP_PROBE_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
struct esp_probe_t { struct esp_probe_t {