Diary/2015-3-3
Embedded Linux Hands-on Tutorial -- ZedBoard
Linux + Zynqに慣れるべく,2013年と2年前の資料だけど,Embedded Linux Hands-on Tutorial -- ZedBoard をやってみる.
ISEは14.4.
14.7でやろうとしたら,PSのIPコアのバージョンがあがっているためか,そのままではBitStreamが生成できなかった.
OSはCentOS 6.2を用意.
今日びCnetOS 6.2のリポジトリはそうそうないので,
baseurl=http://vault.centos.org/6.2/os/$basearch/
とかを使う.(cf. http://d.hatena.ne.jp/tmatsuu/20120324/1332578375)
x86_64版でインストールするけど,CodeSaurcyの都合で32bit実行/開発環境も必要.
sudo yum install compat-libstdc++-33-3.2.3-69.el6.i686 sudo yum install glibc-devel.i686 glibc-devel
とかした上でISEをインストールする必要があるので注意.
準備
- 設計イメージのダウンロードと展開
wget http://www.digilentinc.com/Data/Products/ZEDBOARD/ZedBoard_Linux_Design.zip unzip ZedBoard_Linux_Design.zip
- XPSで開く
source /opt/Xilinx/14.4/ISE_DS/settings64.sh xps ZedBoard_Linux_Design/hw/xps_proj/system.xmp &
HWの変更と合成
- PSのGPIOコアからLEDをはずす
- I/O Peripheralsをクリック
- Zynq PS MIO Configurationsダイアログが開く → EMIO GPIOの幅を60から52に変更 (8 LEDピンの削除)
- Portsタブを開いてポートの設定
- processing_system7_0の(IO_IF) GPIO_0を選択
- ポートをNo Connectionに
- ポートをExternal Portsに.名前のprefixの_pinを削除(既存のUCFとできるだけあわせるため)
- Create and Import Peripheral Wizardでmyledを作る
- コア名はmyled.
- AXI4-Lite
- software resetとinclude data phase timerはオフ
- レジスタの数は1つ
- user_logicは(私の場合)VHDLのままでいい
- myledの追加と編集
- add IP.パラメタはデフォルトのまま
- ソースコードを修正.Browse HDL Sources...でHDLコードに,View MPDでmpdファイルに簡単にアクセスできる
- user_logic.vhdの修正
101 LED : out std_logic_vector(7 downto 0); 148 LED <= slv_reg0(7 downto 0);
- myled.vhdの修正
141 LED : out std_logic_vector(7 downto 0); 306 LED => LED,
- myled_v2_1_0.mpdの修正
40 PORT LED = "", DIR = O, VEC = [7:0]
- Project -> Rescan User RepositriesでIPコアをリスキャン
- Portsタブでmyled_0を開くと追加したLEDな出力ポートができているので外部出力ピンに
- UCFでピン割り当てを変更
- ProjectタブのUCF File: data/system.ucf からアクセスできる
- 80行目付近からのOn-board LED'sのprocessing_system7_0_GPIO<>をmyled_0_LED_pin<>に変更.
- 以降のペリフェラルに対するprocessing_sytem7_0_GPIO<>のインデックスを8減らす
- Bitファイルの生成
- Hardware->Genearete Bitstream
U-BOOT作る
- U-Bootのコンパイルの準備
gitで取得するかBranchのアーカイブかを利用する.
git clone https://github.com/Digilent/u-boot-digilent
ドキュメントに沿ったバージョンのものをダウンロードしてみた.
wget https://github.com/Digilent/u-boot-digilent/archive/v2012.04-digilent-13.01.zip
展開して,もぐる
unzip v2012.04-digilent-13.01.zip cd u-boot-digilent-2012.04-digilent-13.01
- U-Bootのコンパイルのための設定
- IPアドレスの設定.include/configs/zynq_zed.h を編集.
/* Default environment */
#define CONFIG_IPADDR 10.0.0.1
#define CONFIG_SERVERIP 10.0.0.3
- ビルド
次のようにしてビルド.
make CROSS_COMPILE=arm-xilinx-linux-gnueabi- zynq_zed_config make CROSS_COMPILE=arm-xilinx-linux-gnueabi-
できあがったものをコピー.
cp u-boot ../ZedBoard_Linux_Design/boot_image/u-boot.elf
FSBLを作ってBOOT.BINを作る
- BOOT.BINを作る(準備)
(閉じていれば)xpsでxmpを再び開く.
xps ZedBoard_Linux_Design/hw/xps_proj/system.xmp &
Project→Export Hardware Design to SDKでExportしつつSDK起動.
ワークスペースは,
ZedBoard_Linux_Design/hw/xps_proj/SDK/SDK_Export
にある.
File⇒New⇒Project...でXilinxのApplication Projectの作成を開始.
キモは,
Project Name: FSBL Hardware Plat: xps_proj_hw_platform OS Platform: standalone
くらいか.Available Templatesでは,Zynq FSBLを選択.
- main.cの修正
ZedBoardでは,FSBLで,USB-ResetピンのトグルによってUSB PHYチップをリセットする必要があるらしい.
main.cのFsbHandOff()の呼び出しの前(472行目)に次のコードを追加.
472 473 /* Reset the USB */ 474 { 475 fsbl_printf(DEBUG_GENERAL, "Reset USB...\r\n"); 476 477 /* Set data dir */ 478 *(unsigned int *)0xe000a284 = 0x00000001; 479 480 /* Set OEN */ 481 *(unsigned int *)0xe000a288 = 0x00000001; 482 Xil_DCacheFlush(); 483 /* For REVB Set data value low for reset, then back high */ 484 #ifdef ZED_REV_A 485 *(unsigned int *)0xe000a048 = 0x00000001; 486 Xil_DCacheFlush(); 487 *(unsigned int *)0xe000a048 = 0x00000000; 488 Xil_DCacheFlush(); 489 #else 490 *(unsigned int *)0xe000a048 = 0x00000000; 491 Xil_DCacheFlush(); 492 *(unsigned int *)0xe000a048 = 0x00000001; 493 Xil_DCacheFlush(); 494 #endif 495 }
デフォルトで自動Buildだけど,念の為にCleanしてBuild.
- BOOT.BINを作る
Xilinx Tools⇒Create Zynq Boot Imageでツールを起動.
FSLB elfには,
ZedBoard_Linux_Design/hw/xps_proj/SDK/SDK_Export/FSBL/Debug/FSBL.elf
を選択.
List of partitions int the boot imageは,FSBL.elf,system.bit,u-boot.elf の順.
ZedBoard_Linux_Design/hw/xps_proj/SDK/SDK_Export/FSBL/Debug/FSBL.elf ZedBoard_Linux_Design/hw/xps_proj/SDK/SDK_Export/xps_proj_hw_platform/system.bit ZedBoard_Linux_Design/boot_image/u-boot.elf
出力先のフォルダは,
ZedBoard_Linux_Design/boot_image/
にする.
できあがったu-boot.binをBOOT.BINにリネーム.
Linuxカーネルのコンパイル
- Linuxカーネルのコンパイルの準備
gitのメインブランチかタグを切られたものを持ってくる.
u-bootのときと同じように,v3.6-digilent-13.01とタグを切られたものを持ってくることにする.
https://github.com/Digilent/linux-digilent/archive/v3.6-digilent-13.01.zip
wgetで取得したら拡張子がつかなかったので末尾に.zipをつけて,unzipで展開してもぐる.
- コンフィグ
まずはデフォルトコンフィギュレーション
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- digilent_zed_defconfig
で,menuconfig
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- menuconfig
ちなみに,ncurses-develがなかったのでyumでインストール...
ドキュメントではPmodOLED1をビルトイン・ドライバからローダブルモジュールに変更している
具体的には Device Driver→PMOD Support と辿って,PmodOLED1の'*'を'M'に変更.
- ビルド
Exitをつづけて終了したらビルド
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi-
ビルドが終わったらarch/arm/boot/zImageができている
デバイスツリーを作る
カーネルソースの下で,
./scripts/dtc/dtc -I dts -O dtb -o ../devicetree.dtb arch/arm/boot/dts/digilent-zed.dts
を実行
SDカードにセットアップ
- SDカードを用意
先頭1GBをvfat,残りをext4にする.
- fdiskでパーティション作る
- vfatとext4で,それぞれフォーマット.たとえば,
suudo mkfs -t vfat -n ZED_BOOT /dev/sdb1 sudo mkfs -t ext4 -L ROOT_FS /dev/sdb2
- ルートファイルシステムの用意
- Linaroをダウンロード.
wget http://releases.linaro.org/12.09/ubuntu/precise-images/ubuntu-desktop/linaro-precise-ubuntu-desktop-20120923-436.tar.gz
- 展開
mkdir -p /tmp/linaro sudo cp linaro-precise-ubuntu-desktop-20120923-436.tar.gz /tmp/linaro cd /tmp/linaro sudo tar zxf fs.tar.gz
- ext4領域をマウント
mkdir -p /tmp/sd_ext4 sudo mount /dev/sdb2 /tmp/sd_ext4
- 展開した一式をコピー.ドキュメントではrsync使ってる
cd binary/boot/filesystem.dir/ sudo rsync -a ./ /tmp/sd_ext4 sudo sync; sudo sync; sudo sync; # 念のため
- unmountして取り出す
sudo umount /tmp/sd_ext4
- BOOT.BIN,dtc,zImageをコピー
vfat領域に
- BOOT.BIN
- devicetree.dtb
- zImage
をコピーする.
ZedBoardで起動してみる
HDMIケーブルつなぐとGUIがあがってくるのがわかる.
apt-get install openssh-server
とかするとsshdがインストールできる.
sshでログインできるようにrootのパスワードを適当に設定.
myled用のドライバを作る
- 準備
カーネルソースにアクセスしやすいようにシンボリックリンクを用意
ln -s linux-digilent-3.6-digilent-13.01 linux-digilent
作業用のディレクトリを用意して移動
mkdir drivers cd drivers
- 必要なファイルを書いてmake
Makefileを書く
obj-m := myled.o all: make -C ../linux-digilent/ M=$(PWD) modules
clean: make -C ../linux-digilent/ M=$(PWD) clean
myled.c(355)を書いて,make.
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi-
デバイスツリーを更新
myledのアドレスをxpsで確認.今回は0x7e400000-0x7e40ffffの64KBの空間だった.
サンプルをコピー
cp ../linux-digilent/arch/arm/boot/dts/digilent-zed.dts .
一番最後にエントリを追加.
myled { compatible = "dglnt,myled-1.00.a"; reg = <0x7e400000 0x10000>; };
編集したらデバイスツリーを作りなおす
../linux-digilent/scripts/dtc/dtc -I dts -O dtb -o devicetree.dtb digilent-zed.dts
- システムに反映
scpでmyled.koとdevicetree.dtbをコピー.
ブートパーティションはマウントされてないので,マウントしてコピー
mount /dev/mmcblk0p1 /mnt/ cp /root/devicetree.dtb /mnt/
で,リブート.
再起動したら,/proc/myledができている.
insmod myled.ko echo 0x0F > /proc/myled echo 0xF0 > /proc/myled
とかして楽しむ
ユーザアプリを書く
作業用ディレクトリをつくって,もぐる
mkdir user_app cd user_app
led_blink.c(358)を書く.Makefileも用意.ドキュメントのMakefileは何か変な感じだったので注意.
また,クロスコンパイル環境とターゲットでライブラリがちぐはぐなので-staticが必要だった.
CC = arm-xilinx-linux-gnueabi-gcc CFLAGS = -g -static all : led_blink led_blink : led_blink.c ${CC} ${CFLAGS} -o $@ $^ clean : rm -rfv *.o rm -rfv led_blink .PHONY : clean
Linaroの場合,ホストコンパイラもあるので,ソースをコンパイルしてもOK.