ESP32 に有線LANをつなげる

(2020/06/18追記 続きの記事を書きました→
「ESP32 の 有線LAN / 無線LANの書き分け」
https://qiita.com/nanbuwks/items/f7e3a8ed24d56bb56501 )


ESP32には WiFi 機能があるが、有線LANの機能も入っている。

ESP32 Series Datasheet
https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf

によると、4.1.7 Ethernet MAC Interface に以下のようにある。


> An IEEE-802.3-2008-compliant Media Access Controller (MAC) is provided for Ethernet LAN communications.
ESP32 requires an external physical interface device (PHY) to connect to the physical LAN bus (twisted-pair, fiber,
etc.). The PHY is connected to ESP32 through 17 signals of MII or nine signals of RMII.

(MIIかRMIIを使ってツイストペアやファイバー等を使ったLANへの接続ができる)

# MIIとかPHYとか

以下の意味です。

PHY: physical layer ・・・OSI参照モデルでいう最下層（第1層：物理層）。 アナログ信号処理などを行う。
MAC：physical layer ・・・IEEE 802プロトコルにおいて、OSI参照モデルでいう第2層（データリンク層）の下層にあたる。MACアドレスはこの層に付く。MACアドレスによる通信、PHYでの衝突調停などを行う。ちなみにMACに対応する第2層の上層はLLC。

MII:100BaseのPHY層と上位層（MAC層）を接続するための信号規格。1ポートに対し18本の信号線が必要。
RMII:MIIに必要な信号線を削減したもの。1ポートに対し9本の信号線が必要。


なお、MIIを拡張したものとしてGMII、RGMII、SGMII、OSGMIIなどの規格がある。


MAC(MEDIA ACCESS CONTROL)とは、第2層にある。ESP32には第2層まで実装されているということですね。

ESP32にPHYをつけて使えるようにするためには、PHYチップ、パルストランス、RJ45コネクタ、クロック、電源、抵抗やコンデンサ、ノイズフィルターぐらいが必要。その上で適切な制御をすることで有線LANで通信することができる。


#  配線方法

MII (Media Independent Interface) および RMII (Reduced Media Independent Interface)の配線について。

データシート esp32_technical_reference_manual_en.pdf によると


|EMAC SIGNAL|ESP32 GPIO|
|:--:|:--:|
|EMAC_TX_CLK|IO0|
|EMAC_RXD2	|IO1(U0TXD)|
|EMAC_TX_ER|	IO4|
|EMAC_RX_CLK	|IO5||
|EMAC_TXD3	|IO12|
|EMAC_RX_ER	|IO13|
|EMAC_TXD2	|IO14|
|EMAC_RXD3	|IO15|
|EMAC_CLK_OUT|	IO16|
|EMAC_CLK_180|	IO17|
|EMAC_TXD0	|IO19|
|EMAC_TX_EN	|IO21|
|EMAC_TXD1	|IO22|
|EMAC_RXD0	|IO25|
|EMAC_RXD1	|IO26|
|EMAC_RX_DV	|IO27|
|emac_mdc|	GPIO Matrix |
|emac_mdi|〃|
|emac_mdo|〃|
|emac_crs|〃|
|emac_col|〃|

GPIO Matrix と書いたところは、再配置可能かな？

# PHY追加以外の有線LAN接続

これまでに述べた方法とは別に、シリアル通信やSPIで有線LANインターフェースをつなげることもできます。

チップにMAC,PHYが入っているので、MACの無いArduinoなどでも有線LANをつなげることができます。

以下のものはSPIでつなげる、Arduinoなどでよく使われるものです。


## WIZnet W5100/W5500 
MAC,PHYが入っていてSPIで動きます。W5100はArduinoの純正Etnernetシールド（V1)、W5500はArduinoの純正Etnernetシールド（V2)に使われていて、ArduinoのEthernet2ライブラリで使えます。
USR-ES1 W5500を使ったモジュール
https://www.usriot.com/download/ES1/USR-ES1-EN-V1.0.pdf
USR-ES1をESP32に繋ぐ例
http://okiraku-camera.tokyo/blog/?p=7220


## Microchip ENC28J60
https://www.switch-science.com/catalog/19/
MAC,PHYが入っていてSPIで動きます



# RMII での接続をやってみる

今回は、せっかく ESP32 に入っている MAC を活かし、なおかつ MII で ESP32 を接続すると配線本数が多くて使いづらい、ということで RMII で接続します。

さて、RMII でつながる PHY チップは何を使ったらいいかな？



## WIZnet IP101GRI

MIIおよびRMMI接続のPHYチップ。
ESP32-Ethernet-Kit では、RMII接続で使っている。
「ESP32-Ethernet-Kit V1.0 Getting Started Guide」
https://www.mouser.com/pdfDocs/Espressif_ESP32-Ethernet-Kit_GS.pdf

## Microchip LAN8720A


OLIMEX の ESP32-EVB ボードhttps://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware
には、LAN8710Aが使われていました。

LAN8710AはLAN8710AはMIIおよびRMII接続両方をサポートしていますが、
ESP32-EVB においては LAN8710A は RMII で接続しているみたいです。

また、LAN8710AのバリエーションとしてLAN8720Aがあります。違いとして、LAN8720AはRMIIのみサポートらしいです。



巷の作例では、LAN8720がよく使われているようで、LAN8710A/LAN8720Aで接続を試してみることにします。



# 安価なボード

LAN8720A ボードとして安価なボードを taobao で買ってみました。
![IMG_20200206_144120.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/07e1be49-ff6d-eb72-54d8-597d698b3ff3.jpeg)

あとで気が付きましたが、これらはWaveShare の LAN8720 ETH Board
https://www.waveshare.com/lan8720-eth-board.htm
 のパチもんらしいです。

上記サイトには

> CAUTION: This product is protected by patent, anyone making copies/knock-offs SHOULD be held liable pursuant to law.

とあります。可能な限りこちらから購入するべきでしょうね・・・。


# LAN8720 ETH Board 結線方法


https://ht-deko.com/arduino/esp-wroom-32.html
を参考に、

RMII (Reduced Media Independent Interface)

|RMII SIGNAL|ESP32 GPIO|LAN8720 board sylk|改造方法|
|:--:|:--:|:--:|:--:|
| PHY_POWER| GPIO17  | NC |OSC1番ピンに接続および4.7kΩでプルダウンに改造|
| EMAC_TXD1 |  GPIO22  | TX1||
| EMAC_TXD0   |GPIO19 | TXD||
| EMAC_TX_EN  |GPIO21 | TX_EN||
|EMAC_RXD1   |GPIO26 |  RX1||
| EMAC_RXD0   | GPIO25 |RX0||
| EMAC_RX_DV|GPIO27   | CRS||
| EMAC_TX_CLK |GPIO00 | nINT/REFCLK| 4.7kΩでプルアップに改造 |
| SMI_MDC    |GPIO23  | MDC||
| SMI_MDIO  |GPIO18   | MDIO||
|GND|             |  GND||
|3V3|              |  VCC||

と接続します。

しかしながらこれだと、ESP32に接続するためにGOIO0のOSCからのクロック供給とブートモード機能といの干渉が起こります。それの回避のために改造が必要となりますが、このように試してみました。

![IMG_20200206_151858.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d82015f1-59ac-7ddf-0dc6-8729a03f8b01.jpeg)


発振子の足をNCのピンに引き出して、GPIO17につなぎます。
GPIO17はコードの中でクロック出力の有効化・無効化をしてくれています。
https://sautter.com/blog/ethernet-on-esp32-using-lan8720/



# スケッチ

Arduino開発環境で、「ファイル」-「 スケッチ例」-「WiFi」のETH_LAN8720_internal_clock

再度
https://ht-deko.com/arduino/esp-wroom-32.html
を参考に、接続指定を以下のように変更します。

```
/*
    This sketch shows how to configure different external or internal clock sources for the Ethernet PHY
*/

#include <ETH.h>

/* 
   * ETH_CLOCK_GPIO0_IN   - default: external clock from crystal oscillator
   * ETH_CLOCK_GPIO0_OUT  - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
   * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
   * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/

#define ETH_CLK_MODE    ETH_CLOCK_GPIO0_IN

// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN   17

// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE        ETH_PHY_LAN8720

// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR        PHY1

// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_MDC_PIN     23

// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN    18

```

# 実行

以下のようにして、接続できました。

![IMG_20200206_153719.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4718f8b8-58ce-929f-b1da-c6c165015895.jpeg)


```

ETH Connected
ETH MAC: 30:AE:A4:38:98:4F, IPv4: 192.168.42.17, FULL_DUPLEX, 100Mbps

connecting to google.com
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Thu, 06 Feb 2020 08:57:58 GMT
Expires: Sat, 07 Mar 2020 08:57:58 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
closing connection


connecting to google.com
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
.
.
.
```

# トラブルシューティング

```

E (1055) emac: Timed out waiting for PHY register 0x2 to have value 0x0007(mask 0xffff). Current value 0x0000
E (2055) emac: Timed out waiting for PHY register 0x3 to have value 0xc0f0(mask 0xfff0). Current value 0x0000
E (2055) emac: Initialise PHY device Timeout

```

となる。
これはプルアップやプルダウンをしわすれていたことによるものです。


# 基板化

ここまで試してきた ESP32 ＋ LAN8720 の構成で改めて基板化してみました。

![IMG_20200207_011554.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b7895e3b-6cf2-8c8d-254a-a4bf43793fda.jpeg)


写真左上の空きパターンはnRF52840/nRF52833ボード「アオノドン」用です。
これを載せると以下のマルチプロトコルが扱えて、ぼくのかんがえたさいきょうの基板感があります。

- 有線LAN(ESP32)
- 無線LAN(ESP32)
- Bluetooth5.0(ESP32 https://launchstudio.bluetooth.com/ListingDetails/97856 )
- Bluetooth mesh(ESP32)
- Bluetooth5/5.1/mesh(nRF52840/nRF52833)
- Zigbee(nRF52840/nRF52833)
- Thread(nRF52840/nRF52833)
- ANT(nRF52840/nRF52833)
- 2.4GHz Nordic独自プロトコル(nRF52840/nRF52833)

とりあえず、Zigbeeと有線LANのゲートウェイとして動かす予定です。