ラズパイ3でベアメタル - その3:シリアル通信(UART)でデータ送信(割り込みなし)
今回は、UARTを使用してシリアル通信で「ラズパイ3からPCへデータ送信」を作ってみます。
まずは割り込みは使用せずに作ってみます。
なお、Raspberry Pi 3で64bitベアメタル(bare metal)プログラミングを試してみる
本シリーズの目次はコチラです。
0. PCとRaspberry Pi 3のシリアル通信の準備
PCとRaspberry Pi 3のシリアル通信での接続方法は、「Raspberry Pi シリアル通信」辺りで検索すると色々と出てきます。
(Raspberry Pi 3の記事も既に色々なサイトで書かれている様ですが、Raspberry Pi側のピン番号等、
Raspberry Pi 2と同じなので、2の記事を参考にしても良いと思います。)
例えば、以下の記事が参考になるかと思います。
1. Mini UARTについて
UARTはシリアル通信を実現するために、送信・受信それぞれ1本ずつの信号線上に、
通信データフォーマットに合わせた形で1ビットずつ送信したり、その逆(受信)を行ったりする機能です。
BCM2837、というより、少なくともBCM2835からのBroadcomのSoCには、
以下の2つのUARTが存在します。(データシート(*1)を参照)
- UART1: Mini UART
- UART0: PL011
今回は、「最小限のコードで簡単に使える方を」という判断で、UART1のMini UARTを使います。
(VideoCoreにより初期化されているため、初期設定なしで使えます。)
(*1): Peripheral specification
(BCM2837のPeripheral specificationは公開されていないので、これが一番参考になります。)
2. UARTでのデータ送信について
UARTには送信・受信それぞれにFIFOがあり、
データ送信の際は、送信FIFOへデータを追加すると、
UARTにより送信の信号線上に1ビットずつ送出されます。
送信は1バイトずつで、手順は以下のとおりです。
1. UARTの送信FIFOの状態を確認
2. UARTの送信FIFOへ1バイト追加
なお、以降の説明で登場するレジスタのアドレスは、
(*1)で説明されているBCM2835のアドレスをRaspberry Pi 3用(BCM2837)に読み替えたものです。
(読み替えについてはその2:GPIO制御のブログ記事の通りです。)
2.1. UARTの送信FIFOの状態を確認
UARTの送受信のFIFO状態を確認するには、LSR(Line Status Register)というレジスタを使用します。
LSRのアドレスは0x3f215054で、送信FIFOの状態確認には、以下の2つのビットを確認します。
- ビット6: Transmitter idle(以降、TX_IDLE)
- 送信FIFOが空であり、かつトランスミッターがアイドル状態(最後のビットの送り出し(シフト)が完了した)場合に1がセットされる
- ビット5: Transmitter empty(以降、TX_EMPTY)
- 送信FIFOが少なくとも1バイト受け付けられる場合に1がセットされる
この2つのビットの組み合わせに対し、UARTのTxFIFOが1バイト受付可能か否かをまとめると以下のとおりです。
TX_IDLE | TX_EMPTY | 送信FIFOは1バイト受付可能か |
0 | 0 | 受付不可 |
0 | 1 | 受付可 |
1 | 0 | 受付可、ただしTX_IDLE=1の時点でTX_EMPTY=1であるはずなので、この組み合わせは無い |
1 | 1 | 受付可 |
この表から、TX_IDLEとTX_EMPTYが共に0ではない事を確認すれば、送信FIFOへ1バイト追加しても良いことがわかります。
3. ソースコード('A'を送信し続ける)
以上を元に、「無限ループで文字'A'を送信し続ける」ソースコードは以下のとおりです。
#define MU_IO (*(volatile unsigned int *)0x3f215040) #define MU_LSR (*(volatile unsigned int *)0x3f215054) #define MU_LSR_TX_IDLE (1U << 6) #define MU_LSR_TX_EMPTY (1U << 5) int main(void) { while (1) { while (!(MU_LSR & MU_LSR_TX_IDLE) && !(MU_LSR & MU_LSR_TX_EMPTY)); MU_IO = (unsigned int)'A'; } return 0; }
ソースコードのビルドとRaspberry Pi 3での実行方法は以下のブログ記事を参照して下さい。
また、Makefileを加えた必要なファイル一式は
以下のGitHubのリポジトリの「uart_tx_char_simple」ディレクトリにあります。
上記のリポジトリをcloneしてビルドするまでの手順は以下のとおりです。
[PC]$ git clone https://github.com/cupnes/bare_metal_aarch64.git [PC]$ cd bare_metal_aarch64/uart_tx_char_simple/ [PC]$ make [PC]$ ls kernel8.img kernel8.img
加えて、UARTの初期設定をVideoCoreで実行されるファームウェアに任せたいので、
ファームウェアが参照する設定ファイル「config.txt」もmicroSDに配置する必要があります。
以下の「config.txt」をkernel8.img同様にmicroSDのFAT32側パーティションに配置しておいて下さい。
enable_uart=1
4. 動作確認
PCとRaspberry Pi 3を接続し、Raspberry Pi 3を起動すると、
PC側でシリアルポートを開いている端末アプリの画面に「AAA...」と'A'が立て続けに表示されます。