2019年4月28日日曜日

ESP32をWi-Fi AP/イーサネットコンバーターにする(LAN8720使用)

最近になって、昨年公式githubに”eth2wifi”というサンプルが上がっているのに気づきました。
どうやらこれを使うと、有線LANをつないでWi-Fiアクセスポイントを立ち上げる
あるいはESP32がWi-Fiアクセスポイントに接続して、ESP32を介して有線LANの機器をLANに接続する
ということができるようです。1000円そこらでAPが作れるのは画期的です。

ESP32は、Wi-Fiの他に、物理層の部分以外Ethernetにも対応しています。
実際にEthernetを使うためにはEthernet PHY(フィジカル=物理層)
の回路が必要です。
よく知りませんが、通信用のクロックを作ったり、
信号レベルなどを有線LANの規格にあわせたりしてくれる回路なのだと思います。
これらの回路をESP32内部に入れるのはあまり使う人いないのに不毛ということで
物理層がはじめからは載っていないのだと思います。僕もそれでいいと思います。

調べるとEthernet PHYのICというものがいろいろ出ていて、簡単にブレークアウトボードに乗っているものが手に入るICとして、LAN8720がESP32ではよく使われているようです。

というわけで、LAN8720の載った基板をAliexpressで注文しました。
200円くらいで売っています。
https://www.aliexpress.com/item/1pcs-Smart-Electronics-LAN8720-module-network-module-Ethernet-transceiver-RMII-interface-development-board-for-arduino/32947407343.html?spm=2114.search0204.3.41.18a547acrOaaW9&ws_ab_test=searchweb0_0,searchweb201602_4_10065_10068_319_10059_10884_317_10887_10696_321_322_10084_453_10083_454_10103_10618_10307_537_536,searchweb201603_16,ppcSwitch_0&algo_expid=a53a62b5-87f4-46c8-8fea-e77569fc6b6b-6&algo_pvid=a53a62b5-87f4-46c8-8fea-e77569fc6b6b&transAbTest=ae803_5

届いたので、
冒頭のリンクのURLに書いてあるとおり配線しました。


 まあたくさん配線しないといけなくて、めんどくさいですがジャンパ線で直接接続のバラックです。
リンク先に注意書きが書いてあるのですが、
LAN8720ボードからのクロック出力をGPIO0に入力していますが、
ESP32の起動時にGPIO0がローに落ちていると、ファーム書き込みモードに入ってしまいます。
そこで、調べたら出てきた対策をします。
発振子の足をNCのピンに引き出して、GPIO17につなぎます。
GPIO17はコードの中でクロック出力の有効化・無効化をしてくれています。
こんなやり方でいいのか?という感じがしますがこれでうまくいきました。
基板を立ち上げるなら、トランジスタで電源ごと切ったりするほうが健全な気もします。



eth2wifiサンプルのディレクトリで、make menuconfigで動作の設定ができます。


僕が買ったボードのPHY Addressは1でした。
USE PHY Power pinにチェックが入っていると、PHY Power GPIOで制御ができます。
WiFi station modeにチェックが入っていると、イーサネットコンバーター
チェックを外すとAPになります。

実際通信してみましたが、CATV12Mではほぼ上限の値が出ていたので、実際にはもっと早いスピードで通信できると思います。
ツイッターを見ながらプライムビデオを流すくらいの使い方は余裕でできました。
本当に1000円そこらでAPを自作できるのはすごいですね。
2つ数珠つなぎにしてAP-イーサネットコンバーターとやれば中継機とかも組めそうです。
(それはもっとうまいやり方がありそうですが)

どうやってこれを実現しているのか?コードを見るととてもシンプルで驚きます。

static esp_err_t tcpip_adapter_sta_input_eth_output(void* buffer, uint16_t len, void* eb)
{
    if (ethernet_is_connected) {
        esp_eth_tx(buffer, len);
    }

    esp_wifi_internal_free_rx_buffer(eb);
    return ESP_OK;
}

Wi-Fiに受信バッファがあったらEthernetに送る
Ethernetに受信バッファがあったらWi-Fiに送るというような関数があります
シリアル通信のようなノリでこんなことができているのですね。
パケットをそのまま処理しているので、ESP32自身に宛てられたパケットを判別して処理するようなコードを書かないとESP32自身は通信ができないような気がします。
市販のAPのようにWebUIを実装したりするのは結構たいへんそうです。
ボタンを押しながら起動で別モードとして設定モードが立ち上がるような実装だと特に問題なく作れそうです。