Hatena::ブログ(Diary)

へにゃぺんて@日々勉強のまとめ

2016-05-29

ラズパイ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)
  • ビット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バイト追加しても良いことがわかります。


2.2. UARTの送信FIFOへ1バイト追加

Mini UARTの場合、送信FIFOへのデータ追加と受信FIFOからのデータ取り出しは

共にIOレジスタで行います。

(レジスタへの書き込みで送信FIFOへデータ追加、

レジスタ読み出しで受信FIFOからのデータ取り出し)


ここではラズパイ3からPCへデータを送信してみたいので、

IOレジスタへデータを書き込んでみます。

なお、IOレジスタのアドレスは0x3f215040です。


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同様にmicroSDFAT32パーティションに配置しておいて下さい。

enable_uart=1

4. 動作確認

PCとRaspberry Pi 3を接続し、Raspberry Pi 3を起動すると、

PC側でシリアルポートを開いている端末アプリの画面に「AAA...」と'A'が立て続けに表示されます。


5. その他、参考になる記事

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

リンク元