今のサンプルの実装って
- boot.S で JTAG の初期化してる
- GPIO の初期化も boot.S でやってる
ということになってたり。とりあえず現状含めて UART な初期化のあたりの盛り込みというか色々試験してみたいと思います。
現状確認
まず、boot.S から呼び出されている GPIO の初期化が以下。
{% gist 11282290 %}
最初に GPPUD なレジスタの 0x2 を代入して wait 150 cycle してます。マニュアルの記述によれば Enable Pull Up controll とのこと。
で、次に GPPUDCLK なレジスタのビットを全部立てて wait 150 cycle した後に GPPUDCLK と GPFSEL なレジスタを 0 で初期化してます。
つうかこの実装、delay にループ使ってますね。とりあえずここではこんなもの、という理解でかつ、現状を羅列しておくと
- pullup all されている (GPPUD は 0x02)
- GPPUDCLK、GPFSEL は全て 0 で初期化
ということになるのかどうか。GPPUDCLK を初期化した後に wait させてないけどいいのかな。
で、boot.S の中で init_gpio 呼び出して戻ってきたら JTAG なレジスタの初期化をしてます。コードの断片を以下に。
{% gist 11282860 %}
あ、.L2 のあたり以下な記述です。
.L3:
.align 2
.L2:
.word 538968072
.word 538968064
こうしてみるに自分で書いときながら可読性ゼロだな。で、最後におもむろに kernel_main な手続きに、という形です。ので状態としては
- GPFSEL0 の 4 にあたる場所が 0x04 になってる
- GPFSEL2 の 22、27、25、24 にあたる場所が 0x03 になってる
のか。これも確認できるはず。GPFSEL は
- 0 が 0x20200000
- 2 が 0x20200008
になるのか。先に計算するの面倒なのでとりあえず結線して kernel_main の入口で止めてレジスタ確認してみます。
ちなみに GPPUD は 0x20200094 で良いのかな。GPPUDCLK が以下?
- GPPUDCLK0 : 0x20200098
- GPPUDCLK1 : 0x2020009c
む、チュートリアルの実装に誤りがありますね。GPPUDCLK1 が 0x20200098 になってます。おそらく使っていないのだろうな。
後天性記憶不全
どこかに記録してすぐ見れるように、と思いつつアレです。以下が JTAG な接続。
| raspberry pi | ARM-USB-TINY-H |
|--------------|----------------|
| 1 | 1 |
| 7 | 5 |
| 13 | 7 |
| 15 | 3 |
| 18 | 13 |
| 22 | 9 |
| 25 | 6 |
以下がシリアルの pin です。
- 6 : GND
- 8 : TX (GPIO14)
- 10 : RX (GPIO15)
ということで結線して確認開始。とりあえず以下、GPPUD と GPPUDCLK
(gdb) x/x 0x20200094
0x20200094: 0x00000002
(gdb) x/x 0x20200098
0x20200098: 0x00000000
(gdb) x/x 0x2020009c
0x2020009c: 0x00000000
そのまんまですね。次は GPFSEL か。こっちはちょっと確認大変。
(gdb) x/x 0x20200000
0x20200000: 0x00002000
(gdb) x/x 0x20200008
0x20200008: 0x0061b0c0
ズルして bit に直しました。
-
0x00002000 : 10000000000000
00 000 000 000 000 000 010 000 000 000 000
右から 0、1、2 なので FSEL4 が 0x2?
って思ったら ALT5 は 0x02 と、でした (滝汗
もひとつが以下。
- 0x0061b0c0 : 11000011011000011000000
ええと、FSEL22, FSEL24, FSEL25, FSEL27 が 0x3 になってますね。
00 000 000 011 000 011 011 000 011 000 000
こちらも OK です。とは言え、とりあえず JTAG 接続は問題無いのでこうなってないと駄目なのか。
ちなみに、continue でプログラム終了したら C-c でもっかい load したらプログラムが再起動されますね。これは便利。次はシリアル関連のレジスタの値の確認か。
uart_init 直後
レジスタ確認を、なんですが何を確認すれば良いのか、からですね。uart_init 見てみるに
- UART0_CR (0x20201030) が 0x301 とかになってるはず
- GPPUDCLK0 (0x20200098) の 14 と 15 が 1 になってるはず (0 で初期化されていた)
- GPFSEL1 (0x20200004) の 4 および 5 が 0x04 になってるはず
- UART0_ICR (0x20201044) が 0x7FF
- UART0_IBRD (0x20201024) が 1
- UART0_FBRD (0x20201028) が 40
- UART0_LCRH (0x2020102c) の 4, 5, 6 番目のビットが 1
- UART0_IMSC (0x20201038) の 1, 4, 5, 6, 7, 8, 9, 10 が 1
書き方乱暴ですが確認を。とりあえず以下。
(gdb) x/x 0x20201030
0x20201030: 0x00000301
(gdb) x/x 0x20200098
0x20200098: 0x00000000
(gdb) x/x 0x20200004
0x20200004: 0x00024000
期待値になってるのかどうか。GPFSEL1 が
- 0x00024000 : 100100000000000000
確かに 4 番目と 5 番目が 0x04 になってます。
100 100 000 000 000 000
続きが以下。
(gdb) x/x 0x20201044
0x20201044: 0x00000000
(gdb) x/x 0x20201024
0x20201024: 0x00000001
(gdb) x/x 0x20201028
0x20201028: 0x00000028
(gdb) x/x 0x2020102c
0x2020102c: 0x00000070
(gdb) x/x 0x20201038
0x20201038: 0x000007f2
UART0_ICR が 0 ですね。IBRD とか FBRD の値は適正です。また、0x70 は 2 進数にすると 1110000 で 4, 5, 6 番目が 1 になってるのが分かります。最後に 7f2 な IMSC ですが以下になってて
- 0x7f2 : 11111110010
1, 4, 5, 6, 7, 8, 9, 10 が 1 になってるのが分かります。素晴しす。ICR なレジスタについてはマニュアル確認してみます。
UARTICR レジスタ
書き込み専用らしいので読み出す事自体がアレらしいです。とりあえず UART 初期化のあたり、ソース確認してみます。
UART 初期化のあたり掘削
初期化、ということで baremetal 本では以下な手順としています。
- UART 無効化 (UART_CR の最下位ビット 0 とあります)
- GPIO14, 15 を pull down して ALT0 に
- ボーレートの設定 (IBRD, FBRD)
- LCRH レジスタの設定 (FIFO enabled, word length 8 bit)
- UART 有効化 (UART_CR を 0x301 に)
これに加えて Tutorial のコードでは割り込みな IMSC レジスタも値を変更しているのか。別途で UART 使った情報のやりとりなサンプルを盛り込んで動作確認してみます。