!Embedded Linux Hands-on Tutorial -- ZedBoard Linux + Zynqに慣れるべく,2013年と2年前の資料だけど,[Embedded Linux Hands-on Tutorial -- ZedBoard|http://www.digilentinc.com/Data/Documents/Product%20Documentation/ZedBoard_ELHoT.zip] をやってみる. 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 {{ref myled.c}}を書いて,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 {{ref led_blink.c}}を書く.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.