STM32F746DiscoでのSDカードデータ転送速度
”STM32F746DiscoでSTM32CubeIDEプロジェクトを通じてSDカードを扱う“で作ったプロジェクトでのSDカードのデータ転送速度を確認してみます。
手元にある正体不明の2GBマイクロSDカードは最低限Class2、2MB/sではあるはずです。
一応CrystalDiskMarkで確認してみると
シーケンシャルライトでも最低3.15MB/sでした。ランダムライトがやけに遅いですが本題でないのでスルーします。
ではSTM32CubeIDEに実装していきましょう!!!
まず測定用の変数を用意します。
1 2 3 4 |
uint32_t startTime; uint32_t endTime; uint32_t writeTime; uint32_t readTime; |
速度を測るためf_write()、f_read()前後にHAL_GetTick関数を入れます。
1 2 3 4 5 |
startTime = HAL_GetTick(); res = f_write(&MyFile, wtext, sizeof(wtext) - 1, (void *)&byteswritten); endTime = HAL_GetTick(); writeTime = endTime - startTime; UNUSED(writeTime); |
1 2 3 4 5 |
startTime = HAL_GetTick(); res = f_read(&MyFile, wtext, sizeof(wtext) - 1, (UINT*)&bytesread); endTime = HAL_GetTick(); readTime = endTime - startTime; UNUSED(readTime); |
速度測定コードの最後のUNUSED(…)は(void)…のマクロでbuild時にWarningを出させないためのものです。
また”STM32F746DiscoでSTM32CubeIDEプロジェクトを通じてSDカードを扱う“でのwtextでは文字列が少なくf_write()、f_read()のオーバーヘッド部分が大きすぎて真の速度がわからないのでもっと大きくしてみます。
そしてwtext、rtextが分かれているとサイズを2倍とってしまうのでwtextのみにします。つまりwtextを書いてwtextに読み込みます。ちなみにSTM32F746DiscoveryのRAMサイズは320kbyteです。
このwtextをStartDefaultTask()内に置いておいたままだとTaskサイズが足らなくなるので外に出します。
wtextのサイズはとりあえず200kbyteです。text分はasciiコードなので1文字=1byteですので200kbyte=200k文字数になります。char配列サイズを+1しているのはヌル文字分です。
7 8 9 10 11 12 |
#define wtextLength 200000 char wtextSrc[] = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r"; char wtextSrc2[wtextLength / (sizeof(wtextSrc) - 1) + 1]; char wtext[wtextLength + 1]; /* USER CODE END PV */ |
いきなり200kbyte分のwtext文字列を作るのは大量の文字列になるのでstrcatで文字列を生成します。その生成用にwtextSrc、wtextSrc2を用意します。2つ用意するのはいきなりwtextSrc→wtextだと処理時間が掛かってしまうのでいったん中規模のwtextSrcwを作ってそこからwtextを作っているためです。
あとstrcatするので<string.h>をincludeします。
1 2 3 4 |
/* USER CODE BEGIN Includes */ #include <string.h> /* USER CODE END Includes */ |
wtextを生成するコードをf_writeの前に付け加えます。
1 2 3 4 5 6 |
for(x = 0; x < (sizeof(wtextSrc2) - 1) / (sizeof(wtextSrc) - 1); x++){ strcat(wtextSrc2, wtextSrc); } for(x = 0; x < (sizeof(wtext) - 1) / (sizeof(wtextSrc2) - 1); x++){ strcat(wtext, wtextSrc2); } |
では走らせてみましょう。
f_write、f_readのオーバーヘッドを取り除くためにデータサイズをいくつか変えてみて何回かの平均をとってみました。
転送データ量(kbyte) | 10 | 100 | 200 |
ライト時間(ms)(3回平均) | 14 | 44.33 | 76.33 |
リード時間(ms)(3回平均) | 4.33 | 18.333 | 32.67 |
ここから近似式y=ax+bの係数a,bを計算してみます。
aはExcelのSLOPE(範囲)、bはINTERCEPT(範囲)で計算できます。
計算結果は
ライト
a=0.328ms、b=11.00ms
リード
a=0.149ms、b=3.05ms
この近似式から再計算した値を再度さきほどの表に入れてみます。
転送データ量(kbyte) | 10 | 100 | 200 |
ライト時間(ms)(3回平均) | 14 | 44.33 | 76.33 |
近似式からのライト時間(ms) | 14.28 | 43.80 | 76.59 |
リード時間(ms)(3回平均) | 4.33 | 18.33 | 32.67 |
近似式からのリード時間(ms) | 4.54 | 17.94 | 32.85 |
係数aを転送速度に変換してみると
ライト
1kbyte/0.328ms≒3.05Mbyte/s
リード
1kbyte/0.149ms≒6.71Mbyte/s
となります。
オーバーヘッド時間はbそのものなので
ライト
11.00ms
リード
3.05ms
となります。
ちなみに最適化をなし(-o0)から最大(-o3)まで変えてみましたが結果は大差なかったです。