ラズパイのシリアルポート(mini-UART)の割り込み処理を書く

連休で割と時間が取れるので、Raspberry PiベアメタルMicroPythonでこれまで気になっていながら、手をつけていなかった部分をいろいろいじっています。

タイマー割り込みを作ったおかげで、Raspberry Piの割り込み処理が分かってきたので、シリアルポート受信の割り込み処理を行ってみました。
割り込み処理ができると、ループ処理中などREPL以外のタイミングでのキーボード入力をバッファに貯めておくことができるようになります。
実装方法としては、リングバッファを用意して、UARTの割り込みハンドラではリングバッファに追記し、MicroPython側もリングバッファから読み取るようにします。

UARTの割り込みが有効にでき、割り込みハンドラを呼び出せるようになれば、それほど難しくはありません。

と思ったのですが・・・マニュアル(P.12)の記載ミスに泣かされました。
なんと、mini-UARTの割り込みイネーブルレジスタ(IER)のRxとTxの割り込みの記載が逆になっていました。

mini-uart-ier.png

タイトルが「IER」ではなく「IIR」になっているのはまだ笑って許せるレベルです。
上の表では、データ受信時の割り込み許可ビットはbit 1になっていますが、実はbit 0とbit 1は逆で、bit 1は送信バッファが0のときの割り込みを有効にします。
うまく受信できないのに、なぜか割り込みハンドラは連続的に呼ばれるという現象が起きていたのですが、これならそうなって当然です。

手がかりは、いつものdwelch67さんのサンプルの中にありました。

raspberrypi/uart04.c at master · dwelch67/raspberrypi

こちらのコードでは、IERの設定が

PUT32(AUX_MU_IER_REG,0x5); //enable rx interrupts

となっています。私が最初に書いたコードは2を設定(bit 1を1にするために)していたので、明らかにおかしいですね。

いろいろ調べた結果、Broadcomのマニュアルに対する正誤表がこちらにありました。
(とても多くの誤りがあることが判ります。)

BCM2835 datasheet errata – eLinux.org

P.12に関する記載を見ると

Bits 3:2 are marked as don’t care, but are actually required in order to receive interrupts.
Bits 1:0 are swaped. bit 0 is receive interrupt and bit 1 is transmit.

とあります。

確かに、dwelch67さんのコードでは、bit 0とbit 2を1にしていますが、Bits 3:2の役割が分かりません。
また、試しにbit 0だけを有効にして動かしてみたところ、ちゃんと受信できました。

マニュアルの記載によると、このmini-UARTは昔よく使われていたシリアルポート制御チップの16550をベースにしているようです。
そこで、ネットで16550の情報を調べてみました。

すると、16550のIERは

bit 0: データ受信時に割り込み
bit 1: 送信バッファが空になったとき割り込み
bit 2: ラインステータスレジスタ(LSR)が変化したとき割り込み
bit 3: モデムステータスが変化したとき割り込み

という仕様であることが分かりました。
mini-UARTのIERもこれを踏襲しているものと仮定すると、LSRの変化とは何を示しているのでしょう。
ラインステータスレジスタについては、マニュアルには以下のように記載されています。

mini-uart-lsr.png

bit 0: 受信FIFOバッファにデータあり
bit 1: 受信FIFOバッファが溢れた

ということで、IERのbit 2は「データ無し→あり」になった瞬間、およびバッファがあふれた瞬間に割り込みをかけたい場合に使用すると思われます。
一方、bit 0はとにかく1文字受信したら割り込みがかかるということかと思われます。

IERのbit 2では検出できるがbit 0では検出できないシチュエーションは、あまり無いように思いますので、とりあえずIERはbit 0だけを使うことにしました。

mini-UARTの割り込みはIRQ #29のAUX割り込みになりますが、AUX割り込みはSPI1、SPI2とも共用しています。
そのため、割り込みの原因がこの3つのうちどれだったのかを示すのがAUX_IRQレジスタです。

mini-uart-pending.png

AUXラインに割り込みがあったときは、AUX_IRQレジスタのbit 0が立っているときのみmini-UARTの割り込みハンドラを呼ぶようにしています。
mini-UARTのIIRレジスタでは、さらに割り込み要因が送信受信のどちらだったかが確認できます。

mini-uart-iir.png

bit 0が、mini-UARTで処理が必要な割り込みがあるかどうか、bit 1がmini-UARTの送信バッファが空でないかどうか、bit 2がmini-UARTの受信データがあるかどうかを示すフラグになっています。

コメント