2011-03-09 22:10:41

STBeeボード+2.4インチ液晶パネルYHY024006Aで動画再生60FPS超える

テーマ:STM32
SDIO + FSMC + DMAの組み合わせで60fpsオーバー達成!

ついに動画再生できました(^ω^)

↑ 61.5fps達成しましたb かなりヌルヌル動いてます!
元が30fpsの動画なので倍速くらいの再生速度になってます。動画はシンデレラロマンスです。<(_ _)>
60fpsで撮影できるカメラがあれば・・・。

前回は液晶にSDカードから画像を表示させることまでできました。
しかし描画速度がとても遅かった><;

理由は二つ。
・SDカードからの読込みはシングルブロックリードしか使ってなかった。
・CPUから直接GPIOを叩くことで液晶の信号線やデータバスを操作してた。

SDカードへのアクセスはクラスタ内の連続するセクタをマルチブロックリードすることで速度向上が望めるのですが、ボトルネックは液晶へのデータ転送速度です。

STmicroのアプリケーションノートをなんとなしに眺めていると、
「TFT LCD interfacing with the high-density STM32F10xxx FSMC」というかなりビビっとくるタイトルのノートが。
このタイトルのおしりについてるFSMCというのはFlexible Static Memory Controllerのことで要するに外部メモリを扱うための機能のことです。
外部バスの所定の番地にアクセスすることで外部メモリとマイコン間でデータを転送してくれるのです。

お?おおおおお・・・なるほど!液晶を外部メモリとして扱うワケですかっ!
ファンタスティックすぎる!

思い立ったが吉日、液晶のコネクタ線をバラしてFSMC仕様に配置換え。
GPIODとGPIOEにまたがっててしかもピンアサインが不規則なので注意深く配置。

$とんすけぶろぐ
↑STBeeボードのSTM32F103VET6(100pinパッケージ)の接続。8080系インタフェースのLCD。

ソフトウェア側はNOR型の16bit幅SRAMメモリ、バンク1の領域1として構造体を初期化。
液晶のRS信号はレジスタへのアクセスかGRAMへのアクセスかを決める信号で、FSMCのアドレスポートに割り当てることで所定の外部メモリ番地にアクセスすることで制御できます。
アプリケーションノートにはRS信号をA0に割り当ててましたが、STBeeボードにはA0ピンがないので一番若い番号のA16を割り当てました。
外部バスアドレスのバンク1の領域1は0x60000000番地から始まっています。
RS信号をA0に割り当てた場合、0x60000000番地をアクセスするとRS信号がアクティブ(レジスタアクセス)に、0x60000002(16bit幅なのでアドレス+2)にアクセスすると非アクティブ状態(GRAMアクセス)になります。
RS信号をA16に割り当てた場合、RS信号が非アクティブ(GRAMアクセス)になるオフセットアドレスは2^16 * 2 = 0x20000なのでGRAMアクセスには0x60020000番地を使います。
レジスタアクセスにはその-2の0x6001fffe番地を使います。

$とんすけぶろぐ
↑水色がレジスタアクセス。ピンクがGRAMアクセス。(メモリアクセス幅16bit時)

FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef p;

/*-- FSMC Configuration ----------------------------------------------------*/
p.FSMC_AddressSetupTime = 1;
p.FSMC_AddressHoldTime = 0;
p.FSMC_DataSetupTime = 5;
p.FSMC_BusTurnAroundDuration = 0x00;
p.FSMC_CLKDivision = 0x00;
p.FSMC_DataLatency = 0x00;
p.FSMC_AccessMode = FSMC_AccessMode_B;

FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);

/* Enable FSMC Bank1_NOR Bank */
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);

↑ペリフェラルライブラリでの初期化例。

あとはこんな感じでLCD構造体つくってマクロつくって
typedef struct
{
__IO uint16_t LCD_REG;
__IO uint16_t LCD_RAM;
} LCD_TypeDef;

#define LCD_BASE ((uint32_t)(0x6001fffe))
#define LCD ((LCD_TypeDef *) LCD_BASE)

値を代入するだけでピクセルが描画できる
LCD->LCD_REG = 0x0022; // 描画コマンド
LCD->LCD_RAM = 0xf800; // GRAMにデータを出力

リードする場合はこうするだけ
var = LCD->LCD_RAM;

これで煩わしい信号制御やGRAM読み込みのためにポート入出力の切り替えもしなくて済みました(^ω^)
外部バスにアクセスするだけで読み書きできる素晴らしい!
さらにDMAを組み合わすとCPUは一切介さずに液晶表示ができるようになる。
これなら動画再生いけるかも!

そして動画再生を考えてみました。
最も素早く描画できる方法は、
動画をQVGAサイズにリサイズして1フレームずつ画像をBMPで出力。
出力された各BMP画像を16bit色のRGB565に変換しデータをトップダウンに並べ替えイメージデータとして出力。
各イメージデータを連結して一つの動画データファイルを作る。
動画データファイルをSDカードから出来る限りクラスタサイズと近いブロック数で読み込んで液晶に描画。
動画切り出しはffmpegを使い、BMP→イメージ化する処理はC言語で描き、イメージの連結はcatコマンドで行いました。

この方法だと1フレームあたり150KBになるため動画ファイルがバカでかくなります(^^A
仮に30fpsの動画を1分間切り出せば、60 x 30 x 150KB ≒ 264MB
5分間だと約1.3GBにまで膨れ上がります><;
まあSDカードも高容量化してるのでその辺はあまり気にしないでおきます。←

SDカードへのアクセスはSDIO機能を使ってクロック周波数24MHz・データ幅4bitで高速アクセス。
カード初期化時にCMD6でHigh Speedモードに。(High Speedモードは>25MHzなので意味ないかも?)
さらにSDカードのクラスタサイズを出来る限り大きくしてフォーマット。32KBが望ましい。
クラスタ内の連続しているブロックはマルチブロックリードで描画用バッファに連続読み込み。
描画用バッファはクラスタサイズと同じ32KBを割り当て一気に1クラスタ分読み込み、DMAを使ってバッファからLCDに描画しました。
その結果大成功!想像以上に高速に描画できました。

↓いろんなカードでクラスタサイズごとに試してみた結果です。
末尾の(*)は同一カードです。

・クラスタサイズ32K
61.5fps FAT16 TOSHIBA SD 2GB CLASS4 ver1.10 追記 新記録65.4fpsでました。
44.6fps FAT32 HAGIWARA microSDHC 4GB CLASS4 ver2.00
44.6fps FAT32 HAGIWARA microSD 2GB ver2.00 CLASS4 (*)
43.0fps FAT32 pqi SDHC 8GB CLASS6 ver2.00

・クラスタサイズ16K
33.6fps FAT32 HAGIWARA microSD 2GB ver2.00 CLASS4 (*)
31.3fps FAT16 ノーブランド microSD 1GB ver1.10

・クラスタサイズ4K
13.4fps FAT32 HAGIWARA microSD 2GB ver2.00 CLASS4 (*)


全部のカードで60fps超えるわけではなく、東芝の2GBカード ver1.10だけが異常に速かった。
このカードのスピードクラスはCLASS4だけど、この描画テストに限りCLASS6よりも速い。
61.5fpsだと9MB/sも出ていることになる。\(@o@)/
不信に思ってあとでPCでベンチマークとったらCLASS6のほうがやっぱり速い。
なぜだろう・・・?
ver1.10とver2.00のカードじゃ高速アクセスの仕方が違うのかな?
High Speedモード(カードクロック周波数50MHz)で真価を発揮するのかもしれない。

P.S.
SDカードのスピードクラスは最低保証速度だそうで、CLASS4でもCLASS6より速いということは十分にあり得ることのようです。(今回のケースではDefault Speedモード:カードCLK周波数25MHz以下において)
ですのでカードの最高速度は実際ベンチマークとってみないと分からないみたいです。
TOSHIBAのカードがスピードクラスを大きく上回り高速だったのはやはりSDカードの本家メーカー(他にPanasonic、Sandisk)であるが故かもしれません。
安いカードばかりあさってたので気づきませんでした(^^;A


それにしてもSTM32ってかなりハイパフォーマンスですね。びっくりです。
動画再生ができたので今度は音楽も一緒に流れるように出来たらなぁー。
タイミング取ったりとか難しそう\(@o@)/
AD
いいね!した人  |  コメント(0)  |  リブログ(0)

とんすけさんの読者になろう

ブログの更新情報が受け取れて、アクセスが簡単になります

コメント

[コメントをする]

コメント投稿

AD

ブログをはじめる

たくさんの芸能人・有名人が
書いているAmebaブログを
無料で簡単にはじめることができます。

公式トップブロガーへ応募

多くの方にご紹介したいブログを
執筆する方を「公式トップブロガー」
として認定しております。

芸能人・有名人ブログを開設

Amebaブログでは、芸能人・有名人ブログを
ご希望される著名人の方/事務所様を
随時募集しております。