ENC28J60を使ってESP32でEthernet UDP通信する
MICROCHIPのENC28J60を使ってESP32(Arduino core for the ESP32)でUDP通信を行ってみます。
1. 準備
ENC28J60を入手します。aitendoやAmazonで1,000円程度で購入できます。入手に時間がかかってもよければAliexpressを使うと$2~$3で購入できます。今回はおなじみのチップサイズがSOPではなくSSOPの小さいモジュール版を使用しました。SOP版と同じように使うことができます。
ESP32はESP32-DevKitCを使います。秋月電子で購入できます。
2. 接続
ENC28J60とESP32を以下の図のように接続します。接続情報はこれから使用するEthernetライブラリ(UIPEthernet)のこちらのリンクを参考にしました。
ESP32 | ENC28J60 |
---|---|
IO5 (SS) | CS |
IO23 (VS_MOSI) | SI |
IO19 (VSMISO) | SO |
IO18 (VS_SCK) | SCK |
3V3 | VCC |
GND | GND |
ESP32-DevKitCは3.3Vのレギュレーターに1A以上出力可能なNCP1117を使用しているため、ENC28J60と直接つなげています。とはいえUSBからの給電のため3.3V全体で500mA以上を超えないように気をつける必要はあります。(3.3VラインはESP32のチップへの電源供給にも使われています)
秋月電子電子の商品ページに貼られているリンクからESP32-DevKitCの回路図を確認することができます。
http://akizukidenshi.com/download/ds/espressifsystems/ESP32-Core-Board-V2_sch.pdf
NCP1117データシート
https://www.onsemi.jp/PowerSolutions/document/NCP1117JP-D.PDF
3. ボードライブラリ修正
Arduino core for the ESP32 Ver 1.0.2にはEthernetを使用するためのライブラリに不備があり、コンパイルすることができません。Arduino core for the ESP32 Ver 1.0.1であればビルドが可能になるため、Ver 1.0.1を使う場合はこの項目は飛ばしてください。
Ver 1.0.2でコンパイルできるようにするためにはArduino core for the ESP32のClient.hを修正する必要があります。 Client.hはボードマネージャを使用してインストールしてあれば以下のパスにがあります。(Windows)
C:\Users\<アカウント名>\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.2\cores\esp32\Client.h
テキストエディタでClient.hを開いて以下の行をコメントアウトします。
// virtual int connect(IPAddress ip, uint16_t port, int timeout) =0; // virtual int connect(const char *host, uint16_t port, int timeout) =0;
これに関する経緯については前回の記事の「ライブラリの修正」項目で少し触れているのでそちらを参考ください。 W5500を使ってESP32でEthernet UDP通信する - Re: note
4. Ethernetライブラリのインストール
EthernetライブラリはESP32とENC28J60をサポートしている以下のものを使用します。
Arduino IDEのライブラリマネージャから「UIPEthernet」で検索してインストールすることができます。
ESP32の公式フォーラムESP32 with ENC28J60 Ethernet Module では別のライブラリであるEtherCardからforkされたESP32対応ライブラリも試してみましたが、残念ながらビルドすることができませんでしたので、今回はUIPEthernetを使用して進めます。
5. コード
以下のコードをESP32に書き込みます。
#include <UIPEthernet.h> uint8_t mac[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; uint8_t IP[] = { 10, 0, 1, 8 }; uint8_t MASK[] = { 255, 255, 255, 0 }; uint8_t DNS[] = { 10, 0, 1, 1 }; uint8_t GW[] = { 10, 0, 1, 1 }; EthernetUDP udp; #define UDP_TX_PACKET_MAX_SIZE 700 char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; char ReplyBuffer[] = "acknowledged"; void setup() { Serial.begin(115200); Serial.println("starting..."); // Ethernet.begin(mac);// Use DHCP Ethernet.begin(mac, IP, DNS, GW, MASK); Serial.print("Local IP : "); Serial.println(Ethernet.localIP()); Serial.print("Subnet Mask : "); Serial.println(Ethernet.subnetMask()); Serial.print("Gateway IP : "); Serial.println(Ethernet.gatewayIP()); Serial.print("DNS Server : "); Serial.println(Ethernet.dnsServerIP()); udp.begin(3001); } void loop() { int packetSize = udp.parsePacket(); if (packetSize) { Serial.printf("Received packet of size %d\n", packetSize); IPAddress remote = udp.remoteIP(); Serial.printf("From %d.%d.%d.%d:%d - ", remote[0], remote[1], remote[2], remote[3], udp.remotePort()); udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); Serial.print("Contents: "); Serial.println(packetBuffer); // send a reply to the IP address and port that sent us the packet we received udp.beginPacket(udp.remoteIP(), udp.remotePort()); udp.write(ReplyBuffer); udp.endPacket(); } }
UIPEthernetを使って他の端末からpingを打って応答を確認するだけの場合は、loop()関数の中に
server.available();
だけを入れると良いでしょう。これを書かないとIPを取得できてもpingの応答が返りません。
6. 実行
シリアルモニタでログを確認します。通信相手はNode.jsを使うと簡単に用意することができます。正常に動作していれば、ログに受信したメッセージと相手先にReplyBufferで設定した文字列が表示されます。
動作が不安定だったり動作しなかったりする場合は、電源を別のものに変えたり接続のワイヤーを短くしたりするなどしてみてください。私は最初3.3VラインをESP32からではなく、外部電源から供給していましたがまったく動作しませず、ESP32から直接供給するように変更すると安定動作するようになりました。
7. まとめ
ENC28J60を使ってESP32(Arduino core for the ESP32)でUDP通信を行ってみました。Arduino core for the ESP32は現在でも頻繁に開発が行われており、未完成の部分や不安定な部分がありますが、ESP32は他のマイコンと比較すると入手性も良く、安価・高性能と大きなポテンシャルを持っています。これからも多くの人に使われることによってライブラリも洗練されると嬉しいですね。