以下の記事の部分的な和訳・要約の個人用メモです。外付けDDRメモリを使用してアプリケーションを実行するまでの手順を解説します。
環境
- Hardware
- Arty A7 100T
- PCとつなぐ用ケーブル
- Software
- Vivado 2023.2
- Vitis Unified IDE 2023.2
- GTKTerm
手順
-
プロジェクト作成
-
Do not specify sources at this timeにチェック - boardファイルを選択。一応
Refreshしてから選択するのが吉。
-
-
ハードウェア設計
Create Block Design-
BoardタブからDDR SDRAMを右クリック、Auto Connectを選択 -
clk_ref_iピンを削除し、MIGの出力ポートui_addn_clk_0をそこに接続 -
sys_clk_iはxdcファイルで登録しておく -
Run Connection Automation(リセットピンの追加) -
Clocking Wizardを追加,clk_in1とMIGのui_clkを接続resetとMIGのui_clk_sync_rstを接続 -
MicroBlazeを追加,Run Block Automation,Clock ConnectionにClocking Wizardのclk_out1を指定,Local Memoryを32KBに変更 Run Connection Automation-
BoardタブからUSB UARTを右クリック、Connect Board Componentを選択 -
AXI Timerを追加 -
Run Connection Automation(すべて選択) Validate DesignCreate HDL WrapperGenerate BitstreamExport Hardware...-
Launch Vitis IDE
-
ソフトウェア設計
- workspaceの指定
- platformの指定
- アプリケーションはexampleから適当に
Hello Worldを選択 - ビルド
- 実行
おまけ
DDRとBRAMそれぞれに100回ずつREADとWRITEを実行しました。
BRAMとDDRメモリセルでのアクセス速度比較
#define __MICROBLAZE__
#include <unistd.h>
#include <sys/_intsup.h>
#include <xstatus.h>
#include "xparameters.h"
#include "platform.h"
#include "xil_printf.h"
#include "xtmrctr.h"
#define DDR_BASE 0x80000000
#define BRAM_BASE 0x50
XTmrCtr TimerCounterInst;
int init(){
int Status;
Status = XTmrCtr_Initialize(&TimerCounterInst, XPAR_AXI_TIMER_0_BASEADDR);
if (Status != XST_SUCCESS) {
xil_printf("Timer Initialize Error\n\r");
return XST_FAILURE;
}
XTmrCtr_SetOptions(&TimerCounterInst, 0, XTC_AUTO_RELOAD_OPTION);
XTmrCtr_Start(&TimerCounterInst, 0);
return XST_SUCCESS;
}
int main()
{
init_platform();
int res = init();
if(res != XST_SUCCESS)return 0;
u32 tStart, tEnd;
double fval;
int whole, thousandths;
int repeatNum = 10000;
int tmp;
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
*(int *)DDR_BASE = 9; // DDR WRITE
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
tmp = *(int *)DDR_BASE; // DDR READ
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
*(int *)BRAM_BASE = 1; // BRAM WRITE
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
tmp = *(int *)BRAM_BASE; // BRAM READ
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
cleanup_platform();
return 0;
}
End - Start = 7952440 // DDR WRITE
Time = 79.524 ms
End - Start = 7952436 // DDR READ
Time = 79.524 ms
End - Start = 7289934 // BRAM WRITE
Time = 72.899 ms
End - Start = 7289937 // BRAM READ
Time = 72.899 ms
経過したクロック数に多少の誤差はあれどDDRとBRAM間でそこまでの差は見られませんでした。
参考