LicheeRV Dock(RISC-V)でベアメタル開発を目指す 2日目
はじめに
本稿ではLicheeRV Dockを使ってベアメタル開発に挑戦した様子を記しています。
以前の模様は1日目として記してあります。本稿は途中からとなりますので最初から読みたい方は1日目の記事もお読みください。
FELモードの概要
1日目の記事ではWindows用のxfelをダウンロードしたところまででした。
AllwinnerのCPUではLicheeRV Dockに限らず他のボードでもFELという押しボタンがついています。これを押しながら電源をON(USB-Cケーブルから電源を供給)すると、FELモードという起動モードに入ることができます。
xfelアプリが正しくインストールされた状態で上記を実行すると、デバイスマネージャからUSB-IDを伴ったデバイスとしてWindowsから認識されるようになります。
FELモードは緊急時にシリアル通信によりCPUが起動できるモードです。製品に組み込み後にフィールドで何らかのトラブルがあって起動できなくなった、等のときにPCとUSBケーブルで接続してこのボタンを押しながら電源ONして、Windowsから起動用のアプリを流し込むといった使い方が考えられます。
Lチカプログラムのコンパイル準備
ベアメタル開発で最初に動かすのはLEDチカチカ、通称Lチカでしょうか。
今回ソースコードはこんな感じで。チカチカというためにはある程度時間を稼ぐ処理が必要なのですが、delay()関数に書いたように nop を指定数分繰り返すようにしました。
GPIOはPB, PC, PD, PE, PF, PGと6グループ、そのうちPCのコンフィグなどはUserManualのP.1080に記載があります。今回はほぼそのまま、その通りにしました。
そしてLEDにつながっているCPUのポートはPC1です。
以下、main.cです。
#define GPIO_BASE 0x02000000
#define PC_CFG0 (*(volatile unsigned int *)(GPIO_BASE + 0x60))
#define PC_DATA (*(volatile unsigned int *)(GPIO_BASE + 0x70))
void delay(volatile int count) {
while(count--) {
asm volatile("nop");
}
}
int main(void) {
// PC1をGPIO出力に設定(bits 4-6を001にする)
PC_CFG0 = (PC_CFG0 & 0xFFFFFF0F) | 0x00000010;
while(1) {
PC_DATA |= (1 << 1); // PC1 HIGH (LED ON)
delay(2000000);
PC_DATA &= ~(1 << 1); // PC1 LOW (LED OFF)
delay(2000000);
}
return 0;
}
続いてlink.ldを以下のようにしました。
RAMの先頭番地0x00045000というのは、ここにあるD1-Hユーザーマニュアルというものの中にメモリマップについて書かれていましたが、どこかのソースでこのアドレスを見た気がしました。見つけたら追記しますが今はそういうものだと思ってください。
/* link.ld */
OUTPUT_ARCH(riscv)
ENTRY(_start)
MEMORY {
RAM : ORIGIN = 0x00045000, LENGTH = 128K
}
SECTIONS {
.text : {
*(.text.start)
*(.text*)
} > RAM
.rodata : {
*(.rodata*)
} > RAM
.data : {
*(.data*)
} > RAM
.bss : {
*(.bss*)
*(COMMON)
} > RAM
}
スタートアップのアセンブラ(start.S)は以下です。
# start.S
.section .text.start
.global _start
_start:
# スタックポインタの設定
la sp, _stack_top
# mainを呼び出し
call main
# 無限ループ
1: j 1b
.section .bss
.align 12
_stack:
.space 8192
_stack_top:
で、上記ファイルが用意できたらビルドします。手動でやりました。
- ツールチェインの確認(インストール時に確認できていれば飛ばして良い)
riscv64-unknown-elf-gcc --version
- コンパイルとリンク
riscv64-unknown-elf-gcc -march=rv64imac -mabi=lp64 -nostdlib \
-T link.ld start.S main.c -o blink.elf \
-fno-zero-initialized-in-bss
3.elfとbin生成
riscv64-unknown-elf-objcopy -O binary blink.elf blink.bin
ここからの手順ですが・・・シリアルのモニタを準備します。
シリアルモニタは、DDR初期化とかを向こうにやってもらうため、その結果が必要なのです。極論やったつもりになればモニタリングは必要ありません。まあしかし今後のことも考えて、ここで準備しておきましょう。
- TeraTermを立ち上げておき、USB-serialをモニタする(COMxxに見えているはずなのでそれを選択。シリアル通信の設定は下記です。
| 項目 | 設定値 |
|---|---|
| ボーレート | 115200 |
| データビット | 8 bit |
| パリティ | None |
| ストップビット | 1 bit |
| フロー制御 | None |
| 文字コード | UTF-8(任意) |
- xfelはWindowsのPowershellで起動する。Powershellで、
xfel version
USBのIDが見えればOK
3. PowershellでDDR初期化
xfel ddr d1
これを送信するとTeraTermに以下が出力される。
DRAM only have internal ZQ!!
get_pmu_exist() = 4294967295
ddr_efuse_type: 0x0
[AUTO DEBUG] single rank and full DQ!
ddr_efuse_type: 0x0
[AUTO DEBUG] rank 0 row = 15
[AUTO DEBUG] rank 0 bank = 8
[AUTO DEBUG] rank 0 page size = 2 KB
DRAM BOOT DRIVE INFO: %s
DRAM CLK = 792 MHz
DRAM Type = 3 (2:DDR2,3:DDR3)
DRAMC ZQ value: 0x7b7bfb
DRAM ODT value: 0x42.
ddr_efuse_type: 0x0
DRAM SIZE =512 M
DRAM simple test OK.
- 作成したバイナリをPowershellで転送。
xfel write 0x45000 blink.bin
- Powershellで実行
xfel exec 0x45000
ここで作成したバイナリが動作し、LEDが点滅します。
トラブルシューティング
xfel ddr d1
ERROR: No FEL device found!
・・・LicheeRV DockがFELモードになっていません。
- SDカードが入っていませんか?SDカードから起動していませんか?
- 電源を入れる(USB-Cを接続する)ときFELボタンを押しながらやりましたか?
- FELボタンからすぐ手を離してないですか?2秒程度待ちます。
Discussion