mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(parlio_tx): support psram buffer
This commit is contained in:
parent
8bf4b5bbc0
commit
bf487cc290
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user