feat(parlio_rx): support parlio rx on p4

This commit is contained in:
laokaiyao
2024-01-23 19:39:51 +08:00
parent 3f632df143
commit dcc7cf9379
19 changed files with 238 additions and 91 deletions

View File

@ -48,6 +48,8 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
} }
// hal layer initialize // hal layer initialize
parlio_hal_init(&group->hal); parlio_hal_init(&group->hal);
group->dma_align = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
group->dma_align = group->dma_align < 4 ? 4 : group->dma_align;
} }
} else { // group already install } else { // group already install
group = s_platform.groups[group_id]; group = s_platform.groups[group_id];

View File

@ -30,6 +30,7 @@
#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)
#if SOC_PARLIO_TX_RX_SHARE_INTERRUPT #if SOC_PARLIO_TX_RX_SHARE_INTERRUPT
#define PARLIO_INTR_ALLOC_FLAG_SHARED ESP_INTR_FLAG_SHARED #define PARLIO_INTR_ALLOC_FLAG_SHARED ESP_INTR_FLAG_SHARED
@ -57,6 +58,12 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t;
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) #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
#ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR #ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR
/* The descriptor address can be mapped by a fixed offset */ /* The descriptor address can be mapped by a fixed offset */
#define PARLIO_GET_NON_CACHED_DESC_ADDR(desc) (desc ? (parlio_dma_desc_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(desc)) : NULL) #define PARLIO_GET_NON_CACHED_DESC_ADDR(desc) (desc ? (parlio_dma_desc_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(desc)) : NULL)
@ -107,11 +114,12 @@ typedef enum {
typedef struct parlio_unit_t *parlio_unit_base_handle_t; typedef struct parlio_unit_t *parlio_unit_base_handle_t;
typedef struct parlio_group_t { typedef struct parlio_group_t {
int group_id; // group ID, index from 0 int group_id; // group ID, index from 0
portMUX_TYPE spinlock; // to protect per-group register level concurrent access portMUX_TYPE spinlock; // to protect per-group register level concurrent access
parlio_hal_context_t hal; // hal layer context parlio_hal_context_t hal; // hal layer context
parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles uint32_t dma_align; // DMA buffer alignment
parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles
parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles
} parlio_group_t; } parlio_group_t;
/** /**

View File

@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -33,7 +33,9 @@
#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"
#include "esp_dma_utils.h"
#include "esp_private/gdma.h" #include "esp_private/gdma.h"
#include "esp_cache.h"
static const char *TAG = "parlio-rx"; static const char *TAG = "parlio-rx";
@ -81,8 +83,9 @@ typedef struct parlio_rx_unit_t {
gdma_channel_handle_t dma_chan; /*!< DMA channel */ gdma_channel_handle_t dma_chan; /*!< DMA channel */
size_t max_recv_size; /*!< Maximum receive size for a normal transaction */ size_t max_recv_size; /*!< Maximum receive size for a normal transaction */
size_t desc_num; /*!< DMA descriptor number */ size_t desc_num; /*!< DMA descriptor number */
dma_descriptor_t *dma_descs; /*!< DMA descriptor array pointer */ size_t desc_size; /*!< DMA descriptors total size */
dma_descriptor_t *curr_desc; /*!< The pointer of the current descriptor */ parlio_dma_desc_t **dma_descs; /*!< DMA descriptor array pointer */
parlio_dma_desc_t *curr_desc; /*!< The pointer of the current descriptor */
void *usr_recv_buf; /*!< The pointe to the user's receiving buffer */ void *usr_recv_buf; /*!< The pointe to the user's receiving buffer */
/* Infinite transaction specific */ /* Infinite transaction specific */
void *dma_buf; /*!< Additional internal DMA buffer only for infinite transactions */ void *dma_buf; /*!< Additional internal DMA buffer only for infinite transactions */
@ -125,19 +128,21 @@ typedef struct parlio_rx_delimiter_t {
} flags; } flags;
} parlio_rx_delimiter_t; } parlio_rx_delimiter_t;
#define PRALIO_RX_MOUNT_SIZE_CALC(total_size, div, align) ((((total_size) / (align)) / (div)) * (align))
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) static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans)
{ {
dma_descriptor_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 */
memcpy(&rx_unit->curr_trans, trans, sizeof(parlio_rx_transaction_t)); memcpy(&rx_unit->curr_trans, trans, sizeof(parlio_rx_transaction_t));
portENTER_CRITICAL_SAFE(&s_rx_spinlock); portENTER_CRITICAL_SAFE(&s_rx_spinlock);
trans->delimiter->under_using = true; trans->delimiter->under_using = true;
portEXIT_CRITICAL_SAFE(&s_rx_spinlock); portEXIT_CRITICAL_SAFE(&s_rx_spinlock);
uint32_t desc_num = trans->size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; uint32_t desc_num = trans->size / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE;
uint32_t remain_num = trans->size % DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; uint32_t remain_num = trans->size % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE;
/* If there are still data remained, need one more descriptor */ /* If there are still data remained, need one more descriptor */
desc_num += remain_num ? 1 : 0; desc_num += remain_num ? 1 : 0;
if (trans->flags.infinite && desc_num < 2) { if (trans->flags.infinite && desc_num < 2) {
@ -146,30 +151,40 @@ static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_
} }
size_t mount_size = 0; size_t mount_size = 0;
size_t offset = 0; size_t offset = 0;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
uint32_t alignment = rx_unit->base.group->dma_align;
#else
uint32_t alignment = 4;
#endif
/* Loop the descriptors to assign the data */ /* Loop the descriptors to assign the data */
for (int i = 0; i < desc_num; i++) { for (int i = 0; i < desc_num; i++) {
size_t rest_size = trans->size - offset; size_t rest_size = trans->size - offset;
if (rest_size >= 2 * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
mount_size = trans->size / desc_num; if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) {
} else if (rest_size <= DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) { mount_size = PRALIO_RX_MOUNT_SIZE_CALC(trans->size, desc_num, alignment);
mount_size = (desc_num == 2) && (i == 0) ? rest_size / 2 : rest_size; } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) {
mount_size = (desc_num == 2) && (i == 0) ? PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment) : rest_size;
} else { } else {
mount_size = rest_size / 2; mount_size = PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment);
} }
p_desc[i].buffer = (void *)((uint8_t *)trans->payload + offset); p_desc[i]->buffer = (void *)((uint8_t *)trans->payload + offset);
p_desc[i].dw0.size = mount_size; p_desc[i]->dw0.size = mount_size;
p_desc[i].dw0.length = mount_size; p_desc[i]->dw0.length = mount_size;
p_desc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; p_desc[i]->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
// Link the descriptor // Link the descriptor
if (i > 0) { if (i < desc_num - 1) {
p_desc[i - 1].next = &p_desc[i]; p_desc[i]->next = p_desc[i + 1];
} else {
/* For infinite transaction, link the descriptor as a ring */
p_desc[i]->next = trans->flags.infinite ? p_desc[0] : NULL;
} }
offset += mount_size; offset += mount_size;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(p_desc[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
} }
/* For infinite transaction, link the descriptor as a ring */
p_desc[desc_num - 1].next = trans->flags.infinite ? &p_desc[0] : NULL;
/* Reset the current DMA node */ /* Reset the current DMA node */
rx_unit->curr_desc = p_desc; rx_unit->curr_desc = p_desc[0];
return offset; return offset;
} }
@ -251,6 +266,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
gpio_conf.mode = config->flags.io_loop_back ? GPIO_MODE_INPUT_OUTPUT : GPIO_MODE_INPUT; gpio_conf.mode = config->flags.io_loop_back ? GPIO_MODE_INPUT_OUTPUT : GPIO_MODE_INPUT;
gpio_conf.pin_bit_mask = BIT64(config->clk_in_gpio_num); gpio_conf.pin_bit_mask = BIT64(config->clk_in_gpio_num);
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config clk in GPIO failed"); ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config clk in GPIO failed");
} else {
gpio_ll_input_enable(&GPIO, config->clk_in_gpio_num);
} }
esp_rom_gpio_connect_in_signal(config->clk_in_gpio_num, esp_rom_gpio_connect_in_signal(config->clk_in_gpio_num,
parlio_periph_signals.groups[group_id].rx_units[unit_id].clk_in_sig, false); parlio_periph_signals.groups[group_id].rx_units[unit_id].clk_in_sig, false);
@ -275,6 +292,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
if (!config->flags.io_no_init) { if (!config->flags.io_no_init) {
gpio_conf.pin_bit_mask = BIT64(config->valid_gpio_num); gpio_conf.pin_bit_mask = BIT64(config->valid_gpio_num);
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed"); ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed");
} else {
gpio_ll_input_enable(&GPIO, config->valid_gpio_num);
} }
/* Not connect the signal here, the signal is lazy connected until the delimiter takes effect */ /* Not connect the signal here, the signal is lazy connected until the delimiter takes effect */
} }
@ -286,7 +305,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
if (!config->flags.io_no_init) { if (!config->flags.io_no_init) {
gpio_conf.pin_bit_mask = BIT64(config->data_gpio_nums[i]); gpio_conf.pin_bit_mask = BIT64(config->data_gpio_nums[i]);
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed"); ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed");
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->data_gpio_nums[i]], PIN_FUNC_GPIO); } else {
gpio_ll_input_enable(&GPIO, config->data_gpio_nums[i]);
} }
esp_rom_gpio_connect_in_signal(config->data_gpio_nums[i], esp_rom_gpio_connect_in_signal(config->data_gpio_nums[i],
parlio_periph_signals.groups[group_id].rx_units[unit_id].data_sigs[i], false); parlio_periph_signals.groups[group_id].rx_units[unit_id].data_sigs[i], false);
@ -330,18 +350,22 @@ static IRAM_ATTR bool s_parlio_rx_default_eof_callback(gdma_channel_handle_t dma
/* The current transaction finished, try to get the next transaction from the transaction queue */ /* The current transaction finished, try to get the next transaction from the transaction queue */
if (xQueueReceiveFromISR(rx_unit->trans_que, &next_trans, &high_task_woken) == pdTRUE) { if (xQueueReceiveFromISR(rx_unit->trans_que, &next_trans, &high_task_woken) == pdTRUE) {
if (rx_unit->cfg.flags.free_clk) { if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false);
}
} }
/* 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 != 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); s_parlio_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); s_parlio_mount_transaction_buffer(rx_unit, &next_trans);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs); 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);
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true);
}
} }
} else if (rx_unit->curr_trans.delimiter) { // Add condition in case the curr_trans has been cleared in the last timeout isr } else if (rx_unit->curr_trans.delimiter) { // Add condition in case the curr_trans has been cleared in the last timeout isr
/* No more transaction pending to receive, clear the current transaction */ /* No more transaction pending to receive, clear the current transaction */
@ -368,7 +392,15 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle
} }
/* Get the finished descriptor from the current descriptor */ /* Get the finished descriptor from the current descriptor */
dma_descriptor_t *finished_desc = rx_unit->curr_desc; parlio_dma_desc_t *finished_desc = rx_unit->curr_desc;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_err_t ret = ESP_OK;
ret |= esp_cache_msync((void *)finished_desc, rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
ret |= esp_cache_msync((void *)(finished_desc->buffer), finished_desc->dw0.size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
if (ret != ESP_OK) {
ESP_EARLY_LOGW(TAG, "failed to sync dma buffer from memory to cache");
}
#endif
parlio_rx_event_data_t evt_data = { parlio_rx_event_data_t evt_data = {
.delimiter = rx_unit->curr_trans.delimiter, .delimiter = rx_unit->curr_trans.delimiter,
.data = finished_desc->buffer, .data = finished_desc->buffer,
@ -399,21 +431,41 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle
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 s_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;
uint32_t desc_num = max_recv_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED + 1; uint32_t desc_num = max_recv_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED + 1;
/* set at least 2 descriptors */ /* set at least 2 descriptors */
if (desc_num < 2) { if (desc_num < 2) {
desc_num = 4; desc_num = 2;
} }
rx_unit->desc_num = desc_num; rx_unit->desc_num = desc_num;
/* Allocated and link the descriptor nodes */ /* Allocated and link the descriptor nodes */
rx_unit->dma_descs = (dma_descriptor_t *)heap_caps_calloc(desc_num, sizeof(dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); rx_unit->dma_descs = heap_caps_calloc(desc_num, sizeof(parlio_dma_desc_t *), MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptors"); ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptor array");
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
size_t alignment = MAX(cache_line_size, PARLIO_DMA_DESC_ALIGNMENT);
rx_unit->desc_size = ALIGN_UP(sizeof(parlio_dma_desc_t), alignment);
for (int i = 0; i < desc_num; i++) {
rx_unit->dma_descs[i] = heap_caps_aligned_calloc(alignment, 1, rx_unit->desc_size, PARLIO_DMA_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(rx_unit->dma_descs[i], ESP_ERR_NO_MEM, err, TAG, "no memory for DMA descriptors");
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(rx_unit->dma_descs[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
}
rx_unit->max_recv_size = max_recv_size; rx_unit->max_recv_size = max_recv_size;
return ESP_OK; return ret;
err:
for (int i = 0; i < desc_num; i++) {
if (rx_unit->dma_descs[i]) {
free(rx_unit->dma_descs[i]);
rx_unit->dma_descs[i] = NULL;
}
}
free(rx_unit->dma_descs);
rx_unit->dma_descs = NULL;
return ret;
} }
static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit)
@ -422,7 +474,7 @@ static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit)
gdma_channel_alloc_config_t dma_chan_config = { gdma_channel_alloc_config_t dma_chan_config = {
.direction = GDMA_CHANNEL_DIRECTION_RX, .direction = GDMA_CHANNEL_DIRECTION_RX,
}; };
ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed"); ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed");
gdma_connect(rx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0)); gdma_connect(rx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0));
/* Set GDMA strategy */ /* Set GDMA strategy */
@ -487,8 +539,10 @@ static esp_err_t s_parlio_select_periph_clock(parlio_rx_unit_handle_t rx_unit, c
#endif #endif
/* Set clock configuration */ /* Set clock configuration */
parlio_ll_rx_set_clock_source(hal->regs, clk_src); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_set_clock_div(hal->regs, &clk_div); parlio_ll_rx_set_clock_source(hal->regs, clk_src);
parlio_ll_rx_set_clock_div(hal->regs, &clk_div);
}
rx_unit->clk_src = clk_src; rx_unit->clk_src = clk_src;
/* warning if precision lost due to division */ /* warning if precision lost due to division */
@ -525,7 +579,14 @@ static esp_err_t s_parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit)
} }
/* Free the DMA descriptors */ /* Free the DMA descriptors */
if (rx_unit->dma_descs) { if (rx_unit->dma_descs) {
for (int i = 0; i < rx_unit->desc_num; i++) {
if (rx_unit->dma_descs[i]) {
free(rx_unit->dma_descs[i]);
rx_unit->dma_descs[i] = NULL;
}
}
free(rx_unit->dma_descs); free(rx_unit->dma_descs);
rx_unit->dma_descs = NULL;
} }
/* Free the internal DMA buffer */ /* Free the internal DMA buffer */
if (rx_unit->dma_buf) { if (rx_unit->dma_buf) {
@ -591,9 +652,13 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
/* 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(s_parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed");
/* Reset RX module */ /* Reset RX module */
parlio_ll_rx_reset_clock(hal->regs); PARLIO_RCC_ATOMIC() {
parlio_ll_rx_reset_clock(hal->regs);
}
parlio_ll_rx_reset_fifo(hal->regs); parlio_ll_rx_reset_fifo(hal->regs);
parlio_ll_rx_enable_clock(hal->regs, false); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, false);
}
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(s_parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed");
@ -651,7 +716,9 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu
if (!rx_unit->cfg.flags.free_clk) { if (!rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_reset_fifo(hal->regs); parlio_ll_rx_reset_fifo(hal->regs);
parlio_ll_rx_start(hal->regs, true); parlio_ll_rx_start(hal->regs, true);
parlio_ll_rx_enable_clock(hal->regs, true); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, true);
}
} }
/* Check if we need to start a pending transaction */ /* Check if we need to start a pending transaction */
@ -663,14 +730,18 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu
// The semaphore always supposed to be taken successfully // The semaphore always supposed to be taken successfully
assert(xSemaphoreTake(rx_unit->trans_sem, 0) == pdTRUE); assert(xSemaphoreTake(rx_unit->trans_sem, 0) == pdTRUE);
if (rx_unit->cfg.flags.free_clk) { if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_enable_clock(hal->regs, false); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, false);
}
} }
s_parlio_set_delimiter_config(rx_unit, trans.delimiter); s_parlio_set_delimiter_config(rx_unit, trans.delimiter);
s_parlio_mount_transaction_buffer(rx_unit, &trans); s_parlio_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);
parlio_ll_rx_enable_clock(hal->regs, true); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, true);
}
} }
} }
err: err:
@ -691,7 +762,9 @@ esp_err_t parlio_rx_unit_disable(parlio_rx_unit_handle_t rx_unit)
rx_unit->is_enabled = false; rx_unit->is_enabled = false;
/* stop the RX engine */ /* stop the RX engine */
gdma_stop(rx_unit->dma_chan); gdma_stop(rx_unit->dma_chan);
parlio_ll_rx_enable_clock(hal->regs, false); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, false);
}
parlio_ll_rx_start(hal->regs, false); parlio_ll_rx_start(hal->regs, false);
if (rx_unit->curr_trans.delimiter) { if (rx_unit->curr_trans.delimiter) {
portENTER_CRITICAL(&s_rx_spinlock); portENTER_CRITICAL(&s_rx_spinlock);
@ -842,7 +915,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit
portEXIT_CRITICAL_ISR(&s_rx_spinlock); portEXIT_CRITICAL_ISR(&s_rx_spinlock);
if (is_stopped) { if (is_stopped) {
if (rx_unit->cfg.flags.free_clk) { if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false);
}
} }
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); s_parlio_set_delimiter_config(rx_unit, trans->delimiter);
@ -853,7 +928,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit
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(rx_unit->base.group->hal.regs, true); parlio_ll_rx_start(rx_unit->base.group->hal.regs, true);
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true); PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true);
}
} }
} else { // Otherwise send to the queue } else { // Otherwise send to the queue
/* Send the transaction to the queue */ /* Send the transaction to the queue */
@ -871,8 +948,17 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit,
ESP_RETURN_ON_FALSE(rx_unit && payload && recv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(rx_unit && payload && recv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified"); ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified");
ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large"); ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large");
uint32_t alignment = rx_unit->base.group->dma_align;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
ESP_RETURN_ON_FALSE(payload_size % alignment == 0, ESP_ERR_INVALID_ARG, TAG, "The payload size should align with %"PRIu32, alignment);
if (recv_cfg->flags.partial_rx_en) {
ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment);
}
#endif
#if CONFIG_GDMA_ISR_IRAM_SAFE #if CONFIG_GDMA_ISR_IRAM_SAFE
ESP_RETURN_ON_FALSE(esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM"); ESP_RETURN_ON_FALSE(esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM");
#else
ESP_RETURN_ON_FALSE(recv_cfg->flags.indirect_mount || esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM");
#endif #endif
if (recv_cfg->delimiter->eof_data_len) { if (recv_cfg->delimiter->eof_data_len) {
ESP_RETURN_ON_FALSE(payload_size >= recv_cfg->delimiter->eof_data_len, ESP_ERR_INVALID_ARG, ESP_RETURN_ON_FALSE(payload_size >= recv_cfg->delimiter->eof_data_len, ESP_ERR_INVALID_ARG,
@ -895,7 +981,7 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit,
if (recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount) { if (recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount) {
ESP_RETURN_ON_FALSE(!rx_unit->dma_buf, ESP_ERR_INVALID_STATE, TAG, "infinite transaction is using the internal DMA buffer"); ESP_RETURN_ON_FALSE(!rx_unit->dma_buf, ESP_ERR_INVALID_STATE, TAG, "infinite transaction is using the internal DMA buffer");
/* Allocate the internal DMA buffer to store the data temporary */ /* Allocate the internal DMA buffer to store the data temporary */
rx_unit->dma_buf = heap_caps_calloc(1, payload_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); rx_unit->dma_buf = heap_caps_aligned_calloc(alignment, 1, payload_size, PARLIO_DMA_MEM_ALLOC_CAPS);
ESP_RETURN_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, TAG, "No memory for the internal DMA buffer"); ESP_RETURN_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, TAG, "No memory for the internal DMA buffer");
/* Use the internal DMA buffer so that the user buffer can always be available */ /* Use the internal DMA buffer so that the user buffer can always be available */
p_buffer = rx_unit->dma_buf; p_buffer = rx_unit->dma_buf;

View File

@ -405,7 +405,7 @@ static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_tx_unit_t *tx_unit, const
#if CONFIG_IDF_TARGET_ESP32P4 #if CONFIG_IDF_TARGET_ESP32P4
// Write back to cache to synchronize the cache before DMA start // Write back to cache to synchronize the cache before DMA start
esp_cache_msync(buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); esp_cache_msync((void *)buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif // CONFIG_IDF_TARGET_ESP32P4 #endif // CONFIG_IDF_TARGET_ESP32P4
} }

View File

@ -4,8 +4,8 @@ components/esp_driver_parlio/test_apps/parlio:
disable: disable:
- if: SOC_PARLIO_SUPPORTED != 1 - if: SOC_PARLIO_SUPPORTED != 1
disable_test: disable_test:
- if: IDF_TARGET == "esp32p4" - if: IDF_TARGET in ["esp32h2", "esp32p4"]
temporary: true temporary: true
reason: lack of runner reason: IDF-9806 waiting for the fix of the bit shift issue after reset
depends_components: depends_components:
- esp_driver_parlio - esp_driver_parlio

View File

@ -1,2 +1,2 @@
| Supported Targets | ESP32-C6 | ESP32-H2 | | Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | | ----------------- | -------- | -------- | -------- |

View File

@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -18,6 +18,7 @@ extern "C" {
#define TEST_PARLIO_CALLBACK_ATTR #define TEST_PARLIO_CALLBACK_ATTR
#define TEST_PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #define TEST_PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif #endif
#define TEST_PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#if CONFIG_IDF_TARGET_ESP32C6 #if CONFIG_IDF_TARGET_ESP32C6
#define TEST_CLK_GPIO 10 #define TEST_CLK_GPIO 10
@ -42,15 +43,16 @@ extern "C" {
#define TEST_DATA6_GPIO 8 #define TEST_DATA6_GPIO 8
#define TEST_DATA7_GPIO 9 #define TEST_DATA7_GPIO 9
#elif CONFIG_IDF_TARGET_ESP32P4 #elif CONFIG_IDF_TARGET_ESP32P4
#define TEST_CLK_GPIO 20 #define TEST_CLK_GPIO 32
#define TEST_DATA0_GPIO 21 #define TEST_VALID_GPIO 36
#define TEST_DATA1_GPIO 22 #define TEST_DATA0_GPIO 20
#define TEST_DATA2_GPIO 34 #define TEST_DATA1_GPIO 21
#define TEST_DATA3_GPIO 35 #define TEST_DATA2_GPIO 22
#define TEST_DATA4_GPIO 48 #define TEST_DATA3_GPIO 23
#define TEST_DATA5_GPIO 49 #define TEST_DATA4_GPIO 45
#define TEST_DATA6_GPIO 10 #define TEST_DATA5_GPIO 46
#define TEST_DATA7_GPIO 11 #define TEST_DATA6_GPIO 47
#define TEST_DATA7_GPIO 48
#else #else
#error "Unsupported target" #error "Unsupported target"
#endif #endif

View File

@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -17,16 +17,26 @@
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/i2s_periph.h" #include "soc/i2s_periph.h"
#include "soc/spi_periph.h" #include "soc/spi_periph.h"
#include "soc/parlio_periph.h" #include "soc/parlio_periph.h"
#include "esp_dma_utils.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "test_board.h" #include "test_board.h"
#define TEST_SPI_HOST SPI2_HOST #define TEST_SPI_HOST SPI2_HOST
#define TEST_I2S_PORT I2S_NUM_0 #define TEST_I2S_PORT I2S_NUM_0
#define TEST_VALID_SIG (PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1) #define TEST_VALID_SIG (PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1)
#if SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT
#define TEST_OUTPUT_CLK_PIN TEST_CLK_GPIO
#else
#define TEST_OUTPUT_CLK_PIN -1
#endif
#define TEST_DEFAULT_UNIT_CONFIG(_clk_src, _clk_freq) { \ #define TEST_DEFAULT_UNIT_CONFIG(_clk_src, _clk_freq) { \
.trans_queue_depth = 10, \ .trans_queue_depth = 10, \
.max_recv_size = 10 * 1024, \ .max_recv_size = 10 * 1024, \
@ -35,7 +45,7 @@
.ext_clk_freq_hz = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? _clk_freq : 0, \ .ext_clk_freq_hz = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? _clk_freq : 0, \
.clk_in_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? TEST_CLK_GPIO : -1, \ .clk_in_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? TEST_CLK_GPIO : -1, \
.exp_clk_freq_hz = _clk_freq, \ .exp_clk_freq_hz = _clk_freq, \
.clk_out_gpio_num = -1, \ .clk_out_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? -1 : TEST_OUTPUT_CLK_PIN, \
.valid_gpio_num = TEST_VALID_GPIO, \ .valid_gpio_num = TEST_VALID_GPIO, \
.data_gpio_nums = { \ .data_gpio_nums = { \
[0] = TEST_DATA0_GPIO, \ [0] = TEST_DATA0_GPIO, \
@ -56,6 +66,10 @@ typedef struct {
uint32_t timeout_cnt; uint32_t timeout_cnt;
} test_data_t; } test_data_t;
#ifndef ALIGN_UP
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#endif
TEST_PARLIO_CALLBACK_ATTR TEST_PARLIO_CALLBACK_ATTR
static bool test_parlio_rx_partial_recv_callback(parlio_rx_unit_handle_t rx_unit, const parlio_rx_event_data_t *edata, void *user_data) static bool test_parlio_rx_partial_recv_callback(parlio_rx_unit_handle_t rx_unit, const parlio_rx_event_data_t *edata, void *user_data)
{ {
@ -285,11 +299,15 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_
.delimiter = deli, .delimiter = deli,
.flags.partial_rx_en = false, .flags.partial_rx_en = false,
}; };
uint8_t recv_buff[TEST_EOF_DATA_LEN]; uint8_t *recv_buff = NULL;
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t buff_size = ALIGN_UP(TEST_EOF_DATA_LEN, alignment);
recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS);
bool is_success = false; bool is_success = false;
// sample 5 times // sample 5 times
for (int i = 0; i < 5 && !is_success; i++) { for (int i = 0; i < 5 && !is_success; i++) {
TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, TEST_EOF_DATA_LEN, &recv_config)); TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, buff_size, &recv_config));
TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000)); TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000));
for (int k = 0; k < TEST_EOF_DATA_LEN; k++) { for (int k = 0; k < TEST_EOF_DATA_LEN; k++) {
printf("%x ", recv_buff[k]); printf("%x ", recv_buff[k]);
@ -315,6 +333,7 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_
} }
// Delete the sender task // Delete the sender task
vTaskDelete(sender_task); vTaskDelete(sender_task);
free(recv_buff);
TEST_ESP_OK(parlio_rx_unit_disable(rx_unit)); TEST_ESP_OK(parlio_rx_unit_disable(rx_unit));
TEST_ESP_OK(parlio_del_rx_unit(rx_unit)); TEST_ESP_OK(parlio_del_rx_unit(rx_unit));
@ -409,8 +428,7 @@ TEST_CASE("parallel_rx_unit_install_uninstall", "[parlio_rx]")
TEST_ESP_OK(parlio_rx_unit_disable(units[0])); TEST_ESP_OK(parlio_rx_unit_disable(units[0]));
TEST_ESP_OK(parlio_del_rx_unit(units[0])); TEST_ESP_OK(parlio_del_rx_unit(units[0]));
} }
#define TEST_PAYLOAD_SIZE 5120
#define TEST_PAYLOAD_SIZE 5000
// This test case uses soft delimiter // This test case uses soft delimiter
TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]")
@ -444,7 +462,11 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]")
.delimiter = deli, .delimiter = deli,
.flags.partial_rx_en = false, .flags.partial_rx_en = false,
}; };
uint8_t *payload = heap_caps_calloc(1, TEST_PAYLOAD_SIZE, TEST_PARLIO_MEM_ALLOC_CAPS); uint8_t *payload = NULL;
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t payload_size = ALIGN_UP(TEST_PAYLOAD_SIZE, alignment);
payload = heap_caps_aligned_calloc(alignment, 1, payload_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS);
TEST_ASSERT(payload); TEST_ASSERT(payload);
printf("Testing one normal transaction...\n"); printf("Testing one normal transaction...\n");
@ -535,7 +557,11 @@ TEST_CASE("parallel_rx_unit_receive_timeout_test", "[parlio_rx]")
.delimiter = timeout_deli, .delimiter = timeout_deli,
.flags.partial_rx_en = false, .flags.partial_rx_en = false,
}; };
uint8_t *payload = heap_caps_calloc(1, TEST_PAYLOAD_SIZE, TEST_PARLIO_MEM_ALLOC_CAPS); uint8_t *payload = NULL;
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t payload_size = ALIGN_UP(TEST_PAYLOAD_SIZE, alignment);
payload = heap_caps_aligned_calloc(alignment, 1, payload_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS);
TEST_ASSERT(payload); TEST_ASSERT(payload);
printf("Testing the timeout callback...\n"); printf("Testing the timeout callback...\n");

View File

@ -1,12 +1,10 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2023 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
@pytest.mark.esp32c6 @pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.generic @pytest.mark.generic
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',

View File

@ -213,13 +213,13 @@ static inline void parlio_ll_rx_set_recv_bit_len(parl_io_dev_t *dev, uint32_t bi
* @brief Set the sub mode of the level controlled receive mode * @brief Set the sub mode of the level controlled receive mode
* *
* @param dev Parallel IO register base address * @param dev Parallel IO register base address
* @param active_level Level of the external enable signal, true for active high, false for active low * @param active_low_en Level of the external enable signal, true for active low, false for active high
*/ */
__attribute__((always_inline)) __attribute__((always_inline))
static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_level) static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_low_en)
{ {
dev->rx_mode_cfg.rx_smp_mode_sel = 0; dev->rx_mode_cfg.rx_smp_mode_sel = 0;
dev->rx_mode_cfg.rx_ext_en_inv = !active_level; // 0: active low, 1: active high dev->rx_mode_cfg.rx_ext_en_inv = active_low_en;
} }
/** /**
@ -359,7 +359,7 @@ static inline void parlio_ll_rx_treat_data_line_as_en(parl_io_dev_t *dev, uint32
} }
/** /**
* @brief Wether to enable the RX clock gating * @brief whether to enable the RX clock gating
* *
* @param dev Parallel IO register base address * @param dev Parallel IO register base address
* @param en True to enable, False to disable * @param en True to enable, False to disable
@ -519,7 +519,7 @@ static inline void parlio_ll_tx_set_eof_condition(parl_io_dev_t *dev, parlio_ll_
} }
/** /**
* @brief Wether to enable the TX clock gating * @brief whether to enable the TX clock gating
* *
* @note The MSB of TXD will be taken as the gating enable signal * @note The MSB of TXD will be taken as the gating enable signal
* *
@ -589,7 +589,6 @@ static inline void parlio_ll_tx_set_bus_width(parl_io_dev_t *dev, uint32_t width
{ {
uint32_t width_sel = 0; uint32_t width_sel = 0;
switch (width) { switch (width) {
// TODO: check this field (IDF-8284)
case 16: case 16:
width_sel = 4; width_sel = 4;
break; break;

View File

@ -58,6 +58,7 @@ ESP_STATIC_ASSERT(sizeof(dma_descriptor_align8_t) == 16, "dma_descriptor_align8_
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */ #define DMA_DESCRIPTOR_BUFFER_MAX_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED (4095-3) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 4B */ #define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED (4095-3) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 4B */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_16B_ALIGNED (4095-15) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 16B */ #define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_16B_ALIGNED (4095-15) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 16B */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED (4095-63) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 64B */
/** /**
* Get the number of DMA descriptors required for a given buffer size. * Get the number of DMA descriptors required for a given buffer size.

View File

@ -63,6 +63,10 @@ config SOC_ETM_SUPPORTED
bool bool
default y default y
config SOC_PARLIO_SUPPORTED
bool
default y
config SOC_ASYNC_MEMCPY_SUPPORTED config SOC_ASYNC_MEMCPY_SUPPORTED
bool bool
default y default y
@ -991,6 +995,10 @@ config SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH
int int
default 16 default 16
config SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT
bool
default y
config SOC_PARLIO_TX_SIZE_BY_DMA config SOC_PARLIO_TX_SIZE_BY_DMA
bool bool
default y default y

View File

@ -635,8 +635,8 @@ typedef enum {
*/ */
typedef enum { typedef enum {
PARLIO_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ PARLIO_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
PARLIO_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ PARLIO_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
PARLIO_CLK_SRC_EXTERNAL = -1, /*!< Select EXTERNAL clock as the source clock */ PARLIO_CLK_SRC_EXTERNAL = -1, /*!< Select EXTERNAL clock as the source clock */
PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
} soc_periph_parlio_clk_src_t; } soc_periph_parlio_clk_src_t;

View File

@ -34,7 +34,7 @@
#define SOC_MCPWM_SUPPORTED 1 #define SOC_MCPWM_SUPPORTED 1
#define SOC_TWAI_SUPPORTED 1 #define SOC_TWAI_SUPPORTED 1
#define SOC_ETM_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1
// #define SOC_PARLIO_SUPPORTED 1 //TODO: IDF-7471 #define SOC_PARLIO_SUPPORTED 1
#define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1
#define SOC_EMAC_SUPPORTED 1 #define SOC_EMAC_SUPPORTED 1
#define SOC_USB_OTG_SUPPORTED 1 #define SOC_USB_OTG_SUPPORTED 1
@ -393,6 +393,7 @@
#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 16 /*!< Number of data lines of the TX unit */ #define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */
#define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */ #define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */
#define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */ #define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */
/*--------------------------- MPI CAPS ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/

View File

@ -261,9 +261,11 @@ examples/peripherals/parlio:
examples/peripherals/parlio/parlio_rx: examples/peripherals/parlio/parlio_rx:
disable: disable:
- if: SOC_PARLIO_SUPPORTED != 1 or IDF_TARGET == "esp32p4" - if: SOC_PARLIO_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true temporary: true
reason: not support esp32p4 yet (IDF-7471) reason: lack of runner
depends_components: depends_components:
- esp_driver_parlio - esp_driver_parlio

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32-C6 | ESP32-H2 | | Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | | ----------------- | -------- | -------- | -------- |
# Logic Analyzer Example # Logic Analyzer Example

View File

@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -11,6 +11,8 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "soc/soc_caps.h"
#include "hal/dma_types.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_probe.h" #include "esp_probe.h"
@ -19,12 +21,17 @@ extern "C" {
#endif #endif
#define ESP_PROBE_DEFAULT_Q_DEPTH 8 #define ESP_PROBE_DEFAULT_Q_DEPTH 8
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * 4092) #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED)
#else
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED)
#endif
#if CONFIG_PARLIO_ISR_IRAM_SAFE #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 #else
#define ESP_PROBE_ALLOC_CAPS MALLOC_CAP_DEFAULT #define ESP_PROBE_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif #endif
#define ESP_PROBE_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
struct esp_probe_t { struct esp_probe_t {
uint32_t sample_width; /*!< sample width, i.e., enabled probe channel nums */ uint32_t sample_width; /*!< sample width, i.e., enabled probe channel nums */

View File

@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -8,8 +8,11 @@
#include <string.h> #include <string.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "driver/parlio_rx.h" #include "driver/parlio_rx.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_clk_tree.h" #include "esp_clk_tree.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_dma_utils.h"
#include "esp_check.h" #include "esp_check.h"
#include "esp_probe_private.h" #include "esp_probe_private.h"
@ -43,7 +46,11 @@ esp_err_t esp_probe_priv_init_hardware(esp_probe_handle_t handle, esp_probe_conf
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
s_ephi = calloc(1, sizeof(esp_probe_impl_pralio_t)); s_ephi = calloc(1, sizeof(esp_probe_impl_pralio_t));
ESP_RETURN_ON_FALSE(s_ephi, ESP_ERR_NO_MEM, TAG, "no memory for the esp probe hardware implementation"); ESP_RETURN_ON_FALSE(s_ephi, ESP_ERR_NO_MEM, TAG, "no memory for the esp probe hardware implementation");
s_ephi->payload = heap_caps_calloc(1, ESP_PROBE_DEFAULT_MAX_RECV_SIZE, ESP_PROBE_ALLOC_CAPS);
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t payload_aligned_size = ESP_PROBE_DEFAULT_MAX_RECV_SIZE & ~(alignment - 1);
s_ephi->payload = heap_caps_aligned_calloc(alignment, 1, payload_aligned_size, ESP_PROBE_DMA_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(s_ephi->payload, ESP_ERR_NO_MEM, err, TAG, "no memory for payload"); ESP_GOTO_ON_FALSE(s_ephi->payload, ESP_ERR_NO_MEM, err, TAG, "no memory for payload");
// Get the channel number, the channel number can only be the power of 2 // Get the channel number, the channel number can only be the power of 2

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32-C6 | ESP32-H2 | | Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | | ----------------- | -------- | -------- | -------- |
# Parallel IO TX Example: Simple RGB LED Matrix # Parallel IO TX Example: Simple RGB LED Matrix