Raspberry Pi Zero WでベアメタルUART

mini-uart.png

昨日のLチカに続いて、Raspberry Pi Zero WでUARTでのテキスト送受信を試してみました。
コードは以下で公開しています。

bare_matal_rpi_zero/mini-uart at master · boochow/bare_matal_rpi_zero

Raspberry Piシリーズでは、UARTはGPIO14/GPIO15を使うようになっており、その接続ピンは先日作った実験用ボードでUSB-UARTアダプタに接続できるようにしてあります。

最初は、昨日と同じく「BareMetalで遊ぶ Raspberry Pi」の通りに進めていたのですが、どうしてもUARTが反応してくれません。
これはどうもPi Zero WのI/OがPi model Aと違うのだろう、ということでいろいろネットの情報を探してみました。

その結果、どうやらPi Zero WではGPIO14/GPIO15にUARTを割り当ててはいるものの、正式なUARTを使用することはできず、mini-UARTという簡易型UARTを使用するか、またはBluetoothを使わない前提でUARTを使うか、という選択であるらしいことが分かりました。

以下のdwelch67さんのリポジトリにあるPi Zero用のUARTサンプルはPi Zero Wでも動作しました。

dwelch67/raspberrypi-zero: Raspberry Pi Zero baremetal examples

このサンプルは、Mini-UARTを使っています。
Mini-UARTは上記の本でも解説されていますが、正規のUARTよりも若干機能が制約されます。
BCM2835 ARM Peripheralsによると、Mini-UARTはUARTと違って

• Break detection
• Framing errors detection.
• Parity bit
• Receive Time-out interrupt
• DCD, DSR, DTR or RI signals

をサポートしないと書かれています(2.2節)。
なので、上記の本では発展性を考慮してmini-UARTではなく本来のUARTを使って解説されているのでした。

mini-UARTはどのRaspberry Piでも動作しますが、本来のUARTが動作しないのはPi Zero WとRaspberry Pi3のようです。Raspberry Pi3については、以下でちらりと触れられていました。

Raspberry Pi3 のシリアルコンソールで通信速度が合わない – Qiita

Raspberry Pi 3 になって、Bluetooth のサポートのために、GPIO の UART の割り当てが変更され、uart1 を使うようになった。
uart0 は Bluetooth が使うようになっている。

おそらく、Pi Zero Wについても同じ事情でUARTの割り当てが変更になったと思われます。

さらに調べていくと、以前も触れたPi用ベアメタルOSであるultiboのフォーラムで以下のような書き込みを見つけました。

GPS Receiver connected to UART on Raspbberry Pi Zero W – ultibo.org

When the WiFi/BT was added FPF swapped the Uarts.
TX0/RX0 on the Header is now the miniuart Page 8 manual.
The BT chip uses Uart 1 page 175.
Page 102 show the peripheral alternatives for the header 14/15.
As the WiFI/BT is not yet supported by Ultibo, you could alt5 the GPIO pins 14/15 to use the PL011 uart.

このPage XXというのは、前述のBCM2835 ARM Peripheralsのページ番号のようです。
GPIO14, GPIO15のモードをALT 5にすればmini UARTが使える、ということですが、確かに上に挙げたdwelch67さんのコードでも、そのようにしてmini UARTを使っていました。

PL011 uartというのはARMが実装しているUARTで、これはARMからマニュアルが配布されています
しかし今回はとりあえずmini-UARTの動作を確認してみることにしました。
うまく動かなくても、上記のdwelch67さんのコードと見比べれば、レジスタの操作が正しいかどうか確認できるからです。

思ったよりだいぶ手間取りましたが、以上の結果を踏まえて初期設定~キャラクタの出力~エコーバックを行うコードを何とか動作させることができました。
あまりオリジナルな部分はないのですが、前回のLチカ同様、インラインアセンブラを使っているので見かけ上はCのコードだけになっているのが取り柄です。

なお、mini-UARTについて調べている過程で行き当たった以下のページで紹介されているコードは、かなり短くてまさにmini-UARTは簡易版UART !、という感じですので一見の価値があります。

ラズパイ3でベアメタル – その3:シリアル通信(UART)でデータ送信(割り込みなし) – へにゃぺんて@日々勉強のまとめ

ただし、これだけ短いコードにするにはブートローダにmini-UARTの初期化をさせる必要があり、それにはSDカードに置く「config.txt」に「enable_uart=1」を記載する必要があるそうです。
config.txtなしの状態でも初期化されているのか気になって、config.txt抜きで動作させようと試みたのですが、少なくともGPIO14、15をALT5にする設定と、mini-UARTのボーレートの設定、データ長を8bitにする設定は行う必要がありました。

コメント