ESP32-based IDF development, Ethernet (ETH) routine analysis (built-in mac and external phy)

The Ethernet hardware combination of esp32 I use is built-in MAC and external PHY

For the specific configuration process, please refer to my previous article " (5 messages) ESP32 Ethernet (ETH) environment and parameter configuration, based on internal mac and external PHY (LAN8720A)_Stranglethorn Valley 555 Blog-CSDN Blog  "

After the configuration is complete and the compilation is normal, analyze the code (why there are this series of articles, because the editor intends to make an IoT device that automatically switches between wifi and Ethernet based on ESP32)

When we get an IDF program, we first find the entry function

void app_main(void)

I have deleted most of the useless code (users modify it according to their actual hardware)

void app_main(void)

{

    //有的时候莫名其妙WiFi 、 mac地址都报废,用这个擦除nvs就好了(新增)

    ESP_ERROR_CHECK(nvs_flash_erase());

    nvs_flash_init();//(新增)

    // 初始化TCP/IP网络接口(在应用程序中只能调用一次)

    ESP_ERROR_CHECK(esp_netif_init());

    // 创建在后台运行的默认事件循环

    ESP_ERROR_CHECK(esp_event_loop_create_default());

#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET

     //为idf以太网创建一个新的默认实例

    esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();

    esp_netif_t *eth_netif = esp_netif_new(&cfg);

     // 设置默认处理程序来处理TCP/IP内容

    eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();

    eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();

    phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;

    phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;

    eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();

    esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;

    esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;

    /* 创建ESP32以太网MAC实例 */

   esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);

     /* 创建一个PHY实例LAN8720 */

    esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);

    esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);

    esp_eth_handle_t eth_handle = NULL;

    /* 以太网驱动程序安装 */

    ESP_ERROR_CHECK(esp_eth_driver_install(&config, &eth_handle));

    /*连接TCP/IP协议栈*/

    ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));

#endif //CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET

    // 注册用户定义的事件处理程序

    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));//ETH 的事件处理程序

    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));//IP 的事件处理程序

    /* start Ethernet driver state machine */

#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET

    /*启动以太网驱动程序状态机*/

    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET

}

In the above code, since most of them are packaged, we only need to care about some functions. In the above code, the main parts are basically fixed. We only need to call it according to the template. What we need to care about is only:

①Callback function processing

// 注册用户定义的事件处理程序

    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));//ETH 的事件处理程序

    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));//IP 的事件处理程序

② Timing to start ETH

/*启动以太网驱动程序状态机,此函数要放在回调注册之后,它会触发回调*/

    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

For the use of macro definitions in functions, vs code cannot jump to the problem, and it still cannot be solved (whoever has solved it hopes to give some guidance). You can view it on Espressif’s official website, or use vscode to open the demo path of the idf installation location to search and view, then find the definition location, take the header file to include it, and then open the header file and go to the definition to appear.

Let's take a look at the use in the callback function, where the user generally modifies the function.

/**以太网事件处理程序,只有插拔线检测,没有联网是否成功*/

static void eth_event_handler(void *arg, esp_event_base_t event_base,

                              int32_t event_id, void *event_data)

{

    uint8_t mac_addr[6] = {0};

     /*我们可以从事件数据中获得以太网驱动程序句柄*/

    esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;

    switch (event_id) {

    case ETHERNET_EVENT_CONNECTED:

         //插入网线立即进入此处(作用不大,有网线但是没能获取IP,仍然采用ETH重连)

        esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);

        ESP_LOGI(TAG, "CYY network Link is in");

        ESP_LOGI(TAG, "Ethernet Link Up");

        ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",

               mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

        break;

    case ETHERNET_EVENT_DISCONNECTED:

    //拔出网线立即进入此处,等待用户使用(网线拔出,启动wifi)

        ESP_LOGI(TAG, "CYY network Link is out");

        ESP_LOGI(TAG, "Ethernet Link Down");

        break;

    case ETHERNET_EVENT_START:

        //开机启动完成进入此处

        ESP_LOGI(TAG, "Ethernet Started");

        break;

    case ETHERNET_EVENT_STOP:

        ESP_LOGI(TAG, "Ethernet Stopped");

        break;

    default:

        break;

    }

}

/** IP_EVENT_ETH_GOT_IP的事件处理程序,联网获取IP成功回调*/

static void got_ip_event_handler(void *arg, esp_event_base_t event_base,

                                 int32_t event_id, void *event_data)

{

    ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;

    const esp_netif_ip_info_t *ip_info = &event->ip_info;

    //to do 获取IP成功进入此处,需要用户自行处理(一般启动访问服务器)

    ESP_LOGI(TAG, "CYY get ip succeed");

    ESP_LOGI(TAG, "Ethernet Got IP Address");

    ESP_LOGI(TAG, "~~~~~~~~~~~");

    ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));

    ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));

    ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));

    ESP_LOGI(TAG, "~~~~~~~~~~~");

}

Check the call logic according to log printing

First, because we called in the main function

/*启动以太网驱动程序状态机,此函数要放在回调注册之后,它会触发回调*/

    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

Therefore, the callback is triggered, we have added printing, we have not processed it, and told the developer that it has started

case ETHERNET_EVENT_START:

        //开机启动完成进入此处

        ESP_LOGI(TAG, "Ethernet Started");

At this time, the underlying driver will detect whether there is a network cable plugged in (if not, there is no next step, to do flexible switching, you can add a timeout to enter wifi startup) (if there is a network cable connected, it will enter the following callback)

ETHERNET_EVENT_CONNECTED

Call functions

esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);//获取以太网接口 MAC 地址。

        ESP_LOGI(TAG, "CYY network Link is in");

        ESP_LOGI(TAG, "Ethernet Link Up");

        ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",

               mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

Print out the mac address of the device.

Afterwards, the lower-layer Ethernet driver will acquire the IP address. After the acquisition is successful, it will enter the following callback function

/** IP_EVENT_ETH_GOT_IP的事件处理程序,联网获取IP成功回调*/

static void got_ip_event_handler(void *arg, esp_event_base_t event_base,

                                 int32_t event_id, void *event_data)

{

    ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;

    const esp_netif_ip_info_t *ip_info = &event->ip_info;

    //to do 获取IP成功进入此处,需要用户自行处理(一般启动访问服务器)

    ESP_LOGI(TAG, "CYY get ip succeed");

    ESP_LOGI(TAG, "Ethernet Got IP Address");

    ESP_LOGI(TAG, "~~~~~~~~~~~");

    ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));

    ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));

    ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));

    ESP_LOGI(TAG, "~~~~~~~~~~~");

}

At this point, it means that the Ethernet connection has been successful, we can make tcp communication requests, and we can use mqtt and https to try to connect to the background.

In addition, if the network cable is pulled out at this time (or the router is broken and powered off, etc.), it will enter the callback at this time

ETHERNET_EVENT_DISCONNECTED

At this point, we can perform functions such as turning on wifi.

 

Guess you like

Origin blog.csdn.net/m0_45068979/article/details/131220234