like a /dev/null

いつかは捨てられる儚いモノたちの吹き溜まり

RasPiの起動とarmjtag

Raspberry Piの電源を投入したらどのような手順で所望のプログラムが起動するか、そしてJTAGが使用可能になるのかを調べてみた。

起動直後

mrubyをRaspberry Pi(bare metal)で動かす: Windows編の通りにJTAGを使えるように作業すると、SDカードに以下のファイルを用意することになる。

  • bootcode.bin
  • start.elf
  • kernel.img

これらのファイルが何か、というのを調べたところ、次のような情報があった。

http://raspberrypi.stackexchange.com/questions/10489/how-does-raspberry-pi-boot

訳すとこんな感じだろうか。


  • RasPiの電源投入直後、ARMコアはoffでGPUコアがonにになっており、SDRAMはdisableである。
  • GPUはSoCに内蔵されている1st stage bootloaderの実行を開始する。1st stage bootloaderはSDカードを読み、2nd stage bootloader(bootcode.bin)をL2 cacheに読み出して実行する。
  • bootcode.binはSDRAMをenableにし、SDカードから3rd stage bootloader(loader.bin)をRAMに読み出して実行する。
  • loader.binはGPU firmware(start.elf)を読み出す。
  • start.elfはconfig.txt, cmdline.txt, kernel.imgを読み出す。

loader.binは大してなにもしない。これは.elfファイルを扱うことができ、start.elfをメモリの最初に読み出すのに必要である(ARMはSDRAMをアドレス0番地から使用する)。

bootcode.binに.elf読み出し機能を追加する予定があり、そうなるとloader.binは不要になる。ただ、作業の優先度は低い。


「電源投入直後、ARMコアがoffでGPUコアがonになっており」ってほんと? という気がして調べてみたけど、寄り道な気がしたので深追いしないことにした。

loader.binというのはSDカードにコピーしていないので、bootcode.binに取り込まれたのだろう。

読み込む実行イメージのファイル名はkernel.imgに固定されているようだ。

SDカードにcmdline.txtは用意していないけど、フォーマットは以下のようだ(自分は試していない)。

http://elinux.org/RPiconfig

kernel.imgを読み出した後は書かれていないけど、プログラムカウンタが0x8000にセットされる。なので、自分で作った実行イメージは必ず0x8000にリセットベクタ相当のコードがないといけない。

armjtag

SDカードにコピーされるkernel.imgはarmjtagと呼ばれているもので、以下から取得できる。

https://github.com/dwelch67/raspberrypi/tree/master/armjtag

ちなみにこのリポジトリにはbare metalでRasPiを使うための情報がかなり蓄積されていて、自分もちょこちょこ確認していたりする。

このarmjtagは何をやっているかというと、次のとおり。

  • RasPiのピンヘッダにJTAGのピンがマッピングされるように設定
  • タイマを使い、無限ループでACT LEDを点滅させる

GPIOは有限のピンに多数の機能をマッピングできるように、またボード設計におけるピン配置の柔軟性をあげるために、ピンごとにそれをどのように使いたいかを設定することができる。

単なる入力、出力ピンにすることもできるし、alternate functionとして6つ設定できるようになっている。ここらあたりはSoC-Peripherals.pdfの”6. General Purpose I/O”に書かれている。

というわけで、以下のようにGPIOにJTAGのピンを割り当てている。

GPIO JTAG func
GPIO4 ARM_TDI ALT5
GPIO22 ARM_TRST ALT4
GPIO24 ARM_TDO ALT4
GPIO25 ARM_TCK ALT4
GPIO27 ARM_TMS ALT4

また、これらのピンのpull-up/downを無効にしている。でも、入力ピンは無接続に備えてpull-upかdownにしたほうが良い気がする。

後はLEDを点滅させるためにタイマを使っている。といっても割り込みを使っているわけじゃなく、動作させてカウンタ値を無限ループで確認し、所定の値になったらLEDをon/offしている。

なお、事前にLEDにつながっているGPIO16をoutputモードにしている。このピンをLにするとLEDが点灯し、HにするとLEDが消灯する。