mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/emac_intr_prio' into 'master'
feat(esp_eth): added option to configure interrupt priority Closes IDF-7969 See merge request espressif/esp-idf!29300
This commit is contained in:
commit
9d0b8d62b0
@ -467,6 +467,7 @@ typedef struct {
|
||||
eth_data_interface_t interface; /*!< EMAC Data interface to PHY (MII/RMII) */
|
||||
eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */
|
||||
eth_mac_dma_burst_len_t dma_burst_len; /*!< EMAC DMA burst length for both Tx and Rx */
|
||||
int intr_priority; /*!< EMAC interrupt priority, if set to 0 or a negative value, the driver will try to allocate an interrupt with a default priority */
|
||||
#if SOC_EMAC_USE_IO_MUX
|
||||
eth_mac_dataif_gpio_config_t emac_dataif_gpio; /*!< EMAC MII/RMII data plane GPIO configuration */
|
||||
#endif // SOC_EMAC_USE_IO_MUX
|
||||
@ -494,6 +495,7 @@ typedef struct {
|
||||
} \
|
||||
}, \
|
||||
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
|
||||
.intr_priority = 0, \
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
|
||||
@ -518,6 +520,7 @@ typedef struct {
|
||||
} \
|
||||
}, \
|
||||
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
|
||||
.intr_priority = 0, \
|
||||
.emac_dataif_gpio = \
|
||||
{ \
|
||||
.rmii = \
|
||||
|
@ -41,6 +41,8 @@ static const char *TAG = "esp.emac";
|
||||
#define FLOW_CONTROL_LOW_WATER_MARK (CONFIG_ETH_DMA_RX_BUFFER_NUM / 3)
|
||||
#define FLOW_CONTROL_HIGH_WATER_MARK (FLOW_CONTROL_LOW_WATER_MARK * 2)
|
||||
|
||||
#define EMAC_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED
|
||||
|
||||
#define RMII_CLK_HZ (50000000)
|
||||
#define RMII_10M_SPEED_RX_TX_CLK_DIV (19)
|
||||
#define RMII_100M_SPEED_RX_TX_CLK_DIV (1)
|
||||
@ -664,6 +666,11 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config
|
||||
esp_eth_mac_t *ret = NULL;
|
||||
emac_esp32_t *emac = NULL;
|
||||
ESP_RETURN_ON_FALSE(config, NULL, TAG, "can't set mac config to null");
|
||||
if (esp32_config->intr_priority > 0) {
|
||||
ESP_RETURN_ON_FALSE(1 << (esp32_config->intr_priority) & EMAC_ALLOW_INTR_PRIORITY_MASK, NULL,
|
||||
TAG, "invalid interrupt priority: %d", esp32_config->intr_priority);
|
||||
}
|
||||
|
||||
ret_code = esp_emac_alloc_driver_obj(config, &emac);
|
||||
ESP_RETURN_ON_FALSE(ret_code == ESP_OK, NULL, TAG, "alloc driver object failed");
|
||||
|
||||
@ -675,14 +682,19 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config
|
||||
}
|
||||
/* initialize hal layer driver */
|
||||
emac_hal_init(&emac->hal);
|
||||
|
||||
/* alloc interrupt */
|
||||
if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
|
||||
ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM,
|
||||
emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
|
||||
int isr_flags = 0;
|
||||
if (esp32_config->intr_priority > 0) {
|
||||
isr_flags |= 1 << (esp32_config->intr_priority);
|
||||
} else {
|
||||
ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0,
|
||||
emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
|
||||
isr_flags |= ESP_INTR_FLAG_LOWMED;
|
||||
}
|
||||
if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
|
||||
isr_flags |= ESP_INTR_FLAG_IRAM;
|
||||
}
|
||||
ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, isr_flags,
|
||||
emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
|
||||
ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed");
|
||||
|
||||
#ifdef SOC_EMAC_USE_IO_MUX
|
||||
|
@ -1,6 +1,6 @@
|
||||
idf_component_register(SRCS "esp_eth_test_apps.c"
|
||||
"esp_eth_test_l2.c"
|
||||
"esp_eth_test_hal.c"
|
||||
"esp_eth_test_esp_emac.c"
|
||||
"esp_eth_test_common.c"
|
||||
"esp_eth_test_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static const char *TAG = "esp32_eth_test_hal";
|
||||
static const char *TAG = "eth_test_esp_emac";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -26,12 +26,12 @@ typedef struct
|
||||
uint16_t expected_size;
|
||||
uint16_t expected_size_2;
|
||||
uint16_t expected_size_3;
|
||||
} recv_hal_check_info_t;
|
||||
} recv_esp_emac_check_info_t;
|
||||
|
||||
static esp_err_t eth_recv_hal_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
|
||||
static esp_err_t eth_recv_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
|
||||
{
|
||||
emac_frame_t *pkt = (emac_frame_t *)buffer;
|
||||
recv_hal_check_info_t *recv_info = (recv_hal_check_info_t *)priv;
|
||||
recv_esp_emac_check_info_t *recv_info = (recv_esp_emac_check_info_t *)priv;
|
||||
uint16_t expected_size = recv_info->expected_size + recv_info->expected_size_2 + recv_info->expected_size_3;
|
||||
|
||||
ESP_LOGI(TAG, "recv frame size: %" PRIu16, expected_size);
|
||||
@ -75,9 +75,9 @@ static esp_err_t eth_recv_hal_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, ui
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
TEST_CASE("hal receive/transmit", "[emac_hal]")
|
||||
TEST_CASE("internal emac receive/transmit", "[esp_emac]")
|
||||
{
|
||||
recv_hal_check_info_t recv_info;
|
||||
recv_esp_emac_check_info_t recv_info;
|
||||
recv_info.mutex = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(recv_info.mutex);
|
||||
recv_info.expected_size = 0;
|
||||
@ -106,7 +106,7 @@ TEST_CASE("hal receive/transmit", "[emac_hal]")
|
||||
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_hal_check_cb, &recv_info));
|
||||
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_esp_emac_check_cb, &recv_info));
|
||||
|
||||
// start the driver
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
||||
@ -297,11 +297,71 @@ TEST_CASE("hal receive/transmit", "[emac_hal]")
|
||||
vSemaphoreDelete(recv_info.mutex);
|
||||
}
|
||||
|
||||
TEST_CASE("internal emac interrupt priority", "[esp_emac]")
|
||||
{
|
||||
EventBits_t bits = 0;
|
||||
EventGroupHandle_t eth_event_group = xEventGroupCreate();
|
||||
TEST_ASSERT(eth_event_group != NULL);
|
||||
test_case_uses_tcpip();
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
for (int i = -1; i <= 4; i++) {
|
||||
// create TCP/IP netif
|
||||
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
||||
esp32_emac_config.intr_priority = i;
|
||||
ESP_LOGI(TAG, "set interrupt priority %i: ", i);
|
||||
esp_eth_mac_t *mac = mac_init(&esp32_emac_config, NULL);
|
||||
if (i >= 4) {
|
||||
TEST_ASSERT_NULL(mac);
|
||||
}
|
||||
else {
|
||||
TEST_ASSERT_NOT_NULL(mac);
|
||||
esp_eth_phy_t *phy = phy_init(NULL);
|
||||
TEST_ASSERT_NOT_NULL(phy);
|
||||
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
esp_eth_handle_t eth_handle = NULL;
|
||||
// install Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle));
|
||||
extra_eth_config(eth_handle);
|
||||
// combine driver with netif
|
||||
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
|
||||
TEST_ESP_OK(esp_netif_attach(eth_netif, glue));
|
||||
// register user defined event handers
|
||||
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group));
|
||||
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_event_group));
|
||||
|
||||
// start Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
||||
/* wait for IP lease */
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT);
|
||||
// stop Ethernet driveresp_event_handler_unregister
|
||||
TEST_ESP_OK(esp_eth_stop(eth_handle));
|
||||
/* 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);
|
||||
|
||||
TEST_ESP_OK(esp_eth_del_netif_glue(glue));
|
||||
/* driver should be uninstalled within 2 seconds */
|
||||
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
|
||||
TEST_ESP_OK(phy->del(phy));
|
||||
TEST_ESP_OK(mac->del(mac));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
|
||||
extra_cleanup();
|
||||
}
|
||||
esp_netif_destroy(eth_netif);
|
||||
}
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
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_hal_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
|
||||
static esp_err_t eth_recv_err_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
|
||||
{
|
||||
SemaphoreHandle_t mutex = (SemaphoreHandle_t)priv;
|
||||
free(buffer);
|
||||
@ -309,7 +369,7 @@ static esp_err_t eth_recv_err_hal_check_cb(esp_eth_handle_t hdl, uint8_t *buffer
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
TEST_CASE("hal erroneous frames", "[emac_hal]")
|
||||
TEST_CASE("internal emac erroneous frames", "[esp_emac]")
|
||||
{
|
||||
SemaphoreHandle_t mutex = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(mutex);
|
||||
@ -334,7 +394,7 @@ TEST_CASE("hal erroneous frames", "[emac_hal]")
|
||||
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_hal_check_cb, mutex));
|
||||
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_err_esp_emac_check_cb, mutex));
|
||||
|
||||
// start the driver
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
@ -127,8 +127,8 @@ def ethernet_test(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='ethernet', timeout=980)
|
||||
|
||||
|
||||
def ethernet_int_emac_hal_test(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='emac_hal')
|
||||
def ethernet_int_emac_test(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='esp_emac', timeout=120)
|
||||
|
||||
|
||||
def ethernet_l2_test(dut: IdfDut) -> None:
|
||||
@ -250,8 +250,8 @@ def test_esp_ethernet(dut: IdfDut) -> None:
|
||||
@pytest.mark.parametrize('config', [
|
||||
'default_ip101',
|
||||
], indirect=True)
|
||||
def test_esp_emac_hal(dut: IdfDut) -> None:
|
||||
ethernet_int_emac_hal_test(dut)
|
||||
def test_esp_emac(dut: IdfDut) -> None:
|
||||
ethernet_int_emac_test(dut)
|
||||
dut.serial.hard_reset()
|
||||
ethernet_heap_alloc_test(dut)
|
||||
|
||||
|
@ -196,8 +196,6 @@ static void ethernet_deinit(test_vfs_eth_network_t *network_hndls)
|
||||
{
|
||||
TEST_ESP_OK(esp_eth_stop(network_hndls->eth_handle));
|
||||
TEST_ESP_OK(esp_eth_del_netif_glue(network_hndls->glue));
|
||||
/* driver should be uninstalled within 2 seconds */
|
||||
//TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000));
|
||||
esp_eth_driver_uninstall(network_hndls->eth_handle);
|
||||
TEST_ESP_OK(network_hndls->phy->del(network_hndls->phy));
|
||||
TEST_ESP_OK(network_hndls->mac->del(network_hndls->mac));
|
||||
|
@ -226,7 +226,7 @@ The Ethernet driver is composed of two parts: MAC and PHY.
|
||||
|
||||
You need to set up the necessary parameters for MAC and PHY respectively based on your Ethernet board design, and then combine the two together to complete the driver installation.
|
||||
|
||||
Configuration for MAC is described in :cpp:class:`eth_mac_config_t`, including:
|
||||
Basic common configuration for MAC layer is described in :cpp:class:`eth_mac_config_t`, including:
|
||||
|
||||
.. list::
|
||||
|
||||
@ -236,15 +236,23 @@ Configuration for MAC is described in :cpp:class:`eth_mac_config_t`, including:
|
||||
|
||||
* :cpp:member:`eth_mac_config_t::flags`: specifying extra features that the MAC driver should have, it could be useful in some special situations. The value of this field can be OR'd with macros prefixed with ``ETH_MAC_FLAG_``. For example, if the MAC driver should work when the cache is disabled, then you should configure this field with :c:macro:`ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE`.
|
||||
|
||||
:SOC_EMAC_SUPPORTED: * :cpp:member:`eth_esp32_emac_config_t::smi_mdc_gpio_num` and :cpp:member:`eth_esp32_emac_config_t::smi_mdio_gpio_num`: the GPIO number used to connect the SMI signals.
|
||||
.. only:: SOC_EMAC_SUPPORTED
|
||||
|
||||
:SOC_EMAC_SUPPORTED: * :cpp:member:`eth_esp32_emac_config_t::interface`: configuration of MAC Data interface to PHY (MII/RMII).
|
||||
Specific configuration for **internal MAC module** is described in :cpp:class:`eth_esp32_emac_config_t`, including:
|
||||
|
||||
:SOC_EMAC_SUPPORTED: * :cpp:member:`eth_esp32_emac_config_t::clock_config`: configuration of EMAC Interface clock (``REF_CLK`` mode and GPIO number in case of RMII).
|
||||
.. list::
|
||||
|
||||
:SOC_EMAC_USE_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers.
|
||||
* :cpp:member:`eth_esp32_emac_config_t::smi_mdc_gpio_num` and :cpp:member:`eth_esp32_emac_config_t::smi_mdio_gpio_num`: the GPIO number used to connect the SMI signals.
|
||||
|
||||
:not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`: configuration of EMAC input interface clock when ``REF_CLK`` signal is generated internally and is looped back to the EMAC externally. The mode must be always configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`. This option is valid only when configuration of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`.
|
||||
* :cpp:member:`eth_esp32_emac_config_t::interface`: configuration of MAC Data interface to PHY (MII/RMII).
|
||||
|
||||
* :cpp:member:`eth_esp32_emac_config_t::clock_config`: configuration of EMAC Interface clock (``REF_CLK`` mode and GPIO number in case of RMII).
|
||||
|
||||
* :cpp:member:`eth_esp32_emac_config_t::intr_priority`: sets the priority of the MAC interrupt. If it is set to ``0`` or a negative value, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. Note that *Low* and *Medium* interrupt priorities (1 to 3) can be set since these can be handled in C.
|
||||
|
||||
:SOC_EMAC_USE_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers.
|
||||
|
||||
:not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`: configuration of EMAC input interface clock when ``REF_CLK`` signal is generated internally and is looped back to the EMAC externally. The mode must be always configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`. This option is valid only when configuration of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`.
|
||||
|
||||
Configuration for PHY is described in :cpp:class:`eth_phy_config_t`, including:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user