feat(parlio_tx): support non-blocking transaction queue

This commit is contained in:
morris
2024-03-14 18:35:25 +08:00
parent e759833c44
commit 1008091a74
4 changed files with 31 additions and 22 deletions

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
*/ */
@@ -150,6 +150,9 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
*/ */
typedef struct { typedef struct {
uint32_t idle_value; /*!< The value on the data line when the parallel IO is in idle state */ uint32_t idle_value; /*!< The value on the data line when the parallel IO is in idle state */
struct {
uint32_t queue_nonblocking : 1; /*!< If set, when the transaction queue is full, driver will not block the thread but return directly */
} flags; /*!< Transmit specific config flags */
} parlio_transmit_config_t; } parlio_transmit_config_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
*/ */
@@ -42,8 +42,6 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
if (group) { if (group) {
new_group = true; new_group = true;
s_platform.groups[group_id] = group; s_platform.groups[group_id] = group;
group->group_id = group_id;
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
PARLIO_RCC_ATOMIC() { PARLIO_RCC_ATOMIC() {
parlio_ll_enable_bus_clock(group_id, true); parlio_ll_enable_bus_clock(group_id, true);
parlio_ll_reset_register(group_id); parlio_ll_reset_register(group_id);
@@ -61,6 +59,8 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
_lock_release(&s_platform.mutex); _lock_release(&s_platform.mutex);
if (new_group) { if (new_group) {
portMUX_INITIALIZE(&group->spinlock);
group->group_id = group_id;
ESP_LOGD(TAG, "new group(%d) at %p", group_id, group); ESP_LOGD(TAG, "new group(%d) at %p", group_id, group);
} }
return group; return group;
@@ -81,11 +81,11 @@ void parlio_release_group_handle(parlio_group_t *group)
PARLIO_RCC_ATOMIC() { PARLIO_RCC_ATOMIC() {
parlio_ll_enable_bus_clock(group_id, false); parlio_ll_enable_bus_clock(group_id, false);
} }
free(group);
} }
_lock_release(&s_platform.mutex); _lock_release(&s_platform.mutex);
if (do_deinitialize) { if (do_deinitialize) {
free(group);
ESP_LOGD(TAG, "del group(%d)", group_id); ESP_LOGD(TAG, "del group(%d)", group_id);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -77,12 +77,12 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t;
extern "C" { extern "C" {
#endif #endif
enum { typedef enum {
PARLIO_TX_QUEUE_READY, PARLIO_TX_QUEUE_READY,
PARLIO_TX_QUEUE_PROGRESS, PARLIO_TX_QUEUE_PROGRESS,
PARLIO_TX_QUEUE_COMPLETE, PARLIO_TX_QUEUE_COMPLETE,
PARLIO_TX_QUEUE_MAX, PARLIO_TX_QUEUE_MAX,
}; } parlio_tx_queue_status_t;
typedef enum { typedef enum {
PARLIO_TX_FSM_INIT_WAIT, PARLIO_TX_FSM_INIT_WAIT,

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
*/ */
@@ -161,7 +161,9 @@ static esp_err_t parlio_destroy_tx_unit(parlio_tx_unit_t *tx_unit)
// de-register from group // de-register from group
parlio_tx_unregister_to_group(tx_unit, tx_unit->group); parlio_tx_unregister_to_group(tx_unit, tx_unit->group);
} }
free(tx_unit->dma_nodes); if (tx_unit->dma_nodes) {
free(tx_unit->dma_nodes);
}
free(tx_unit); free(tx_unit);
return ESP_OK; return ESP_OK;
} }
@@ -287,22 +289,22 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
#endif #endif
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
parlio_tx_unit_t *unit = NULL; parlio_tx_unit_t *unit = NULL;
ESP_GOTO_ON_FALSE(config && ret_unit, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(config && ret_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
size_t data_width = config->data_width; size_t data_width = config->data_width;
// data_width must be power of 2 and less than or equal to SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH // data_width must be power of 2 and less than or equal to SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH
ESP_GOTO_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0), ESP_RETURN_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0),
ESP_ERR_INVALID_ARG, err, TAG, "invalid data width"); ESP_ERR_INVALID_ARG, TAG, "invalid data width");
// data_width must not conflict with the valid signal // data_width must not conflict with the valid signal
ESP_GOTO_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG), ESP_RETURN_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG),
ESP_ERR_INVALID_ARG, err, TAG, "valid signal conflicts with data signal"); ESP_ERR_INVALID_ARG, TAG, "valid signal conflicts with data signal");
ESP_GOTO_ON_FALSE(config->max_transfer_size && config->max_transfer_size <= PARLIO_LL_TX_MAX_BITS_PER_FRAME / 8, ESP_RETURN_ON_FALSE(config->max_transfer_size && config->max_transfer_size <= PARLIO_LL_TX_MAX_BITS_PER_FRAME / 8,
ESP_ERR_INVALID_ARG, err, TAG, "invalid max transfer size"); ESP_ERR_INVALID_ARG, TAG, "invalid max transfer size");
#if SOC_PARLIO_TX_CLK_SUPPORT_GATING #if SOC_PARLIO_TX_CLK_SUPPORT_GATING
// clock gating is controlled by either the MSB bit of data bus or the valid signal // clock gating is controlled by either the MSB bit of data bus or the valid signal
ESP_GOTO_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE), ESP_RETURN_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE),
ESP_ERR_INVALID_ARG, err, TAG, "no gpio can control the clock gating"); ESP_ERR_INVALID_ARG, TAG, "no gpio can control the clock gating");
#else #else
ESP_GOTO_ON_FALSE(config->flags.clk_gate_en == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "clock gating is not supported"); ESP_RETURN_ON_FALSE(config->flags.clk_gate_en == 0, ESP_ERR_NOT_SUPPORTED, TAG, "clock gating is not supported");
#endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING
// malloc unit memory // malloc unit memory
@@ -569,10 +571,14 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
ESP_RETURN_ON_FALSE((payload_bits % 8) == 0, ESP_ERR_INVALID_ARG, TAG, "payload bit length must be multiple of 8"); ESP_RETURN_ON_FALSE((payload_bits % 8) == 0, ESP_ERR_INVALID_ARG, TAG, "payload bit length must be multiple of 8");
#endif // !SOC_PARLIO_TRANS_BIT_ALIGN #endif // !SOC_PARLIO_TRANS_BIT_ALIGN
// acquire one transaction description from ready queue or complete queue TickType_t queue_wait_ticks = portMAX_DELAY;
if (config->flags.queue_nonblocking) {
queue_wait_ticks = 0;
}
parlio_tx_trans_desc_t *t = NULL; parlio_tx_trans_desc_t *t = NULL;
// acquire one transaction description from ready queue or complete queue
if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_READY], &t, 0) != pdTRUE) { if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_READY], &t, 0) != pdTRUE) {
if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_COMPLETE], &t, 0) == pdTRUE) { if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_COMPLETE], &t, queue_wait_ticks) == pdTRUE) {
tx_unit->num_trans_inflight--; tx_unit->num_trans_inflight--;
} }
} }