ファイルを使え! SDカードとFAT16
テストプログラムが数十KB程度ならシリアルポートで転送しても1秒かからないので問題にならないが、
SNESのプログラムだと数MBにもなるので転送じゃ時間がかかってしょうがない。
Altera DE1ボードにはSDカードスロットが付いていることもあり、
SDカードからSDRAMにプログラムを読み込んで実行することにしました。
またFAT16を実装して、PCでSDカードにファイルを置いたものをそのまま読めるようにしました。
_ ▼ SDカード (SPIモード)
DE1ボードのマスタークロックは50MHzなので、
1/2でSDカードへのアクセスクロックは25MHzとしました。
DE1の配線の都合もありSPIモードのみの動作で、とりあえずreadのみ実装。
sdcard_ctrl.sflp とSDカード情報読み取りサンプル。
%i "sdcard_ctrl.h"
%i "seg7_ctrl.h"
circuit SDCARD_test
{
input SW<10>;
output HEX0<7>, HEX1<7>;
output SD_CSn; // SD Card CSn
output SD_CLK; // SD Card Clock
output SD_CMD; // SD Card Command & Dout
input SD_DAT; // SD Card Data
sdcard_ctrl sdcard;
seg7_ctrl seg70, seg71;
stage_name sdget { task do(); }
par{
SD_CSn = sdcard.CSn;
SD_CLK = sdcard.CLK;
SD_CMD = sdcard.CMD;
sdcard.DAT = SD_DAT;
HEX1 = seg71.con(sdcard.rdata<7:4>).oSEG;
HEX0 = seg70.con(sdcard.rdata<3:0>).oSEG;
generate sdget.do();
}
stage sdget {
if(sdcard.ack){
// CSD
// sdcard.read(0x000000||0b0||SW<6:0>);
// MBR(第一パーティションエントリ)
sdcard.read(0x000001||SW<7:0>);
finish;
}
}
}
_ ▼ SDカード (SDバスモード) 2016/07/09
基本的にデータはSDカードからSDRAMへロードします。
SDカードのアクセスについては、従来はSPIモードでアクセスしており、
数十KBのデータであれば一瞬でロードできていました。
しかしSNESのデータについては4MBほどあるものもあり、
ロードに数秒かかっている状況でした。
そこで、DE2-115ボードのSDカードコネクタではデータバスが4本ともFPGAと接続されていることもあり、
SDカードのSDバスモード(4bit bus mode)を利用することによって、
ロード時間短縮できないかと思い立ち、実装したものです。
結果としては、4MBのデータロードに7秒かかっていたものを、3秒に短縮することができました。
今回の実装ではいわゆる通常のSDカード(SDSC)のみサポートし、
SDHC、SDXCは未サポートです。
SDSCの仕様ではデフォルトスピードで12.5MB/sまでいけるようですが、
今回の実装ではシングルブロックモードのみの使用のため、
コマンドの度にビジー時間が長く1.3MB/s程度しか出ません。
マルチブロックリードを活用することでもっと速度は上げられますが、
FATファイルシステムとの兼ね合いもあり、今回はこれで我慢します。
トップモジュール
SD_DAT : in std_logic_vector(3 downto 0); -- SD Card Data
SD_CMD : inout std_logic; -- SD Card Command Signal
SD_CLK : out std_logic; -- SD Card Clock
SD_WP_N : in std_logic; -- SD Card Write Protect
signal sd_cmd_out, sd_cmd_en : std_logic;
SD_CMD <= sd_cmd_out when (sd_cmd_en='1') else 'Z';
接続部とテスト
//--------------------- SD_Card Interface ------------------
sdcard_ctrl_sdmode sdcard;
output SD_CLK; // SD Card Clock
output SD_CMD_en; // SD Card CMD Enable
output SD_CMD; // SD Card Command
input SD_RES; // SD Card Response
input SD_DAT<4>; // SD Card Data
SD_CLK = sdcard.CLK;
SD_CMD_en = sdcard.CMD_en;
SD_CMD = sdcard.CMD;
sdcard.RES = SD_RES;
sdcard.DAT = SD_DAT;
stage sdget {
if(sdcard.ack){
// MBR(第一パーティションエントリ)
// 0x1FE -> 0x55
// 0x1FF -> 0xAA
sdcard.read(0x000001FF);
finish;
}
}
sdcard_ctrl_sdmode.sflp
なお、Terasic DE0 FPGAボードについてもSDバスモードが使用できます。
これについては、DE0の古い回路図にはDAT1とDAT2が接続されていないように書かれているため、
使用できるかどうか噂レベルでしか聞いていなかったのですが、
DE0の新しい回路図ではちゃんとデータバスが4本とも接続されているように書かれており、
実際に基板を見ても接続されているようでした。
_ ▼ FAT16
SDカードをFAT16でフォーマットしたものをそのままFPGAで読めるようにとりあえずreadのみ実装。
6502のアセンブラで実装するという手もあったんですが、
SFLで記述した方が楽そうだったのではたしてソフトマクロでの実装となりました。
32MB~2GBまでのFAT16にフォーマットされたSDカードをサポート。
fat16.sflp とファイルをSDRAMに読み込むサンプル。
%i "sdram_ctrl.h"
%i "sdcard_ctrl.h"
%i "fat16.h"
circuit FAT16_test
{
output SD_CSn; // SD Card CSn
output SD_CLK; // SD Card Clock
output SD_CMD; // SD Card Command & Dout
input SD_DAT; // SD Card Data
sdram_ctrl sdram;
reg_ws reset;
sdcard_ctrl sdcard;
fat16 fat;
stage_name card2ram { task do(); }
par{
if(reset){
reset := 0b0;
generate card2ram.do();
}
SD_CSn = sdcard.CSn;
SD_CLK = sdcard.CLK;
SD_CMD = sdcard.CMD;
sdcard.DAT = SD_DAT;
fat.sack = sdcard.ack;
fat.sdata = sdcard.rdata;
}
instruct fat.sread par{
sdcard.read(fat.sadrs);
}
stage card2ram {
reg_wr c2rdata<8>, tA<22>;
state_name st1,st2,st3,st4;
first_state st1;
state st1 if(fat.ack){
fat.fopen(0x00); // 1つめのファイルを指定
tA := 0;
goto st2;
}
state st2 if(fat.ack){
fat.read();
goto st3;
}
state st3 if(fat.ack){
c2rdata := fat.fdata;
fat.read();
goto st4;
}
state st4 if(fat.ack & sdram.ack){
sdram.write(tA, fat.fdata||c2rdata);
tA++;
if(fat.eof) finish;
else goto st2;
}
}
}
今後何かSDカードを使ってログを取るようなことが必要になったらwriteも実装しようかな。
Copyright(C) pgate1 All Rights Reserved.
|