feat(parlio_tx): support psram buffer

This commit is contained in:
Chen Jichang 2024-09-05 17:05:29 +08:00 committed by morris
parent 8bf4b5bbc0
commit bf487cc290
2 changed files with 30 additions and 8 deletions

View File

@ -32,6 +32,7 @@ typedef struct {
Note that, the valid signal will always occupy the MSB data bit */ Note that, the valid signal will always occupy the MSB data bit */
size_t trans_queue_depth; /*!< Depth of internal transaction queue */ size_t trans_queue_depth; /*!< Depth of internal transaction queue */
size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */ size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */
size_t dma_burst_size; /*!< DMA burst size, in bytes */
parlio_sample_edge_t sample_edge; /*!< Parallel IO sample edge */ parlio_sample_edge_t sample_edge; /*!< Parallel IO sample edge */
parlio_bit_pack_order_t bit_pack_order; /*!< Set the order of packing the bits into bytes (only works when `data_width` < 8) */ parlio_bit_pack_order_t bit_pack_order; /*!< Set the order of packing the bits into bytes (only works when `data_width` < 8) */
struct { struct {

View File

@ -52,6 +52,8 @@ typedef struct parlio_tx_unit_t {
gdma_channel_handle_t dma_chan; // DMA channel gdma_channel_handle_t dma_chan; // DMA channel
gdma_link_list_handle_t dma_link; // DMA link list handle gdma_link_list_handle_t dma_link; // DMA link list handle
size_t dma_nodes_num; // number of DMA descriptor nodes size_t dma_nodes_num; // number of DMA descriptor nodes
size_t int_mem_align; // Alignment for internal memory
size_t ext_mem_align; // Alignment for external memory
#if CONFIG_PM_ENABLE #if CONFIG_PM_ENABLE
char pm_lock_name[PARLIO_PM_LOCK_NAME_LEN_MAX]; // pm lock name char pm_lock_name[PARLIO_PM_LOCK_NAME_LEN_MAX]; // pm lock name
#endif #endif
@ -178,7 +180,7 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
return ESP_OK; return ESP_OK;
} }
static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit) static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit, const parlio_tx_unit_config_t *config)
{ {
gdma_channel_alloc_config_t dma_chan_config = { gdma_channel_alloc_config_t dma_chan_config = {
.direction = GDMA_CHANNEL_DIRECTION_TX, .direction = GDMA_CHANNEL_DIRECTION_TX,
@ -191,6 +193,14 @@ static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit)
}; };
gdma_apply_strategy(tx_unit->dma_chan, &gdma_strategy_conf); gdma_apply_strategy(tx_unit->dma_chan, &gdma_strategy_conf);
// configure DMA transfer parameters
gdma_transfer_config_t trans_cfg = {
.max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : 16, // Enable DMA burst transfer for better performance,
.access_ext_mem = true, // support transmit PSRAM buffer
};
ESP_RETURN_ON_ERROR(gdma_config_transfer(tx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
gdma_get_alignment_constraints(tx_unit->dma_chan, &tx_unit->int_mem_align, &tx_unit->ext_mem_align);
// create DMA link list // create DMA link list
size_t dma_nodes_num = tx_unit->dma_nodes_num; size_t dma_nodes_num = tx_unit->dma_nodes_num;
gdma_link_list_config_t dma_link_config = { gdma_link_list_config_t dma_link_config = {
@ -244,6 +254,7 @@ static esp_err_t parlio_select_periph_clock(parlio_tx_unit_t *tx_unit, const par
tx_unit->out_clk_freq_hz = hal_utils_calc_clk_div_integer(&clk_info, &clk_div.integer); tx_unit->out_clk_freq_hz = hal_utils_calc_clk_div_integer(&clk_info, &clk_div.integer);
#endif #endif
PARLIO_CLOCK_SRC_ATOMIC() { PARLIO_CLOCK_SRC_ATOMIC() {
// turn on the tx module clock to sync the register configuration to the module
parlio_ll_tx_enable_clock(hal->regs, true); parlio_ll_tx_enable_clock(hal->regs, true);
parlio_ll_tx_set_clock_source(hal->regs, clk_src); parlio_ll_tx_set_clock_source(hal->regs, clk_src);
// set clock division // set clock division
@ -313,7 +324,7 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed"); ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed");
// install DMA service // install DMA service
ESP_GOTO_ON_ERROR(parlio_tx_unit_init_dma(unit), err, TAG, "install tx DMA failed"); ESP_GOTO_ON_ERROR(parlio_tx_unit_init_dma(unit, config), err, TAG, "install tx DMA failed");
// reset fifo and core clock domain // reset fifo and core clock domain
PARLIO_RCC_ATOMIC() { PARLIO_RCC_ATOMIC() {
@ -344,7 +355,7 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
parlio_ll_tx_set_sample_clock_edge(hal->regs, config->sample_edge); parlio_ll_tx_set_sample_clock_edge(hal->regs, config->sample_edge);
#if SOC_PARLIO_TX_SIZE_BY_DMA #if SOC_PARLIO_TX_SIZE_BY_DMA
// Always use DMA EOF as the Parlio TX EOF // Always use DATA LEN EOF as the Parlio TX EOF
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DATA_LEN); parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DATA_LEN);
#endif // SOC_PARLIO_TX_SIZE_BY_DMA #endif // SOC_PARLIO_TX_SIZE_BY_DMA
@ -528,6 +539,21 @@ 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
size_t cache_line_size = 0;
size_t alignment = 0;
uint8_t cache_type = 0;
esp_ptr_external_ram(payload) ? (alignment = tx_unit->ext_mem_align, cache_type = CACHE_LL_LEVEL_EXT_MEM) : (alignment = tx_unit->int_mem_align, cache_type = CACHE_LL_LEVEL_INT_MEM);
// check alignment
ESP_RETURN_ON_FALSE(((uint32_t)payload & (alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "payload address not aligned");
ESP_RETURN_ON_FALSE((payload_bits & (alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "payload size not aligned");
cache_line_size = cache_hal_get_cache_line_size(cache_type, CACHE_TYPE_DATA);
if (cache_line_size > 0) {
// Write back to cache to synchronize the cache before DMA start
ESP_RETURN_ON_ERROR(esp_cache_msync((void *)payload, (payload_bits + 7) / 8,
ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), TAG, "cache sync failed");
}
TickType_t queue_wait_ticks = portMAX_DELAY; TickType_t queue_wait_ticks = portMAX_DELAY;
if (config->flags.queue_nonblocking) { if (config->flags.queue_nonblocking) {
queue_wait_ticks = 0; queue_wait_ticks = 0;
@ -546,11 +572,6 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
t->payload = payload; t->payload = payload;
t->payload_bits = payload_bits; t->payload_bits = payload_bits;
t->idle_value = config->idle_value & tx_unit->idle_value_mask; t->idle_value = config->idle_value & tx_unit->idle_value_mask;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
// Write back to cache to synchronize the cache before DMA start
ESP_RETURN_ON_ERROR(esp_cache_msync((void *)payload, (payload_bits + 7) / 8,
ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), TAG, "cache sync failed");
#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
// send the transaction descriptor to progress queue // send the transaction descriptor to progress queue
ESP_RETURN_ON_FALSE(xQueueSend(tx_unit->trans_queues[PARLIO_TX_QUEUE_PROGRESS], &t, 0) == pdTRUE, ESP_RETURN_ON_FALSE(xQueueSend(tx_unit->trans_queues[PARLIO_TX_QUEUE_PROGRESS], &t, 0) == pdTRUE,