例えば画像処理回路でフィルタ係数をデータとして持っておき動的に変えたい場合など、
その係数データはDRAMに保存され、必要に応じてPLに読み出される構成になると思います。
しかし、この係数データはどのように用意すればよいのか、という問題に突き当たります。
開発中ならSDKのXMDからデータを書き込めばよいですが、最終的にはそのようにはできません。
ここでは、データをSDカードに持っておき、それを読みだしてDRAMに展開することを考えます。
SDカードからブートするとき、FSBLがFATでフォーマットされたSDカードから"BOOT.BIN"というファイルを読み出し、DRAMに展開します。
FSBLは、SDKでアプリケーションプロジェクトの一種として作成されることからもわかるとおり、
(たぶん)結局普通のベアメタルアプリケーションのようなものなので、
FSBLのコードからSDカードを読み出している部分を頂いてくれば、SDカードからの読み出しが可能になります。
FSBLの準備
適当なプロジェクト(SDカードにアクセスできるPSがあればOKなはず)でSDKを開いて、
メニューのFile -> New -> Application Project からFSBLを作成します。
名前は適当にここではzynq_fsbl_0
とかにしました。
2つ目のページでZynq FSBL
を選んでFinish。
また、コードをいろいろいじるために使い捨てるFSBLプロジェクトをもうひとつ作っておきます。
fsbl_test
とか。
コード・リーディング
fsbl_test
のコードをいじくってみます。
まず、main.c
のmain()
関数を
int main(void)
{
printf("Hello, world!\r\n");
return XST_SUCCESS;
}
に変えてみます。
これで実行すると、普通にコンソールに
Hello, world!
が出力されます。FSBLのコードはベアメタルアプリとしても実行できるみたいです。
main()関数を元に戻し、中を見てみます。
今回はSDカードを読み込む処理を抜き出したいので、BOOT.BIN
でファイル内検索すると、
/*
* SD initialization returns file open error or success
*/
Status = InitSD("BOOT.BIN");
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"SD_INIT_FAIL\r\n");
OutputStatus(SD_INIT_FAIL);
FsblFallback();
}
MoveImage = SDAccess;
というコードが見つかります。
InitSD()
が怪しいですね。
SDKの関数ジャンプ機能でInitSD()の定義に飛んでみます。
cd.c
に定義されていますね。
f_open
, f_seek
, f_read
などなどそれっぽい関数が使われています。
結局、sd.c
内のInitSD()
とSDAccess()
の処理をパクればSDカードからのファイル読み込みが可能です。
SDカードから読んでみる
fsbl_test
のコードを書き換えてSDから読むアプリケーションにしてみます。
まず、main.c
以外のファイルを削除します。
次にmain.c
を以下のように書き換えます。
#include "xparameters.h"
#include "xstatus.h"
#include "ff.h"
char *strcpy_rom(char *Dest, const char *Src)
{
unsigned i;
for (i=0; Src[i] != '\0'; ++i)
Dest[i] = Src[i];
Dest[i] = '\0';
return Dest;
}
u32 loadFileFromSD(char filename[], u32 *dst)
{
FIL fil; /* File object */
FATFS fatfs;
char buffer[32];
char *boot_file = buffer;
// Copy from InitSD
FRESULT rc;
TCHAR *path = "0:/"; /* Logical drive number is 0 */
/* Register volume work area, initialize device */
rc = f_mount(&fatfs, path, 0);
xil_printf("SD: rc= %.8x\n\r", rc);
if (rc != FR_OK) {
return XST_FAILURE;
}
strcpy_rom(buffer, filename);
boot_file = (char *)buffer;
rc = f_open(&fil, boot_file, FA_READ);
if (rc) {
xil_printf("SD: Unable to open file %s: %d\n", boot_file, rc);
return XST_FAILURE;
}
// Copy from SDAccess
UINT br;
rc = f_lseek(&fil, 0);
if (rc) {
xil_printf("SD: Unable to seek to %x\n", 0);
return XST_FAILURE;
}
rc = f_read(&fil, (void*)dst, fil.fsize, &br);
if (rc) {
xil_printf("*** ERROR: f_read returned %d\r\n", rc);
return XST_FAILURE;
}
Xil_DCacheInvalidateRange(dst, fil.fsize);
return XST_SUCCESS;
}
int main(void)
{
printf("Loading test.dat\r\n");
Status = loadFileFromSD("test.dat", ((volatile unsigned int *) 0x04000000));
if ( Status != XST_SUCCESS ) {
printf("Fail\r\n");
}
printf("loaded\r\n");
return XST_SUCCESS;
}
SDカードにtest.dat
というファイル(適当に作ってください)を入れてZedBoardに挿し、このコードを実行すると、SDカード内のtest.dat
がDDRメモリの0x04000000
番地に読み込まれます。
PLからの利用を想定し、InitSD()
とSDAccess()
からコピーしたコードに加えて、Xil_DCacheInvalidateRange()
を呼んでいることに注意してください。
ホストPC(Linux)でhexdump
コマンドでtest.dat
をダンプした結果と、SDKのXDMコンソールでmrd 0x04000000 10
してメモリ内容をダンプした結果が一致すれば成功です。
他のプロジェクトでもこの関数を使う
上記コードのloadFileFromSD()
関数(とstycpy_rom()
)をコピーすれば他のプロジェクトでもSDからの読み込みを実現できます。
ただし、これらはFSBLと同時に作られたBSPプロジェクト内のファイルをインクルードおよびリンクしないといけないので、そこの設定だけ気をつけてください。
具体的には、以下の手順で設定します。
1. この関数を使いたいプロジェクトの上で右クリックし、コンテキストメニューからProperties
を選択。
2. C/C++ General
-> Paths and Symbols
を選択
3. 右ペインのIncludes
タブでAdd...
を押し、zynq_fsbl_0_bsp/ps7_cortexa9_0/include
を追加
4. さらにLibraru Paths
タブでAdd...
を押し、zynq_fsbl_0_bsp/ps7_cortexa9_0/lib
を追加
5. C/C++ Build
-> Settings
を選び、右ペインのLibraries
を選択、Libraries (-l)
にxilffs
を追加