公開日: 2023年10月29日

Raspberry Pi Pico でシリアル通信: "hello, world" を贈る

Raspberry Pi Pico (以下 Pico) は UART (Universal Asynchronous Receiver/Transmitter) によるシリアル通信が可能です。今回も例によって『インターフェース』誌 2023 年 7 月号のサンプルプログラムを使わせていただき、シリアル通信を試してみます。

使用する機材

今回は第 2 回の記事で列挙した機材をすべて使用します。

  • Raspberry Pi Pico H

  • Debug Probe

    今回は GDB によるデバッグは行いませんが、Debug Probe に搭載されている UART-USB 変換器を使ってパソコンに接続します。

  • ブレッドボード

    必須ではありませんが、あれば簡単に Pico の UART と Debug Probe を接続することができます。E-CALL ENTERPRISE 社の EIC-801 あたりが Pico にはちょうどいいサイズです。

  • Pico への給電用 USB ケーブル

接続は図 1 のようになります。ブレッドボードが よくわからないという方は取りあえず EIC-801 を買ってきて、 Pico の 1 番ピン (BOOTSEL ボタンや LED があるあたりに「1」と シルク印刷されているピン) が「5-c」の穴に来るように Pico を挿してください。そして Debug Probe に付属の UART 通信用ジャンパケーブル (オス) の黄色線を「5-a」、 橙色線を「6-a」、黒色線を「7-a」の穴にそれぞれ挿してください。 この配線の意味については「Pico の UART」の節と 「おまけ」の節を参照してください。

図 1: Pico と Debug Probe の接続
図 1: Pico と Debug Probe の接続

サンプルプログラムについて

今回使用するサンプルプログラムは『インターフェース』誌 2023 年 7 月号 pp.58-59 に掲載されている hello,world プログラムです。前回まで使用した L チカプログラムとほぼ同じですが、チカチカを開始する前に Pico の UART を使用して相手局に「hello,world」を送信します。GitHub で公開されているので clone してきてください。その中の part_2/sect_4 ディレクトリに今回使うサンプルコードが収められています。

% git clone https://github.com/ytoyoyama/interface_trykernel.git
% ls interface_trykernel/part_2/sect_4/
application/    boot/       include/    kernel/         linker/

サンプルプログラムのシリアル通信設定は、表 1 のように固定されています。

表 1: サンプルプログラムの通信設定
項目設定値
ボーレート1)

115200

データビット

8 bit

パリティ

なし

ストップビット

1 bit

フロー制御

なし

  1. 余談ですが、「ボーレート (単位: baud)」と「ビットレート (単位: bps)」は同義に使われがちですが別物だそうです。

    • ボーレート = 1 秒間の変調回数
    • ビットレート = 1 秒間に伝送するビット数

    シリアル通信では 1 baud = 1 bps になるため、両者が一致します。参考 URL:

    ボーレート(baudrate)と転送速度(bps)
    https://kei-sakaki.jp/2008/04/06/baudrate-and-bps/

Pico の UART

Pico の UART には UART0、UART1 の 2 チャンネルがあり、デフォルトで利用可能なのは UART0 です。UART0 の送信線 (UART0 TX) は 1 番ピン、受信線 (UART0 RX) は 2 番ピンからそれぞれ取り出せます ([1] Chapter 1 参照)。また、信号の基準電圧となる GND がすぐとなりの 3 番ピンに用意されています。よってこの 1~3 番のピンを使って通信を行います。

UART のレジスタ設定

Pico の、というよりも Pico に搭載されているマイコン RP2040 の UART0 関連レジスタは 0x40034000~ の番地に存在します ([2] 4.2.8 節)。当該ソースコードは kernel/syslib.c のtm_com_init関数です。

UART0 CR レジスタ (syslib.c 14 行目)

主に UART0 のチャンネル自体に関する設定を行っています。EN ビット (bit0) を立てて UART0 そのものを有効にし、TXE (bit1)、RXE (bit2) を立てて送受信をともに可能としています。また、RTSEN (bit14)、CTSEN (bit15) を 0 にすることでハードウェアフロー制御を無効にしています。

UART0 LCR_H レジスタ (syslib.c 13 行目)

表 1 に基づいてシリアル通信設定を行っています。

  • PEN (bit1) = 0 でパリティなし
  • STP2 (bit3) = 0 でストップビット 1
  • FEN (bit4) = 1 で FIFO (送信用、受信用のバッファ) 有効
  • WLEN (bit5,6) = 3 でデータビット 8

UART0 IBRD、FBRD レジスタ (syslib.c 11、12 行目)

ボーレートが 115200 となるように設定している部分ですが、ここにセットする値の計算はちょっと厄介です。詳細は [2] 4.2.3.2.1 節および 4.2.7.1 節を参照してください。それによればボーレートはちょうど 115200 とはならずに 115207 となり、誤差は約 0.006 % となります。UART での 2 局間の相対的な許容誤差は 4% 程度とのことなので (下記 URL 参照)、1 局分を 2% としても十分小さいといえるのではないでしょうか (たぶん…)。

Makefile を書く

第 2 回の記事で作った L チカ用の Makefile をちょっと変更します。PRGNAMEを hello に変更、ソースが置かれているディレクトリを ../../part_2/sect_4 に変更、vpathに kernel ディレクトリを追加、の 3 ヵ所です。

interface_trykernel/part_2/sect_4/Makefile (差分)
--- ../sect_3/Makefile  2023-10-20 11:53:24.662084000 +0900
+++ Makefile    2023-10-27 22:51:11.180798000 +0900
@@ -1,10 +1,10 @@
-PRGNAME := blink
+PRGNAME := hello
 ARCH = arm-none-eabi

 LIBAEABI := 0

-SRCROOTDIR := ../../part_2/sect_3
-vpath %.c $(SRCROOTDIR)/application:$(SRCROOTDIR)/boot
+SRCROOTDIR := ../../part_2/sect_4
+vpath %.c $(SRCROOTDIR)/application:$(SRCROOTDIR)/boot:$(SRCROOTDIR)/kernel
 TOOLDIR := ../tools
 BLDDIR := ./build
 EXEFILE = $(BLDDIR)/$(PRGNAME)

sect_4 ディレクトリに Makefile を追加したことで、~/pico/repo/interface_trykernel/ 以下のディレクトリは次のようになりました (前回以前の分も含む)。★印は私が追加したディレクトリとファイルです。

% tree ~/pico/repo/interface_trykernel/
~/pico/repo/interface_trykernel/
├── build_part2                          ★
│      ├── libs                          ★
│      │      └── libaeabi-cortexm0.a    ★
│      ├── sect_3                        ★
│      │      └── Makefile               ★
│      ├── sect_4                        ★
│      │      └── Makefile               ★
│      └── tools                         ★
│             ├── elf2uf2                ★
│             └── picowrite.sh           ★
├── part_2
│      ├── sect_3
│      └── sect_4
...

この Makefile と picowrite.sh は GitHub でも公開しています。

あとはこれまでと同様に、ビルドしてフラッシュメモリに書き込みます。

% cd ~/pico/repo/interface_trykernel/part_2/sect_4/
% gmake
# ../tools/picowrite.sh build/hello.uf2

cu コマンドを使って通信確認する

話を簡単にするために、書き込み完了後 Pico および Debug Probe の USB ケーブルを抜いてパソコンから切り離した状態になっているとします。ここから動作確認を始めましょう。まず UART で通信可能な状態にします。Debug Probe の USB ケーブルをパソコンに挿し、端末エミュレータを新しく開いてシリアル通信ソフトを起動します。FreeBSD では標準で cu コマンドが利用できます。

# cu -s 115200 -l /dev/cuaU0
Connected

-s オプションでボーレートを指定します。パリティビットはデフォルトで「なし」です。データビットは 8、ストップビットは 1 で固定のようです (マニュアルに記載なし)。cuaU0 の部分は環境によって変わるかもしれません。とはいえ Debug Probe のように USB シリアル変換器で接続する場合は、たいてい cuaU0 や cuaU1 になると思います。ちなみに今回は GDB によるデバッグを行うわけではないので、OpenOCD は起動しておかなくても大丈夫です。

これで受信の準備ができたので、Pico の USB ケーブルを挿して電源を入れてみます。「hello,world」と表示されて Pico の LED が点滅を開始すれば成功です。

# cu -s 115200 -l /dev/cuaU0
Connected
hello,world

よさそうですね、Pico からのメッセージをたしかに受け取ることができました。シェルに戻るには「~.」 (チルダとピリオド) を入力します。

おまけ: ブレッドボード覚え書き

電子工作に慣れていないもので、ここにブレッドボードの初歩を書きとめておきます。無用の方は読み飛ばしてください。

ブレッドボードは形状も大きさもさまざまなものが売っていますが、本稿でおすすめした EIC-801 は図 2 のような概形をしています (ポンチ絵なので細部は正確ではありません)。

  • 縦に見たときに、30 行 (1 ~ 30) × 10 列 (a ~ j) = 300 個の穴 (ソケット) があり、各行の a ~ e と f ~ j はそれぞれ電気的につながっています (緑で描いたライン)。図 1 の例では黄色のジャンパ線を「5-a」の位置に挿しましたが、「5-b」でも (物理的には厳しいものの、理屈のうえでは「5-d」や「5-e」でも) いいわけです。
  • その両脇は電源供給用のラインで、プラス側、マイナス側それぞれ縦方向に電気的につながっています (赤、青で描いたライン)。※ 今回は USB から給電するので、このラインは使いません。
  • a ~ e 列の島と f ~ j 列の島の間には溝が切られていて、両者は電気的にも切断されています。
  • ブレッドボードにマイコンボードを挿すときには、必ずこの溝をまたぐように挿します (図 3)。じゃないと基板の両端のピンどうしが接続されて短絡してしまいます (まあこのサイズなら溝をまたがないように挿そうと思っても挿せませんけど…)。
図 2: EIC-801 概形
図 2: EIC-801 概形
図 3: マイコンボードを挿したところ
図 3: Pico を挿したところ

参考資料

Raspberry Pi Pico 実験室