Raspberry Pi Picoは激安で素晴らしいのですが、通信機能がありません。Wi-FiもBluetoothもないので、せいぜいUART機能を使って、PCとRS-232Cで通信するくらいしかできません。安いのでとりあえず買ってはみたけど、使い道が思いつかないという声を聞きます。センサーで読み取った値をサーバーに送るくらいのことはしたいので、通信機能がほしいです。
本記事では、Raspberry Pi PicoにENC28J60というLANコントローラーを接続して、UDPパケットを送受信し、NTPサーバーから日時のデータを取得します。
▼全体像
プログラムは、10年くらい昔にATmega328PでENC28J60を制御したときのコードを再利用しています。
▼昔作ったやつ
ENC28J60は高機能なLANコントローラーではありませんので、TCP/IPの様な高度な機能は搭載されていません。イーサネットの生パケットを送受信することしかできません。上位のプロトコルはホストのマイコン側に実装します。少なくとも次のような機能がRaspberry Pi Pico側に必要です。
- ARP…IPアドレスからMACアドレスを問い合わせる。および応答する
- DHCPクライアント…ルーター等からIPアドレスを割り当ててもらう
- リゾルバ…インターネットホスト名をDNSサーバに問い合わせてIPアドレスを得る
- パケット通信…UDPパケットをイーサネットフレームの中に入れて送受信する
本記事ではNTPサーバに問い合わせして、データを取得するだけなのでUDP通信を使います。もし、ウェブサーバーなどを作りたかったら、TCPの通信機能を実装する必要があり、かなり大がかりなプログラムになってしまいますので、TCPは本記事では扱いません。今後の挑戦課題となっています。
動画は次のツイートにあります
#RaspberryPiPico とENC28J60で、有線LAN接続でNTPサーバから日時を取得するのできた! pic.twitter.com/eUOHTR7rFQ
— そらみみ (@soramimi_jp) February 11, 2021
ソースコード
ENC28J60とホストのマイコンはSPIで通信します。クロック(SCK)は平常時はLowレベルで、立ち上がりエッジで信号線の読み書きを行うというフォーマットなので、次のフォーマット指定が必要でした。これに気付くまで数時間はまりました。
spi_set_format(SPI_PORT, 8, SPI_CPOL_0, SPI_CPHA_1, SPI_MSB_FIRST);