ESP32 ベースの IDF 開発、イーサネット (ETH) ルーチン分析 (内蔵 Mac および外部 phy)

私が使用している esp32 のイーサネット ハードウェアの組み合わせは、内蔵 MAC と外部 PHY です。

具体的な設定プロセスについては、以前の記事「(メッセージ数 5 件) 内部 MAC と外部 PHY (LAN8720A) に基づく ESP32 イーサネット (ETH) 環境とパラメータ設定_Stranglethorn Valley 555 Blog-CSDN Blog」を参照してください 。

構成が完了し、コンパイルが正常に完了したら、コードを分析します (なぜこの一連の記事があるかというと、編集者は ESP32 に基づいて Wi-Fi とイーサネットを自動的に切り替える IoT デバイスを作成するつもりだからです)。

IDF プログラムを取得すると、まずエントリ関数を見つけます。

void app_main(void)

無駄なコードのほとんどを削除しました (ユーザーは実際のハードウェアに応じてコードを変更します)

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

}

上記のコードでは、ほとんどがカプセル化されているため、一部の関数を意識するだけで済みますが、上記のコードでは、主要な部分は基本的に固定されており、テンプレートに従って呼び出すだけでよく、注意する必要があるのは、 :

①コールバック関数の処理

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

    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 的事件处理程序

② ETHの開始タイミング

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

    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

関数内でマクロ定義を使用する場合、vs code は問題にジャンプすることができず、依然として解決できません (解決した人は何らかのガイダンスを提供してくれることを望んでいます)。Espressif の公式 Web サイトで表示するか、vscode を使用して idf インストール場所のデモ パスを開いて検索して表示し、定義の場所を見つけてヘッダー ファイルを取得してそれをインクルードし、ヘッダー ファイルを開いて次の場所に移動します。表示される定義。

通常、ユーザーが関数を変更するコールバック関数での使用を見てみましょう。

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

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, "~~~~~~~~~~~");

}

ログ出力に従って呼び出しロジックを確認する

まず、main 関数を呼び出したので、

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

    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

したがって、コールバックがトリガーされ、印刷を追加しましたが、処理は行わず、開発者に印刷が開始されたことを伝えました。

case ETHERNET_EVENT_START:

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

        ESP_LOGI(TAG, "Ethernet Started");

このとき、基礎となるドライバーは、ネットワーク ケーブルが接続されているかどうかを検出します (接続されていない場合は、次のステップはありません。柔軟に切り替えるために、Wi-Fi 起動に入るタイムアウトを追加できます) (ネットワーク ケーブルが接続されている場合) 、次のコールバックに入ります)

ETHERNET_EVENT_CONNECTED

関数の呼び出し

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]);

デバイスの MAC アドレスを出力します。

その後、下位層の Ethernet ドライバーが IP アドレスを取得し、取得に成功すると以下のコールバック関数に入ります。

/** 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, "~~~~~~~~~~~");

}

この時点で、イーサネット接続が成功し、TCP 通信リクエストを行うことができ、mqtt と https を使用してバックグラウンドへの接続を試行できることを意味します。

なお、この時にネットワークケーブルが抜けた場合(またはルータが壊れて電源が切れた場合など)、この時点でコールバックに入ります。

ETHERNET_EVENT_DISCONNECTED

この時点で、Wi-Fi をオンにするなどの機能を実行できます。

 

おすすめ

転載: blog.csdn.net/m0_45068979/article/details/131220234