はじめに
この記事は以下の続きとなります。
ZYBO導入記録 (2) Hello worldの表示
今回はZYBOボードでLチカを行っていきます。
開発環境
- 開発用PC : Windows 10 64-bit
- Vivado 2020.2
- Xilinx Vitis 2020.2
- ターゲットボード : ZYBO (旧ZYBO)
開発の流れ
VivadoでFPGA内部のハードウェア構成を定めるハードウェアデザインを開発し、XSAファイルとしてエクスポートする。
VitisでXSAファイルを読み込んでアプリケーションプロジェクトを作成し、Lチカのソースコードを作成してビルドする。
完成したプロジェクトをZYBOボードに書き込む。
ハードウェア設計 (Vivado)
Vivadoを起動する。
[Create Project]をクリック
[Next] をクリック
Project nameを入力する。ここでは "LED_flashing" と入力して [Next]
"RTL Project" を選択して [Next] をクリック。
[Boards] タブを選択し、Searchに "zybo" を入力して [Zybo] を選択し [Next] を選択。
[Finish] を選択。
プロジェクトが作成され、下記の画面が立ち上がる。
[Project manager] から [Create Block Design] を選択。
デザイン名を聞かれるので入力して[OK]を選択。今回は"LED_flashing_system"とする。
[Diagram]ウインドウで中央の[+]マークをクリックするか、右クリックして[Add IP...]をクリックする。
出てきたウインドウで[ZYNQ7 Processing System]を選択してダブルクリック。(最初のDefault Partのボード選択でZyboを選んでいないと表示されない)
選択すると、図のように [ZYNQ] のプロセッサコアを表す “processing_system_7_0” という名前のIPが追加。
[Run Block Automation]をクリック。
[OK]をクリック。
IP “processing_system_7_0″に接続ポート[DDR]と[FIXED_IO]が追加。
[FLCK_CLK0]にマウスカーソルを合わせると鉛筆マークに変化するので、ドラッグし[M_AXI_GP0_ACLK]にクロック出力を繋げる。
[Diagram] の余白で右クリックし、[Add IP] を選択する
[Search] に "gpio" を入力し、表示された [AXI GPIO] をダブルクリック
[Diagram] に [AXI GPIO] が表示される
見やすいように [AXI GPIO] をドラッグして [ZYNQ] の右側に移動する
[Run Connection Automationon] をクリック
[GPIO] をクリック
詳細画面が表示される。
[Options] から [leds_4bits ( 4 LEDs ) ] を選択
[All Automation] にチェックを入れて [OK]
IPが追加されて、自動でIP間が接続される
[Interfaces View] を選択するとよりシンプルで可読性が良い表示に切り替えられる。
[Interfaces View] ではクロックやリセットなどの配線が省略される
[BLOCK DESIGN] ウインドウから [Sources] タブを選択。
[Design sources] > [LED_flashing_system] を右クリックし、[Create HDL Wrapper] をクリック。
このまま [OK] をクリック。
そのまま [OK] をクリック。
LEDへの出力信号がFPGAのどのピンから出力されるか、制約ファイル上で定義していく。
作成された [LED_flashing_system_wrapper(LED_flashing_system_wrapper.v)]をダブルクリックする。
[LED_flashing_system_wrapper.v] の内容が表示される。
下に行くと、LEDへの出力を表す変数名が表示されている。
変数名が [led_4bits_tri_o] という名前であることがわかる。
[Sources] タブの [Constraints] フォルダを右クリックし、[Add Sources...] をクリックする。
作成するファイルの種類を選択するウインドウが開く
- 制約ファイル(constraints)
- 設計ファイル(design sources)
- シミュレーションファイル(simulation sources)
制約ファイルを作成するため[Add or create constraints]を選択し、[Next]をクリックする。
[Create File] をクリックする
ウインドウが表示される。
[File name] にファイルの名前を、[File location] にファイルの格納先を入力し、[OK] をクリック
ここではファイル名を "led_constraints" ファイルの格納先を "C:/Users/user/FPGA_Xilinx" とした。
[Finish] をクリック
[Sources] タブの [Constraints] > [constrs_1] の中に作成された [led_constraints.xdc] があるのでダブルクリック
編集画面が表示される
以下のコードを記述する。
set_property PACKAGE_PIN M14 [get_ports {leds_4bits_tri_o[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits_tri_o[0]}]
set_property PACKAGE_PIN M15 [get_ports {leds_4bits_tri_o[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits_tri_o[1]}]
set_property PACKAGE_PIN G14 [get_ports {leds_4bits_tri_o[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits_tri_o[2]}]
set_property PACKAGE_PIN D18 [get_ports {leds_4bits_tri_o[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits_tri_o[3]}]
FPGAのLED関連のピン配置は下記リンク先の"13 Basic I/O"で確認できる。
https://reference.digilentinc.com/reference/programmable-logic/zybo/reference-manual
[Generate Bitstream] をクリック。
bitstreamファイル作成までしばらく時間がかかる。
作成中は右上スミに作業中の表示が出る。
この画面が出れば完了。[Cancel] をクリック。
メニューバーの [File] から [Export] > [Export Hardware...] を選択する。
[Next] を選択。
[Include bitstream] を選択して [Next] を選択。
XSAファイル名と格納するディレクトリを指定する。
ファイル名は "LED_flashing_system_wrapper" とする。
[Next] をクリック。
ソフトウェアアプリケーション設計 (Vitis)
[Tools] > [Launch Vitis IDE] をクリック。
Workspaceのディレクトリを指定して [Launch] をクリック。
既存のワークスペースを選んでいると以前のプラットフォームプロジェクトが既に表示されているので、右クリックで [Delete] を選択し、ワークスペースから削除する。
この画面で [OK] を押す。
[Delete project contents on disk] にチェックをつけるとXSAファイルがドライブからも削除されてしまうので、チェックを入れないこと。
アプリケーションプロジェクトもあれば合わせてDeleteし、ワークスペースから削除する。
メニューバーより [File] > [New] > [Application Project] を選択
[Next] をクリック。
[Create a new platform from hardware (XSA) ] タブから [Browse] をクリック。
[Vivado] で作成した ”LED_flashing_system_wrapper.xsa” を選択して [開く] をクリック。
[Next] をクリック。
アプリケーションプロジェクト名を入力し、[Next] をクリックする。
アプリケーションプロジェクト名は ”LED_flashing_apprication” とした。
[Next] をクリック。
[Empty Application] を選択して [Finish]
空のCプロジェクトが作成される。
[Explorer] 内の [LED_flashing_application_system] > [LED_flashing_application] > [src] を右クリックし、 [New] > [File] を選択する。
[Create New File] ウインドウが立ち上がる。
File nameを入力する。
拡張子は [***.c] とすること。
今回は "led.c" にして [Finish] を選択する。
何も書かれていない空白のファイルのled.cが立ち上がる。
下記のソースコードを記述する。
# include "xparameters.h"
# define LED *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x00))
# define LED_ctrl *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x04))
int main()
{
LED_ctrl = 0x0;
LED = 0x1;
return 0;
}
プラットフォームプロジェクト (led_flashing_system_wrapper) を選択して右クリックし、[Build Project] を選択してビルドを行う。
システムプロジェクト (led_flashing_application_system) を選択して右クリックし、[Build Project] を選択してビルドを行う。
ZYBOをPCにつなぐ
電源を入れる。
PGOODの赤LEDが点灯していることを確認する。
[LED_flashing_application_system] を右クリックし、[Debug as ] > [Launch Hardware] を選択する。
PC側からFPGAへのbitstreamファイルの書き込み(コンフィギュレーション)とアプリケーションソフトウェアのDDRへの書き込みが実施される。緑の行でプログラムはストップしている。
Resumeアイコンをクリックしてプログラムを実行する。
以下の画面が表示される。
右から1つ目のLEDのみが点灯する。
プログラムを変更する。
[led.c] タブを選択する。
GPIOのデータレジスタ(変数名[LED])に"0x3"(2進数表示で0011)を代入してみる。
# include "xparameters.h"
# define LED *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x00))
# define LED_ctrl *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x04))
int main()
{
LED_ctrl = 0x0;
LED = 0x3;
return 0;
}
Ctrl+s
で変更した [led.c] を保存する。
システムプロジェクト (led_flashing_application_system) を選択して右クリックし、Build Projectを選択してビルドを行う。
一度書込みを行ったことでDebugタブが表示され、システムプロジェクトの表示場所が変わっているので注意すること。
プラットフォームプロジェクトはビルドする必要はなし。
ビルドを忘れるとプログラムが更新されないので注意する。
ビルドを行ったら、前回と同様に [LED_flashing_application_system] を右クリックし、[Debug as ] > [Launch Hardware] を選択して
コンフィギュレーションと書込みを行う。前回と同様にプログラムが途中で止まるので、同様にResumeボタンを押す。
右から1番目と2番目のLEDが点灯する。
[led.c] で同様に
LED = 0x7;
とすると右から1、2、3番目のLEDが点灯する。
LED = 0xF;
とすると4つ全てのLEDが点灯する。
変数LEDは
LED = 0b0100;
のようにバイナリで指定しても良い。
LEDの単純な点灯はできたので、Lチカをやってみる。
LEDを点滅させるために、whileループと時間遅延の行を追加する。
# include "xparameters.h"
# define LED *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x00))
# define LED_ctrl *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x04))
int main()
{
int i, j;
LED_ctrl = 0x0; //write to control register
while(1) {
for ( i=0; i<2; i++ ) {
//switching on and off
if(i==0){
LED = 0x1; //on
}else{
LED = 0x0; //off
}
for ( j=0; j<100000000; j++); //Latency
}
}
return 0;
}
while(1)で無限ループを発生させ、iに関するforループでLEDのONとOFFを切り替える。
jは100メガ秒数えてwhileの1ループを約1秒にしている。
Vivadoで [BLOCK DESIGN] ウインドウから [Design] タブ > [processing_system7_0] > [FCLK_CLK0] を選択すると、下の [Block Pin Properties] にクロックソースである [FCLK_CLK0] の詳細が表示される。
ここからクロック周波数が100MHzであることがわかるので、数え上げるのは100メガ秒で良い。
4つのLEDを別々に点滅させることもできる。
以下は左から1秒、0.5秒、0.25秒、0.125秒ごとにLEDがそれぞれ点滅するプログラム。
# include "xparameters.h"
# define LED *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x00))
# define LED_ctrl *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x04))
int main()
{
int i, j;
LED_ctrl = 0x0; //write to control register
while(1) {
for ( i=0; i<16; i++ ) {
//switching on and off
if(i == 0){
LED = 0x0; // LD3 and LD2 on
}else if(i == 1) {
LED = 0x1; // LD2 on
}else if(i == 2){
LED = 0x2; // LD3 on
}else if(i == 3){
LED = 0x3; // LD3 on
}else if(i == 4){
LED = 0x4; // LD3 on
}else if(i == 5){
LED = 0x5; // LD3 on
}else if(i == 6){
LED = 0x6; // LD3 on
}else if(i == 7){
LED = 0x7; // LD3 on
}else if(i == 8){
LED = 0x8; // LD3 on
}else if(i == 9){
LED = 0x9; // LD3 on
}else if(i == 10){
LED = 0xA; // LD3 on
}else if(i == 11){
LED = 0xB; // LD3 on
}else if(i == 12){
LED = 0xC; // LD3 on
}else if(i == 13){
LED = 0xD; // LD3 on
}else if(i == 14){
LED = 0xE; // LD3 on
}else{
LED = 0xF; //off
}
for ( j=0; j<6250000; j++); //Latency
}
}
return 0;
}
以下は逆に右から1秒、0.5秒、0.25秒、0.125秒ごとにLEDがそれぞれ点滅するプログラム。
# include "xparameters.h"
# define LED *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x00))
# define LED_ctrl *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x04))
int main()
{
int i, j;
LED_ctrl = 0x0; //write to control register
while(1) {
for ( i=0; i<16; i++ ) {
//switching on and off
if(i == 0){
LED = 0xF; // LD3 and LD2 on
}else if(i == 1) {
LED = 0x7; // LD2 on
}else if(i == 2){
LED = 0xB; // LD3 on
}else if(i == 3){
LED = 0x3; // LD3 on
}else if(i == 4){
LED = 0xD; // LD3 on
}else if(i == 5){
LED = 0x5; // LD3 on
}else if(i == 6){
LED = 0x9; // LD3 on
}else if(i == 7){
LED = 0x1; // LD3 on
}else if(i == 8){
LED = 0xE; // LD3 on
}else if(i == 9){
LED = 0x6; // LD3 on
}else if(i == 10){
LED = 0xA; // LD3 on
}else if(i == 11){
LED = 0x2; // LD3 on
}else if(i == 12){
LED = 0xC; // LD3 on
}else if(i == 13){
LED = 0x4; // LD3 on
}else if(i == 14){
LED = 0x8; // LD3 on
}else{
LED = 0x0; //off
}
for ( j=0; j<6250000; j++); //Latency
}
}
return 0;
}
参考
主に以下サイトを参考にしました。今回省いた詳細なレジスタの説明もあります。
【LED点滅編(1)】Vitisで”LED点滅”プログラムを実行してみた – ハードウェア構成 –
【LED点滅編(2)】Vitisで”LED点滅”プログラムを実行してみた –プログラムの作成と実行 –
xdcファイルのコードについては下記が詳しいです。
FPGA オリジナルボード設計 I/O ピンの配置を決める「XDC ファイル」の書き方
おわりに
この記事はFPGAもZYBOも初心者の自分が色々調べながらメモ代わりに書いております。現状では動作することは確認できておりますが、間違いがあったり、後から記事を修正する場合があります。ご容赦ください。
もしも間違っている内容等ありましたら、ぜひご指摘ください。