mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-19 23:45:28 +02:00
feat(esp_eth): a new folder structure of the driver and other improvements
Fixed memory leak in emac_esp_new_dma function. Polished ESP EMAC cache management. Added emac_periph definitions based on SoC features and improved(generalized) ESP EMAC GPIO initialization. Added ESP EMAC GPIO reservation. Added check for frame error condition indicated by EMAC DMA and created a target test.
This commit is contained in:
@@ -5,6 +5,6 @@ idf_component_register(SRCS "esp_eth_test_apps.c"
|
||||
"esp_eth_test_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client
|
||||
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client esp_driver_gpio
|
||||
EMBED_TXTFILES dl_espressif_com_root_cert.pem
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
@@ -36,15 +36,15 @@ esp_eth_mac_t *mac_init(void *vendor_emac_config, eth_mac_config_t *mac_config)
|
||||
#if CONFIG_TARGET_USE_INTERNAL_ETHERNET
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
||||
#if !CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG
|
||||
esp32_emac_config.smi_mdc_gpio_num = CONFIG_TARGET_IO_MDC;
|
||||
esp32_emac_config.smi_mdio_gpio_num = CONFIG_TARGET_IO_MDIO;
|
||||
esp32_emac_config.smi_gpio.mdc_num = CONFIG_TARGET_IO_MDC;
|
||||
esp32_emac_config.smi_gpio.mdio_num = CONFIG_TARGET_IO_MDIO;
|
||||
#endif // CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG
|
||||
if (vendor_emac_config == NULL) {
|
||||
vendor_emac_config = &esp32_emac_config;
|
||||
}
|
||||
mac = esp_eth_mac_new_esp32(vendor_emac_config, mac_config);
|
||||
#elif CONFIG_TARGET_USE_SPI_ETHERNET
|
||||
// Install GPIO ISR handler to be able to service SPI Eth modlues interrupts
|
||||
// Install GPIO ISR handler to be able to service SPI Eth modules interrupts
|
||||
gpio_install_isr_service(0);
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_eth_test_common.h"
|
||||
#include "hal/emac_hal.h" // for MAC_HAL_TDES0_* control bits
|
||||
|
||||
#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via emac_hal_transmit_frame
|
||||
#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers)
|
||||
#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via emac_hal_transmit_multiple_buf_frame (3 buffers)
|
||||
#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via _transmit_frame
|
||||
#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via _transmit_multiple_buf_frame (2 buffers)
|
||||
#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via _transmit_multiple_buf_frame (3 buffers)
|
||||
|
||||
#define MINIMUM_TEST_FRAME_SIZE 64
|
||||
|
||||
@@ -36,12 +37,12 @@ static esp_err_t eth_recv_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffe
|
||||
|
||||
ESP_LOGI(TAG, "recv frame size: %" PRIu16, expected_size);
|
||||
TEST_ASSERT_EQUAL(expected_size, length);
|
||||
// frame transmitted via emac_hal_transmit_frame
|
||||
// frame transmitted via _transmit_frame
|
||||
if (pkt->proto == ETHERTYPE_TX_STD) {
|
||||
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
|
||||
TEST_ASSERT_EQUAL(pkt->data[i], i & 0xFF);
|
||||
}
|
||||
// frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers)
|
||||
// frame transmitted via _multiple_buf_frame (2 buffers)
|
||||
} else if (pkt->proto == ETHERTYPE_TX_MULTI_2) {
|
||||
uint8_t *data_p = pkt->data;
|
||||
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
|
||||
@@ -357,15 +358,17 @@ TEST_CASE("internal emac interrupt priority", "[esp_emac]")
|
||||
vEventGroupDelete(eth_event_group);
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32P4 // IDF-8993
|
||||
#include "hal/emac_hal.h"
|
||||
#include "hal/emac_ll.h"
|
||||
#include "soc/emac_mac_struct.h"
|
||||
static esp_err_t eth_recv_err_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
|
||||
#define TEST_FRAMES_NUM CONFIG_ETH_DMA_RX_BUFFER_NUM
|
||||
|
||||
static uint8_t *s_recv_frames[TEST_FRAMES_NUM];
|
||||
static uint8_t s_recv_frames_cnt = 0;
|
||||
|
||||
static esp_err_t eth_recv_esp_emac_err_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
|
||||
{
|
||||
SemaphoreHandle_t mutex = (SemaphoreHandle_t)priv;
|
||||
free(buffer);
|
||||
xSemaphoreGive(mutex);
|
||||
s_recv_frames[s_recv_frames_cnt++] = buffer;
|
||||
if (s_recv_frames_cnt >= TEST_FRAMES_NUM)
|
||||
xSemaphoreGive(mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -394,7 +397,7 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]")
|
||||
bool loopback_en = true;
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en);
|
||||
|
||||
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_err_esp_emac_check_cb, mutex));
|
||||
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_esp_emac_err_check_cb, mutex));
|
||||
|
||||
// start the driver
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
||||
@@ -413,23 +416,96 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]")
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, local_mac_addr));
|
||||
memcpy(test_pkt->src, local_mac_addr, ETH_ADDR_LEN);
|
||||
// fill with data
|
||||
for (int i = 0; i < ETH_MAX_PAYLOAD_LEN; i++) {
|
||||
int i;
|
||||
for (i = 1; i < ETH_MAX_PAYLOAD_LEN; i++) {
|
||||
test_pkt->data[i] = i & 0xFF;
|
||||
}
|
||||
|
||||
emac_ll_checksum_offload_mode(&EMAC_MAC, ETH_CHECKSUM_SW);
|
||||
size_t transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
uint8_t frame_id = 0;
|
||||
|
||||
size_t transmit_size = 1072;
|
||||
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
|
||||
ESP_LOGI(TAG, "Verify non-failure frame condition");
|
||||
for (i = 1; i <= TEST_FRAMES_NUM; i++) {
|
||||
test_pkt->data[0] = frame_id++;
|
||||
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
|
||||
// if we have only 10 or less Rx buffers, they can be all used pretty fast => wait to be freed prior next Tx
|
||||
if (CONFIG_ETH_DMA_RX_BUFFER_NUM <= 10 && !(i % (CONFIG_ETH_DMA_RX_BUFFER_NUM / 2))) {
|
||||
ESP_LOGI(TAG, "wait prior Tx (frame num %i)", i);
|
||||
vTaskDelay(10);
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "num of sent frames: %d", TEST_FRAMES_NUM);
|
||||
TEST_ASSERT(xSemaphoreTake(mutex, pdMS_TO_TICKS(500)));
|
||||
ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt);
|
||||
|
||||
free(test_pkt);
|
||||
for (i = 0; i < s_recv_frames_cnt; i++) {
|
||||
emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i];
|
||||
ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]);
|
||||
free(recv_frame);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_UINT8(TEST_FRAMES_NUM, s_recv_frames_cnt);
|
||||
s_recv_frames_cnt = 0;
|
||||
|
||||
printf("\n");
|
||||
ESP_LOGI(TAG, "Verify failure condition when every second frame has invalid CRC");
|
||||
uint32_t emac_tx_dbg_flag = EMAC_HAL_TDES0_CRC_APPEND_DISABLE;
|
||||
for (i = 1; i <= TEST_FRAMES_NUM; i++) {
|
||||
test_pkt->data[0] = frame_id++;
|
||||
// make every 2nd frame invalid
|
||||
if (!(i % 2)) {
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS, &emac_tx_dbg_flag));
|
||||
}
|
||||
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
|
||||
if (!(i % 2)) {
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS, &emac_tx_dbg_flag));
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "num of sent frames: %d (every 2nd invalid)", TEST_FRAMES_NUM);
|
||||
TEST_ASSERT_FALSE(xSemaphoreTake(mutex, pdMS_TO_TICKS(500)));
|
||||
ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt);
|
||||
|
||||
for (i = 0; i < s_recv_frames_cnt; i++) {
|
||||
emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i];
|
||||
ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]);
|
||||
free(recv_frame);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_UINT8(TEST_FRAMES_NUM / 2, s_recv_frames_cnt);
|
||||
s_recv_frames_cnt = 0;
|
||||
|
||||
ESP_LOGI(TAG, "Verify full Rx DMA failure condition");
|
||||
// suspend ETH Rx task so the DMA is filled
|
||||
vTaskSuspend(xTaskGetHandle("emac_rx"));
|
||||
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE - 4; // -4 bytes to the frame fit into one descriptor even with CRC
|
||||
// fill the descriptors, keep one free
|
||||
for (i = 1; i <= CONFIG_ETH_DMA_RX_BUFFER_NUM - 1; i++) {
|
||||
test_pkt->data[0] = frame_id++;
|
||||
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
|
||||
vTaskDelay(1); // to prevent "insufficient TX buffer size" error
|
||||
}
|
||||
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE; // now, we will need 2 descriptors to store the frame (with CRC) but only one is free
|
||||
test_pkt->data[0] = frame_id++;
|
||||
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
|
||||
vTaskDelay(50);
|
||||
vTaskResume(xTaskGetHandle("emac_rx"));
|
||||
|
||||
ESP_LOGI(TAG, "num of sent frames: %d", i);
|
||||
TEST_ASSERT_FALSE(xSemaphoreTake(mutex, pdMS_TO_TICKS(500)));
|
||||
ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt);
|
||||
|
||||
for (i = 0; i < s_recv_frames_cnt; i++) {
|
||||
emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i];
|
||||
ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]);
|
||||
free(recv_frame);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(CONFIG_ETH_DMA_RX_BUFFER_NUM - 1, s_recv_frames_cnt); // one frame is missing due to "Descriptor Error"
|
||||
s_recv_frames_cnt = 0;
|
||||
|
||||
// stop Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_stop(eth_handle));
|
||||
/* wait for connection stop */
|
||||
// wait for connection stop
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
|
||||
free(test_pkt);
|
||||
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
|
||||
TEST_ESP_OK(phy->del(phy));
|
||||
TEST_ESP_OK(mac->del(mac));
|
||||
@@ -439,4 +515,3 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]")
|
||||
vEventGroupDelete(eth_event_group);
|
||||
vSemaphoreDelete(mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user