2009/03/02(月)[SOPC][IP] MMC/SPI FatFs - f_writeベンチマーク

[SOPC][IP] MMC/SPI FatFs - f_writeベンチマーク

[SOPC][IP] MMC/SPI FatFsで紹介しているFatFsについて,コメント欄で問合せいただいたファイル書き込み速度のベンチマークをとってみました.


ベンチマーク概要

FatFsのfopen("wb"相当)で確認する

File systemを使う場合でのベンチマークをとることをテーマとする.*1


脳内シミュレーション(a.k.a.妄想)

FatFs(R0.06)ソースコードより,以下の特徴が推定できる.

  • FatFsはマルチセクタライトもサポートしている模様.
  • セクタ境界・クラスタ境界でクラスタ調整・更新・buffer吐き出し処理を走らせる模様.

上記を踏まえてベンチマークを取得すべきケースは以下のパターンを考えた.

  • クラスタサイズでの一括書き込みが最高スループットを出すだろう
  • クラスタをまたぐ,ランダムアクセスが最低速になる.
  • バッファサイズ(またはセクタサイズ)をまたぐ場合も同様.

ベンチマーク対象とコード

[NiosII][ACM] 動画再生装置(お試し版)の構成で試しているため,キャッシュの影響が結構効いてくることも考えられるので,データ転送量を2Mbytesとします.

実行時間測定には,パフォーマンスカウンタを用います.カウンタを3つとして合成してあるので,測定対象を以下のように絞ります.(なんとなく時間のかかりそうなところ,短縮できそうなところに目星をつけてみたつもりです)

  • 総合時間(規定サイズ・規定回数のブロック転送に要した時間.出力されたファイルの検証は行うべき)
  • SPI転送待ち時間
  • 書き込みデータのCRC計算
ベンチマーク部分本体
const int trans_size[] =
	{
	512*64,
	512*128,
	512,
	4096,
	1024,
	64,
	256,
	768,
	1280,
	1636,
	2048,

	0
	} ;

const int sz_write = 512*2*1024*2 ;

~~~
	while (*sz) {
        f_unlink( fn ) ;    // delete the file before test

        if ((res = f_open (&fp, fn, FA_WRITE|FA_OPEN_ALWAYS|FA_CREATE_ALWAYS)) != FR_OK) {
            return (res | 0x1000);
        }
		// size / loop
		i = 0 ;
		PERF_RESET( PERFORMANCE_COUNTER_BASE );
		PERF_START_MEASURING( PERFORMANCE_COUNTER_BASE );
		PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 1);
		do {
			res = f_write(&fp, sdbuf[ i  ], *sz, &rsz) ;
			if (res != FR_OK || rsz == 0) {
				printf ("Error : Bench-fwrite (%d/%d)\n", res, rsz);
				break;
			}
			i +=  rsz;
		} while (i<sz_write) ;
		PERF_END(PERFORMANCE_COUNTER_BASE, 1);

		PERF_STOP_MEASURING(PERFORMANCE_COUNTER_BASE) ;
		printf( "*** fwrite-size = %d ***\n", *sz );
		perf_print_formatted_report( (void*)PERFORMANCE_COUNTER_BASE, alt_get_cpu_freq(), 3, "total ", "xmit","CRC" );
		WAIT_SEC(5) ;

        f_close(&fp);

		sz++ ;
	}

データ転送部・CRC計算部の処理時間測定位置(mmc.c)
BOOL MMC_xmit_datablock(const BYTE * buff,  /* 512 byte data block to be transmitted */
                    BYTE token  /* Data/Stop token */
    )
{
    BYTE resp, wc = 0;
#ifdef _CALC_CRC
PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 3);
    WORD crc = CRC16((BYTE *) buff, 512);
PERF_END(PERFORMANCE_COUNTER_BASE, 3);
#endif

    if (MMC_wait_ready() != 0xFF)
        return FALSE;

PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 2);
    MMC_xmit_spi(token);            /* Xmit data token */
    if (token != 0xFD) {        /* Is data token */
        do {                    /* Xmit the 512 byte data block to MMC */
            MMC_xmit_spi(*buff++);
            MMC_xmit_spi(*buff++);
        } while (--wc);
#ifdef _CALC_CRC
        MMC_xmit_spi(crc >> 8);     /* CRC */
        MMC_xmit_spi(crc & 0xff);
#else
 @       MMC_xmit_spi(0xFF);         /* CRC (Dummy) */
 @       MMC_xmit_spi(0xFF);
#endif
        resp = MMC_rcvr_spi();      /* Reveive data response */
        if ((resp & 0x1F) != 0x05)      /* If not accepted, return with error */
            return FALSE;
    }
PERF_END(PERFORMANCE_COUNTER_BASE, 2);

    return TRUE;
}

*1 : SDカード本来の性能を最大限に生かすのであれば,マルチセクタライトコマンドを放っておけばよいだろう.

測定結果

使用用したカードは,Transcend mini SDカード 2GBをSDアダプタに挿したものです.

    • セクタあたりのバイト数は,512bytes.
    • クラスタあたりのセクタ数は,32です.
    • データセクタエリアの理想write回数は,4096回,128クラスタを消費します.
    • FATエリアの1セクタあたりのクラスタ数:FAT16ならば1セクタに256個,FAT12なら341個を格納できます.

2MBytesのファイルがクラスタ不連続になっているかどうかの確認をしていません.個人的に使用しているSDカードで,この評価用に使っていないため,テスト用のファイルがクラスタ連続で使用しているかは未確認です.あき暮らす他の探索は先頭からのシーケンシャル探索であり,ファイルのunlink処理では空きクラスタにしているため,パフォーマンスの比較に影響は無いと考えました.


結果のまとめと考察

測定結果と主要項目一覧
転送サイズ総時間512byte書込転送要求回数着目点
655364.03239+712クラスタ,マルチセクタCMD
327684.92526+891クラスタ,マルチセクタCMD
40964.43872+5138セクタ連続書込み,1/8クラスタ,マルチセクタCMD
20484.43872+10254セクタ連続書込み,マルチセクタCMD
1636204.466+12713セクタ連続書込み,100バイトコピー,クラスタ境界をまたぐ,マルチセクタ+シングルセクタCMD
1280135.29+16152セクタ連続書込み,256バイトコピー,マルチセクタ+シングルセクタCMD
10247.80936+20491/32クラスタ,マルチセクタCMD
768199.459+13セクタ連続書込み,クラスタ境界をまたぐ
51213.9297+11/64クラスタ, 1セクタ,シングルライトコマンド
25614.0029+01/2セクタ,シングルライトコマンド
6414.0578+61/8セクタ,シングルライトコマンド
  • セクタ境界をまたがないときは,内部バッファへのコピー処理が走る\→ セクタ数の整数倍ではないモノ全てが対象.\とくに小さいものはコピー処理とループ処理で時間を消費する
  • セクタ境界をまたぐと,書き込み処理が走る.\場合によってはリード処理も走る.
  • DRAM間のコピー処理は効率も悪く,処理時間が延びる傾向にある

考察

転送呼び出し回数と,処理時間とが比例していないのは,MMC側の書き込みバッファがあって,連続した書き込み要求は待たされるが,完結して呼び出す分にはFLASHへの書き込みと,ソフトの走行がパラで走っている状況である,と推察する.

512の整数倍・約数を除く転送サイズでは,軒並み桁違いの遅さが目立つ.メモリコピー処理に加えて,セクタ・クラスタ境界をまたぐ処理が追加されるためと考えらる.加えて,端数はシングルセクタライトコマンドを用いるため,転送効率が悪化すると見られる.

1024byte時に中途半端な速度になっているのは,SD内のFLASH書込み待ち時間が発生しているためと考えられる.

512以下の約数では,不要なコピー処理が走らないが,シングルライトコマンドによるコマンド・レスポンス処理時間がかかるため,カードのbuffered-writeが機能しないのかもしれない.




実行結果ナマデータ

fwrite-size = 32768

Total Time: 4.92526 seconds (487789773 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total1004.925264877897671
xmit29.91.471581457432374185
CRC51.52.534742510364714185

fwrite-size = 65536

Total Time: 4.03239 seconds (399361828 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total1004.032393993618221
xmit36.31.465131451044754167
CRC62.52.518662494441814167

fwrite-size = 512

Total Time: 13.9297 seconds (1379575366 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total10013.9296913795753601
xmit10.51.457821443799864097
CRC19.72.741222714866154097

fwrite-size = 4096

Total Time: 4.43872 seconds (439603921 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total1004.438724396039151
xmit331.463601449530084609
CRC64.32.854522827077134609

fwrite-size = 1024

Total Time: 7.80936 seconds (773427070 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total1007.809367734270641
xmit18.71.461001446947596145
CRC50.83.966453928315936145

fwrite-size = 64

Total Time: 14.0578 seconds (1392260079 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total10014.0577713922600731
xmit10.41.465021450932744102
CRC20.12.831102803873134102

fwrite-size = 256

Total Time: 14.0029 seconds (1386825298 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total10014.0029013868252921
xmit10.41.462951448886934096
CRC202.801532774594664096

fwrite-size = 768

Total Time: 199.459 seconds (19754119034 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total100199.45907197541190281
xmit0.7321.460151446106294097
CRC1.32.594872569914484097

fwrite-size = 1280

Total Time: 135.29 seconds (13398914257 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total100135.29001133989142511
xmit1.081.461521447470515711
CRC2.683.623653588810705711

fwrite-size = 1636

Total Time: 204.466 seconds (20250035225 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total100204.46638202500352191
xmit0.7181.467311453200055367
CRC1.663.392833360204435367

fwrite-size = 2048

Total Time: 4.88632 seconds (483933442 clock-cycles)

Section %Time (sec) Time (clocks)Occurrences
total1004.886324839334361
xmit301.463841449761165121
CRC65.33.190863160180685121


今後の課題

SD側の応答待ち時間の計測,f_write内の分岐処理回数を付け加えれば,想像の裏づけを取ることもできるだろう.

カードの性能にも左右されるベンチマークであるため,必ずしも上記の結果どおりとはならないでしょう.カード性能を測定するベンチマークハードウェアを作るのも面白いかもしれませんね.File systemを無視して,SDのwrite buffer sizeや応答時間なんかの測定を自動的にやってくれるのがあると,実力チェックに使えて面白そうです.

実使用に耐えるかどうかを判断するためには,file system経由での(sequential|random)(read|write)も必要でしょう.

まぁ,あくまでもMMCのベンチマークということで... :p

[Q2HB] SPI Core

[Altera][Q2HB][IP] SPI Core

refer to:"Volume 5: Embedded Peripherals","Section I. Off-Chip Interface Peripherals","7. SPI Core"

Core Overview

(略)SPIインタフェースは,よう使われている.SPI core with Avalon-interfaceは,SPIプロトコルを実装し,バックエンドでAvalon-MMインタフェースを提供する.

SPI coreは,SPIマスタかSPIスレーブのどちらかを実装できる.マスタとして設定したときは,SPI coreは32個までの独立したSPIスレーブを制御できる.送受信のレジスタ幅は,1~32ビットの間で設定可能です.より長い転送長はソフトルーチンでサポートされます.SPI coreは,転送が完了するごとにフラグする割込み出力を提供します.



Functional Description

SPI coreは以下の信号で同期通信を行います(SPIプロトコル)

Signal symbol description
Master Out Slave Inmosiマスタからのデータ出力,スレーブへのデータ入力
Master In Slave Outmisoスレーブからのデータ出力,マスタへのデータ入力
Serial Clocksclkマスタに駆動される,スレーブへのクロック.データビットの同期に使う
Slave Selectss_nマスタに駆動される,個別のスレーブへのSelect信号(active Low).対象となるスレーブを選択するのに使う

このコアには,ユーザに見える柿のリソースがあります.

  • MemoryMapped register\rxdata, txdata,status, control, slaveselect
  • 4つのSPIインタフェースポート\sclk, ss_n, mosi, and miso

Instantiating the SPI Core in SOPC Builder

(なんともはやふつー過ぎて省略)


Software Programming Model

alt_avalon_spi_command()

int alt_avalon_spi_command(
	alt_u32 base, alt_u32 slave,
	alt_u32 write_length,
	const alt_u8* wdata,
	alt_u32 read_length,
	alt_u8* read_data,
	alt_u32 flags)

データ長8bit以下のSPIマスタ向けに設計されている.現状,データ長8bit以上のハードには対応していない.
この関数を一度呼ぶと,MOSIからデータを吐いて,MISOからデータを受け取ります.

  1. slaveの指定されたslave chipselect信号をアサートします.IDはゼロオリジンです.
  2. write_lengthバイトだけwdataから読み出して出力します.MISOからのデータは捨てます.
  3. read_lengthバイトだけ,read_dataへデータを格納します.MOSIにはゼロを吐き続けます.
  4. スレーブのselect信号をデアサートします.

コードは,以下のファイルを見ると把握できます.リード時の吐き捨てがマスタ出力ゼロで決めうちですね.
C:\altera\81\ip\altera\sopc_builder_ip\altera_avalon_spi\HAL\src\altera_avalon_spi.c

※SDカードへのアクセスの際には,1'b1での出力が必要と思う(ELMより...SD Spec.見たほうがいいか?)



問題点

SPIマスタのとき,動作クロックをWizardで定義することになるが,動的な変更が効かない
(ELM) MMCの使い方 より,

SPIモードの場合は、速度を制限する状態(OD駆動)が無いので、クロック切り替えなしで最初から20/25MHzでもOKです。

20MHz固定でもいいか...


SDカードをSPIモードで使うときの結論

IPコアは流用できるが,HAL・ドライバは使用できない.自前で制御レジスタをたたくべし.ソースコードの流用はできるだろう(あまりおいしく無いけれど)
→ よそのIPを拾ってこよう….

[Q2HB] Performance Counter Core

[Altera][Q2HB][IP] Performance Counter Core

refer to:"Volume 5: Embedded Peripherals","Section V. Test and Debug Peripherals", "29. Performance Counter Core"

注意
performance counterは,複数clockを使用するシステム上では,CPU clockと同じdomainに配置すること.異なる場合はサイクル数から実時間へ正しく変換できない.(p.2453 "Multiple Clock Domain Considerations")

Core Overview

高精度パフォーマンスカウンタを提供するらしい.GNU profiler, gprofでも使得る模様.通常のInterval timerを利用することも可能.
3種類の測定方法については,"AN 391: Profiling Nios II Systems."にて述べる.

機能としては,クロックサイクルの計数と,イベント回数の記録である.それぞれ64bit/32bit精度を有す.


Software Programming Model

便利なマクロや関数が用意されている.カウンタの初期化,開始,停止,測定対象セクションの開始・終了を行う.測定結果についても,テキストベースで表を出力する関数を用意してある.

パフォーマンスカウンタの名称を"performance counter"とした場合で,section counterは1番目を用いる例である.

    PERF_RESET( PERFORMANCE_COUNTER_BASE );
    PERF_START_MEASURING( PERFORMANCE_COUNTER_BASE );
    PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 1);
	// 測定対象となる処理 //
    PERF_END(PERFORMANCE_COUNTER_BASE, 1);
    PERF_STOP_MEASURING(PERFORMANCE_COUNTER_BASE) ;
    printf("%qu cycle \n", perf_get_section_time(PERFORMANCE_COUNTER_BASE, 1));

注意点としては,section timeのみを図りたい場合でも,total counterも起動する必要があること.また,printfでalt_u64の表示を行う場合には,書式装飾子"q"*1を付与する必要がある.


*1 : gcc方言:long long 型の書式."qu"で"unsigned long long"型である.

注意事項

英語力の弱い人が適当に訳して抜粋,補強しています.
あやしいな,と思ったらご指摘いただけますと幸いです.
なお,オリジナルの英文を参照されることを強く推奨いたします.

[UG] DDR and DDR2 SDRAM High-Performance Controller User Guide

[SOPC][UG][IP] DDR_SDRAM_HP

refer to:"DDR and DDR2 SDRAM High-Performance Controller User Guide (ug_ddr_ddr2_sdram_hp.pdf)"

注意事項(document内部から場所を問わず抜粋)

論理合成時には,あらかじめTcl制約スクリプトを実行しておく必要がある.

_pin_assignments.tcl.


ライセンス制約

OpenCore Plus Evaluationの場合:
time-limited device programming fileを生成する.このため,"Tethered"または"Untethered"による実行となる.時間制限にのみ縛られる場合*1か,JTAGケーブルにより接続されている状態が維持されている必要があります.


Functional Description

Signals
Symbol説明
global_reset_n input)DDRSDRAMコントローラへの非同期リセット入力.全てのリセット信号は,この信号を同期化したものからなる.この信号がローレベルの間は,完全にALTMEMPHY megafunction(PLLも含む)をリセット状態にする.
pll_ref_clk (Input)PLLへのリファレンスクロック入力.
phy_clk (Output)megafunctionのユーザ向けシステムクロック.DDR high-performance controllerとの入出力信号は,このクロックに同期して行う必要がある.
reset_phy_clk_n (Output)ユーザへのリセット信号.この信号は,phy_clkクロックドメインに同期してアサート・デアサートされる.
aux_full_rate_clk (Output)ALTMEMPHY megafunctionがユーザに提供している代替クロック(alternative clock).このクロックは,外部メモリインタフェースのように常に同じ周波数で走ります.\half-rate modeでは,このクロックはphy_clkの2倍の周波数で,2x clockが必要なときはいつも使えます.\full-rate modeでは,このクロックはphy_clk信号と同じPLL出力で駆動されます.
aux_half_rate_clk (Output)ユーザ向け代替クロック.このクロックは常に外部メモリの半分の周波数で走っています.\フルレートモードのとき,このクロックはphy_clkの周波数の半分として使うことができます.例えば,half-rate bridge側に使うことができます.\ハーフレートモードのとき,このクロックはphy_clk信号のように,PLL出力と同じもので駆動されます.
dll_reference_clk (Output)外部でインスタンス化されるDLLに引き込まれる基準クロック.
reset_request_n (Output)PLL出力がロックしていないときに示すリセット要求信号.他のシステムレベルリセットコントローラへの入力の,リセット要求としてこの信号を使う.PLLがロックしていない間は,この信号は常にローレベルです.\コレを使うどんなリセット回路も,レベル検出よりは立下りエッジでリセット要求を検出すべきではない.(=レベルでやれ?)
soft_reset_n (Input)SOPC Builderのためのエッヂ検出リセット入力で,使用するか,他のシステムリセット回路によって制御される.この信号は,PHYに対して完全なリセットをアサートする要因となるが,PHYで使われているPLLには使われない.
oct_ctl_rs_value (Input)ALTMEMPHY信号は,シリアル終端の値を与えます.ALT_OCT megafunction出力"Seriesterminationcontrol"に接続されるべきです.
oct_ctl_rt_value (Input)ALTMEMPHY信号は,パラレル終端の値を与えます.ALT_OCT megafunction出力"Parallelterminationcontrol"に接続されるべきです.
dqs_delay_ctrl_import (Input)このALTMEMPHYインスタンス内で,他のALTMEMPHYインスタンスのDLLを使うことを許可します.DLLつきのALTMEMPHYインスタンスの外部ポートを,他のALTMEMPHYインスタンスの入力ポートへ接続してください.




Creating A Simulation Testbench Environment



*1 : この場合は全てのライセンスにおいてUntetheredもしくはライセンス有りである必要がある.

注意事項

英語力の弱い人が適当に訳して抜粋,補強しています.
あやしいな,と思ったらご指摘いただけますと幸いです.
なお,オリジナルの英文を参照されることを強く推奨いたします.

[Q2HB] PLL

[SOPC][IP] PLL

refer to:"Volume 5: Embedded Peripherals","Section VI. Clock Control Peripherals", "31. PLL Core"

Core Overview

Avalon-MM I/Fをもつ,Stratixシリーズ/Cycloneシリーズ搭載のオンチップPLLコアである.PLLコンポーネントは,Mega FunctionのALTPLLを用いており,ラッパーコアとなる.SOPC Builderから実装するメリットとしては,status/control signalをMMレジスタからアクセス・参照することができる.

用途は,システム全域のクロック生成・モジュールの一部に供給するクロックの生成,である.


Function Description

PLL Status and Control Signals

ALTPLL Mega Fuctionはパラメタライズされていることから,ステータス・コントロール信号は可変長となる.所望のステータス信号・コントロール信号をSOPC Builder systemモジュール外に出すことができる.排他的に,Avalon-MM レジスタ経由でアクセスができる.

設定方法は,Instantiating the Core in SOPC Builderを参照のこと.


System Reset Considerations

FPGAのコンフィレグレーションにおいて,PLLコアは自動的にリセットします.PLLに与えられたリセット回路は,SOPC Builder systemモジュール全域へのリリースを解除する前に,PLLがロックすることを保障します.

注:PLLをリセットすることは,関連するSOPC Builder system moduleをリセットします.


Instantiating the Core in SOPC Builder

PLLコアは,ALTPLL Mega Functionを用いています.MegaWizardインタフェースを用いて,ユーザがステータス・コントロール信号の接続を指定します.
"PLL Setting"にて,ALTPLL MegaWizardを起動します.ここで,[1]Parameter Settingの"Inputs/Lock"ページで,"Lock output"グループに, Create "locked" outputチェックボックスがあります.これにチェックを入れると,PLL lock状態の信号が,SOPC Buidlerシステムモジュールのtop level moduleに出力されます.

その後,"Interface Page"にて,それの信号を出力する先を選択することができます.(registerかexportか)


ALTPLL NameInput / OutputAvalon-MM PLL Wizard NameDefault BehaviorDescription
aresetinputPLL Reset Inputデバイスコンフィグレーション時のみPLL初期化PLLおよびシステムモジュールをリセットする
pllenainputPLL Enable Input常にenablePLLをenableにする信号..
pfdenainputPFD Enable Input位相-周波数検出器は有効検出器を有効にする.クロックリファレンスを切り替えるときに使う?
lockedoutputPLL Locked Output-入力クロックにPLLがロックしたときにアサートされる

※aresetは,PLLのみをリセットするのではなく,SOPC Builder system module全域をリセットします.


注意事項

英語力の弱い人が適当に訳して抜粋,補強しています.
あやしいな,と思ったらご指摘いただけますと幸いです.
なお,オリジナルの英文を参照されることを強く推奨いたします.