mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 20:51:41 +00:00 
			
		
		
		
	Merge branch 'feature/parlio_rx_driver_p4_v5.3' into 'release/v5.3'
feat(parlio_rx): supported parlio rx on p4 (v5.3) See merge request espressif/esp-idf!31096
This commit is contained in:
		| @@ -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]; | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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 | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -1,2 +1,2 @@ | |||||||
| | Supported Targets | ESP32-C6 | ESP32-H2 | | | Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | | ||||||
| | ----------------- | -------- | -------- | | | ----------------- | -------- | -------- | -------- | | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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"); | ||||||
|   | |||||||
| @@ -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', | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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. | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -1011,6 +1015,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 | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -398,6 +398,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 ---------------------------------------*/ | ||||||
|   | |||||||
| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| | Supported Targets | ESP32-C6 | ESP32-H2 | | | Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | | ||||||
| | ----------------- | -------- | -------- | | | ----------------- | -------- | -------- | -------- | | ||||||
|  |  | ||||||
| # Logic Analyzer Example | # Logic Analyzer Example | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 */ | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 morris
					morris