Raspberry Pi Pico を有線LANにつないで通信する


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は本記事では扱いません。今後の挑戦課題となっています。

動画は次のツイートにあります

ソースコード

ENC28J60とホストのマイコンはSPIで通信します。クロック(SCK)は平常時はLowレベルで、立ち上がりエッジで信号線の読み書きを行うというフォーマットなので、次のフォーマット指定が必要でした。これに気付くまで数時間はまりました。

spi_set_format(SPI_PORT, 8, SPI_CPOL_0, SPI_CPHA_1, SPI_MSB_FIRST);