チカラの技術

電子工作やプログラミング

STM32CubeのHALをCoIDEに移植してみました


お久しぶりです。ヌル夫です。
元気です!


○HALですよ
イメージ 1

STM32Cubeという新しい開発環境のファームウェアセットが発表されました。
今はSTM32F4のみ対応ですが、これから他のシリーズも対応して行くとの事です。
公式ページからSTM32F4対応のファームウェアを入手しようとするとSTM32Cubeのみリンクされている状態でした。
つまりSTマイクロさんとしては「これからはこちらを使ってね。」という事なのでしょう。

ファームウェアが変わった事で最も影響を受けるのは関数ライブラリです。
旧「Standard Peripheral Driver」から「HAL(hard ware abstraction layer)」へ変更されていますがこの二つは互換性が全くありません。
旧ライブラリで書かれたソースを移植する際、ペリフェラル関数は全て書き直しになると言っても過言ではありません。

つまりHALは今後のSTM32ユーザーの強制必須科目という事ですね。(苦笑)
下記に移植したソースコードを紹介した後、HALの特徴と旧ライブラリとの比較をしたいと思います。



○HALを移植しました
内容は従来と同じですがソースコードを見て頂けば感じは掴めると思います。
フレームワークの「main.c」にLチカ(TIM4のPWM+割り込みによるGPIO制御)のサンプルコードがあります。

CoIDE開発環境
(「4. CoIDEプロジェクトの作成」の中に移植したフレームワークがあります)



○HALの特徴 ー 抽象化

HALは新しいCMSIS規格を意識してペリフェラルの抽象化と移植性の向上を狙ったライブラリです。
抽象化の為、オブジェクト指向を意識して設計されている事が伺えます。

ソースコードを見た方が分かり易いですね。
以下はペリフェラル(GPIOのDポート)にクロックを供給する関数です。

旧STDライブラリ 「RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);」
HALライブラリ  「__GPIOD_CLK_ENABLE();」

上記は同じ処理ですがHALはペリフェラルを抽象化しているのが分かります。
これは良いですね。私はいつもデータシートと首っ引きでこの設定をしていましたが、それでも良く間違えていました。このように抽象化されると非常に助かります。


○HALのコールバック処理

反対に抽象化で分かりにくくなった部分もあります。
旧STDライブラリではIRQハンドラに直接割り込み時の処理を書いていました。
しかし、HALの作法では若干複雑になります。(作法を気にしなければ従来通り書く事も出来ます)
まず、割り込み時の処理は各割り込みに対応したCallback関数に記述します。
(例: 「HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)」 )
ここでHandle型の引数を取りますが、これはペリフェラルの設定時に使ったHandle変数を使います。
このHandle変数は割り込み関数内で値が利用される為、グローバル変数となりますので気をつけて下さい。

このCallback関数は「HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim))」の中で呼ばれます。
割り込みハンドラにはこの関数を登録します。

TIM4の更新イベントを例にまとめると
-----------------------------------------------------
割り込み発生
------------------------------------------------------

↓割り込みハンドラ呼び出し

---------------------------------------------------------
TIM4_IRQHandler(){
    HAL_TIM_IRQHandler(&Tim4Handle);
}
---------------------------------------------------------

↓HAL_TIM_IRQHandlerで割り込みフラグの処理などを行った後、
↓HAL_TIM_PeriodElapsedCallback(&Tim4Handle)を呼び出し

---------------------------------------------------------
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
     //ここにタイマ更新時の処理をユーザーが書く
}
---------------------------------------------------------

なぜこのように多段でコールバック処理をしているかというと、コールバックの呼び出し元を抽象化する為です。
例えばAD変換の場合ならAD変換完了割り込みとDMA転送完了通知の二つのイベントからコールバックが呼ばれています。
AD変換完了の通知処理とコールバック関数が別なので、ユーザはコールバック関数にAD変換されたデータを処理するプログラムを書く事に集中できます。
また、ユーザがポーリングによってAD変換完了を通知する関数を作った場合もその中でコールバック関数を呼べば共通の処理が行われる訳です。
こうして呼び出し元の通知関数で行われるハードウェア処理を抽象化する事で、関数同士の結合を弱め、移植性、保守性、拡張性を向上させています。

ただし関数分割によるオーバーヘッドとグローバル変数を使用するという副作用もあるので、速度やサイズが重要な場合はコールバック関数を使わないほうが良い場合もあると思います。


○HALの特徴まとめ

1.旧ライブラリとの互換性は全く無い

2.ハードウェアの抽象化が行われていて関数が使いやすくなっている

3.コールバック関数による通知関数の抽象化

4.ペリフェラルの初期化コードは「stm32f4xx_hal_msp.c」ファイルに書くのが作法
(ただし自作フレームワークではmain.cだけ変更すれば使えるようにあえて無視している)
(追記:msp.cのテンプレート(void HAL_PPP_MspInit(PPP_HandleTypeDef *hppp))を使って初期化関数を作ってみましたが、グローバル変数と参照渡しの関係で非常にややこしい書き方になってしまうので、しばらくこのテンプレートは無視する事にしました。)

5.抽象化によってコードサイズは増える。3kB(ROM)のプログラムをHALに移植すると8kBとなった。STM32F4においてはペリフェラルコードのサイズは一部に留まるので大きな問題では無いように思うが、今後STM32F0等ROMが少ないマイコンにSTM32Cubeが移植されると問題が表面化しそうです。

HALの理解はSTM32Cubeに含まれているサンプルコードを読むのが一番だと思います。

それでは皆さん、(大変ですが)頑張ってHALに乗り換えましょう!

英語をアルファベットからやりなおしてTOEIC720までの記録

こんばんわ。
自分は電子系の情報を読む為に英語を勉強しており、能力を測る為にTOEICを受けています。
5月のテストで700点を超えたので一区切りして勉強の経過を書いておこうと思います。


○勉強を始める前の英語力
イメージ 5
英語っておいしいの?

学生の間は英語が大の苦手でずっと避けてきました。
社会人になって就いたのが販売職だった事もあり全く語学には関心が無い状態だったので
中学生レベルの基礎も覚束ない状態でした。

例①:
3年前に書いた自分のプログラムに線を描画する関数が有るのですが関数名が「white_line」でした。
「write_line」と書きたかったのでしょうが、正しくは「draw_line」です。

例②:
SVC文型の英語しか読めなかった。
というかそもそも文型がある事を知らなかった。

悲惨の一語です。


○勉強を始めたきっかけ
イメージ 1
データシート読まなあかんねん

5年前、電子設計の仕事に転職してからデータシートなど英語に接する事が多くなりました。

①ニコ技
ニコニコ技術部の皆さんはどうしてるんだろうと思ったので、IRC
「やはりみなさん英文のデータシートを読んで開発してるんですか?」と質問したところ
英語が読めなきゃオモチャも作れないよ・・・」と言われてガツーンと来ました。
情けないというのも有りましたが凄く悔しかったのを覚えています。
この悔しさが後の勉強のバネになりました。
しかし当時は電子設計を勉強していたので英語の勉強をする時間はありませんでした。

②日本語データシートの終了
上記の後にSTM32マイコンを使い始め、このブログを立ち上げます。
STM32F1には日本語リファレンスマニュアルとデータシートがあり、英語が使えなくてもなんとか開発ができました。
しかしSTM32F2が発表されてから日本語資料はパッタリと無くなってしまいます。
それはSTマイクロにとっての日本市場の重要度が変わったという事で仕方の無いことではありますが
周りの人達(職場外)がSTM32F2で開発を進めている中で自分は日本語資料が無い事が理由で開発も出来ず、取り残されている事に強烈な焦燥感を感じました。
そして英語の勉強を始める事にしました。
1年半前の事です。


○基礎-中学生レベル
イメージ 2
This ! is ! a ! pen !!! これはペンです!!

期間:3ヶ月
勉強時間:毎日1~2時間、土日のどちらかに5時間。

①手始めに

本当に全く英語が出来なかったので何処から手をつけていいかも分かりませんでした。
初心者の参考書として公文式の英文法が有名ですが自分にはそれでも難しすぎました。

そこで初めに選んだのが
「Mr.Evineのアルファベットから英語の基礎をなんとかするドリル」でした。
題名どおり、アルファベットの小文字の書き取りから曜日や数字の英単語を覚えて行き
英語の基礎を学ぶドリルです。
一日で定められた範囲の終わりに演習もついているので復習もしやすかったです。

英語の勉強はこの頃が一番辛かったです。
どんな勉強もそうですが最初は何が分からないかも分からない、入り口すら分からないという状態ではないでしょうか。
加えて、いい大人がアルファベットからやり直すのは恥ずかしいという気持ちが強かったです。
なんとかこのドリルをなんとか1ヶ月で終わらせました。

②文法と単語
これで文法と単語の勉強に入る事が出来ます。
「Mr. Evineの中学英文法を修了するドリル」
「基本英単語・熟語ターゲット1100 」
を平行して2ヶ月間勉強しました。

Mr.Evineのドリルにはコラムがあって、その中に印象深い言葉があります。
「初心者のうちは質より量。効率を考えて手段を探すよりどんどん勉強するべき」
至言です。基礎で覚える事はどんな参考書を使っても同じですから
巷に溢れる効率の良い勉強法などに意味はありません。

③電子辞書
カシオのEX-word XD-B8600を使っています。
単語帳はもちろん、発音や例文も豊富で非常に多機能かつ使いやすい電子手帳です。
今でも愛用しています。


○高校レベル
イメージ 3
C言語が出来たから英語も簡単・・・そう思ってた時期が俺にもありました。

期間:10ヶ月
勉強時間:毎日2~3時間。(途中で仕事を辞めてプラス2~3時間)

英文データシートが読めれば良かったので高校基礎レベルの文法と単語まで覚える事にしました。
主に使った文法書は
「総合英語FOREST」
「Forest  解いてトレーニング」
FORESTは分厚いですが網羅的で丁寧で分かりやすい良書です。

単語帳は
「DUO 3.0」
「風呂で覚える英単語」
「ドラゴン・イングリッシュ必修英単語1000」
特にDUO3.0は練習・応用CDを購入して5周繰り返しました。

また長文独解の参考書として
「あたりまえながらネイティブはなぜ英語を速く読めるのか? 」

それからラダーシリーズ等の学習者向け洋書を5冊ほど読みました。
これでやっとデータシートを読めるかな?というレベルの英語力が付いたと思います。

TOEIC
イメージ 4
聞き流してる内に英語が理解できる?それはジョークだよ!

期間:4ヶ月
勉強時間:毎日3~6時間

TOEICを受けるのは勉強の目的ではありませんでしたが、
英語の勉強の結果を見える形で残したかったのでTOEICの試験を受ける事にしました。

○教材
まず対策本として
「新TOEICテスト一発で正解がわかる 基礎編」

後はテストに場馴れする為に模擬テスト繰り返してやりました。
「TOEICテスト新公式問題集〈Vol.4〉」
「TOEICテスト新公式問題集〈Vol.5〉」
「TOEICテスト究極の模試600問」

○結果
二回受けました。
初回は2013年3月: listening 280  reading 300 total 580でした。
二回目が2013年5月: listening 380  reading 340 total 720でした。

実感として720点は実用英語には程遠い点数です。
TOEICというテストの問題の内容を大筋理解して答えられるのは850点以上ではないでしょうか?
それ以下は闇雲に勘で解いている、という感じだと思います。
またTOEIC試験の内容はビジネスシーンが主ですが、
倒産も解雇も無く同僚や上司はみんな常識と配慮を兼ね備えている素晴らしい世界です。
実社会とのギャップが凄いw

TOEICのアドバイス
低得点なりのTOEICアドバイスを書いてみます。

①本番前にリスニングパートの音が聞き取れるか監督官の人が聞いてくれます。
聞こえにくい場合は申告しましょう。席を替えるなどの対応をしてもらえます。

②本番の試験の難易度は新公式問題集Vol5よりかなり上、Vol4より少し下、というレベルです。
Vol5だけやって本番に臨むと難しすぎて混乱してしまい、本来の実力も出せなくなるのでVol4をやってから本番を受けましょう。

③テスト当日にジタバタ勉強しても余り意味はありません。
2時間のテストで力を出し切るには相当集中力が必要なので、
本番前は休んだりストレッチをしたりして頭が冴えるようにした方が良いと思います。

④模擬テストで500点も取れない状態で受けるのはTOEIC以前の学力がたりないので
基礎からやりなおしましょう。自分に合わないレベルの勉強をしても身につきません。


○その他

海外で有名な感電芸人さん。体張ってます。

○lang8
読む能力ばかりでは無く書く能力も大事かなと思ってlang8で日記を書いていました。
話題はサブカルチャーが中心で頭のおかしな記事を沢山書いてしまいました・・・

○英語漬け
英語漬けやりました。
レベル2からは音声を繰り返し聞いて画面を見ずにデクテーションをしていました。
弱調の単語を聞き取る力が多少上がったと思います。

○海外系の電子サイト
当たり前の事なのですが海外にも電子系ホビイストやガジェット系のサイトがあります。
お勧めのサイトを紹介します。

クラウドファウンディング系
indiegogo
kickstarter

②電子工作・ガジェット系

hackaday  :クラフト系からマイコン系まで幅広い話題。(LPC1114の記事を紹介して頂きました。)
geekboy.it :マイコン系の話題が多い。綺麗にまとまっていて読みやすい。

③STM32系
STM32 forum :本家のフォーラム。非常に活発にトピックが立てられています。
Frank's Random Wanderings :STM32のSDIOやDMAに関して有益な情報があります。

○まとめ

実際は掲載している教材の倍は買って色々手をつけていましたが、実力に合わない教材は終わらせることができず背伸びをしても意味が無いと感じました。
世間的に評価の高い教材はやはりよく出来ていて確実に身になるという安心感があったので続ける事が出来ました。

今後の課題としては英文を読むのにまだ日本語の何倍も時間が掛かるので
これからは量を読んで速く読むよう意識したいと思っています。

それでは!

BMPファイルをマイコンで使いやすい形式に変換するソフト

こんにちわ。
BMPファイルをマイコン用の画像形式に変換するソフトを作りました。

イメージ 3
先頭からデータを読み込んでそのまま表示できる無圧縮データを生成します。



○ダウンロード


実行ファイルのダウンロード


プロジェクトのダウンロード


○機能


このソフトはマイコンでの画像表示を支援する為のソフトでBMPファイルから変換します。
BMPファイルのフォーマットはこちらのページで詳しく解説されています。

主な機能は以下の3つです。
1.ピクセル配置を「下から上へ」→「上から下へ」に並び替えます。
例えばこのようなBMPファイルが有った場合、
イメージ 2
BMPフォーマットは下から上にピクセルが並んでいるのでマイコンで先頭から
画像を読み出すと下のようになってしまいます。

イメージ 1
このソフトはBMPファイルのpixlel配列を並び替えて先頭から画像を読める形式に変換にします。
(画像はcatman)

2.ヘッダファイルを削除します。(非有効化を選択できます。)

3.カラーbitを減色します。



○使い方


1.セレクタから出力したいカラー形式を選択してください。
ヘッダーを残したい場合は右隣のボックスをチェックしてください。
連番BMPの場合は先頭ファイルのヘッダーのみ残します。

2.変換対象のBMPファイルを含むフォルダを選択してください。
入力BMPのファイル名に5桁の連番を設定した場合、00001番から順に変換,結合されます。
00001の無い連番や途中で番号が抜けていた場合、欠番以後は単体のファイルとして処理されます。

選択後、出力ファイルの情報が表示されます。
「Serial file」に動画ファイルが含むBMPファイル数、画像サイズが表示されます。
「Unit files」に単体のファイルの数が表示されます。

3.出力ファイルを保存するフォルダを選択してください。


4.「Start to convert files」をクリックすると変換が開始されます。

5.終了後メッセージが表示され、ファイルが出力されます。
出力後のファイルは「xxxx_yy.bin」
xxxxxにはファイル名,yyには出力後のbit数を表します。

○入力と出力の関係
入力ファイルは8bit,16bit,24bitに対応しています。
ただし、BMP8bitはカラーパレットなので出力もカラーパレットのみ対応しています。
データは入力,出力共にリトルエンディアンです。

『24bit→RGB565』
入力ファイルが24bitBMのとき、ビット配列はMSBから
[R7 R6 R5 R4 R3 R2 R1 R0,G7 G6 G5 G4 G3 G2 G1 G0,B7 B6 B5 B4 B3 B2 B1 B0]
(R:RED, G:GREEN, B:BLUE)
です。

出力ファイル16bitは入力ファイルから
[R7 R6 R5 R4 R3 G7 G6 G5 , G4 G3 G2 B7 B6 B5 B4 B3]
にbit移動,減色されます。

『16bit→RGB555』
16bitBMPファイルはRGB555であるので入出力共に
 [ x R4 R3 R2 R1 R0 G4 G3,G2 G1 G0 B4 B3 B2 B1 B0]
となります。
よって色情報を多く取得したい場合は24bitカラーから16bitへ変換する事をお勧めします。


○画像生成に役立つお勧めのフリーソフト


○Super Bara-Baby X
http://www.vector.co.jp/soft/win95/art/se481023.html
動画からfpsを指定して画像を抽出してくれます。
このソフトで出力したBMPファイルの連番はそのまま私のソフトの動画出力機能へ入力できます。

○縮小マシン easypiccnv

http://www.vector.co.jp/soft/winnt/art/se486873.html
アスペクト比を保ったまま画像を縮小し、余白は設定した背景色で埋めてくれます。
ドラッグ&ドロップで複数ファイルの縮小が可能です。

○リネーム君
http://www.vector.co.jp/soft/win95/util/se093487.html
複数のファイル名を連番で変更してくれます。
Super Bara-Baby Xで抜き出した動画の一部分を切り出して変換したい時に便利。


○その他

○対応していない形式

1. 1bit,2bit,4bit, 32bit のBMPカラーには現在、対応していません。

2.  パディングを含むBMPは対応していません。
バイトパディングとはBMPの1行に含まれるデータが4バイトにアライメントしていない場合に詰め込まれるデータを指します。
入力カラーのバイト数(24bitなら3バイト)× 一行のピクセル数 ÷ 4 で余りが出た場合、そのBMPはパディングを含んでいます。
 一般的なLCDモジュールのpixel幅である320, 400, 480, 680 はパディングを含まないので使用できます。


その他の情報はreadmeを参照してください。
質問等有ればコメントでお気軽にどうぞ。

60fpsの動画をアップしました。

こんばんわ。



○UPしたよ

60fpsの再生動画をUPしました。
今回もささくれPさんの動画を再生させて頂きました。
データ量がSDカードに納まりきらなかったので前半の一部をカットしています。
申し訳ないです。

元は30fpsの動画です。
スピード感のある60fpsの動画が中々無かったので・・・

ただ、短銃にリフレッシュレートを60fpsにしただけではなく、フレーム補間法という
フレーム間に中間フレームを追加する技術を使って30fps->60fpsへ変換してヌルヌル度を上げています。
こちらのブログが非常に参考になりました。
AviSynthを用いたフレーム補間法


○つくづく撮影が・・・

うまくいっていません・・・
前回も言いましたが元はもっと綺麗な画面なのですが、ビデオカメラに映すと暗く写ってしまいます。
無理にISO感度等を上げても今度は白飛びしてしまってうまくいきません。
何度もやり直したのですが納得できる画質にはならなかったです。
実際の画面ははるかに綺麗なので興味のある方は自作して直接見てみてくださいね。



○謝辞

今回はスペック的にかなり厳しい電子工作で、自力だけでは60fpsを達成できなかったと思います。
ネット上の方にアドバイスを頂いたおかげでなんとかできました。
特にとんすけさん、J.SHIMADAさんには非常に有益なアドバイスを頂きました。
ありがとうございました!


次回は自作のBMP→バイナリ変換ソフトをUPする予定です。

50fpsの動画再生をアップしました

こんにちわ。

前回の日記で60fpsの再生が出来るようになりましたが、
無圧縮の動画サイズで60fpsを再生するとSDカードの4Gbyteを使いきってしまい
動画の再生時間が4分17秒が限界になってしまいます。

今、60fps再生の為の適した動画は探しているところです。

今回は50fpsで再生した動画を見て頂ければと思います。


○動画UPしたよ



再生させて頂いた動画はささくれPさんのタイガーランペイジです。
山月記をテーマにした動画で、自分がUPした動画でこの曲を再生するのはこれで3回目になりますw
素晴らしい音楽とMV。

実は50fpsに落としてもSDカードの容量が一杯になってしまい最後の数秒は描画できませんでした。
申し訳ないです。
なお、ソースの動画のフレームレートは30fpsです。
60fpsの動画は意外に少数派なのです・・・


○液晶について


1・画質
液晶を撮影していつも思うのは、本来の画質を撮影できないという事です。
実際はもっと綺麗で色鮮やかなので興味を持った人は自作して肉眼で見てもらえると嬉しいです。

この解像度の液晶になってくると表示がかなり高精細です。
youtubeで全画面にして見てもドットがほとんど分かりません。
自分でもハメコミみたいに見えてしまいますが、ちゃんと再生した液晶画面ですw

無圧縮ゆえマイコンのリソース大部分とデータ量を必要としますが
画質はマイコンで再生した動画の中 (狭w) でもかなりいい部類だと思います。

2.コントローラ無し液晶を使う利点
最近はVRAMを内臓したコントローラICのついた液晶が主流ですが
コントローラの無い液晶にも利点があります。

これは以前、自分がコントローラIC付きの液晶で動画を再生した際の経験ですが
画面の動きが激しいとき、画面がフラッシュした時に画面上に斜めのラインが現れてしまいます。
イメージ 1

この写真だと3本の線が現れていますね。
これはLCDの内臓コントローラが画面をリフレッシュするタイミングと
マイコンからのGRAMへのデータ書き込みが非同期である事によって起こる現象です。
リフレッシュしている間に次の画像がGRAMに書き込まれると、
別のフレームの画像が同じ画面に現れてしまいます。

逆にコントローラICの無い液晶はこのような現象が発生しないため
動きの激しい動画の再生にも適しています。
自分は動きのある動画が好みなのでコレは大きなポイントですね。


○.ピン配置変えました。

SDIOのCMDピンがPDポートだという事が分かったので
16bitポートをPD→PEへ変更しました。
SDIOの他のピンはPCなのになぜ・・・・

それからTIM3のピンもSDカードソケットの実装に邪魔になったのでCHを変えました。
今のピン配置は以下の通りです。
イメージ 2

ピンの移動に伴いボード上の加速度センサも取り外しました。
イメージ 3
仕方・・・仕方なかったんや・・・

以上です。
次回は60fps動画をあげたいと思います。



SDカードの読み出し速度向上とオーバークロック

こんにちは。

共立2000円液晶で動画表示を目指しています。
動画再生の仕組みは至って簡単で、画像をフレームレートの数だけ連続で描画するだけです。

画像表示は前回成功したので、残るは以下の作業だけです。

①PC上でmp4などの動画からマイコンで扱える画像データへ変換
②STM32F4の読み出しバッファに画像データを供給する。

①については自作のソフトを作りました。改良して公開できればと思っています。
今回は②について話します。



○転送速度の見積もり

バッファに供給する1秒当たりのデータ量を決定します。

①いきなり妥協

液晶は24bitカラーで表示できるのですが、
正直肉眼でじっくり見ても16bitカラーとの差が判別できなかったので動画は16bitカラーとします。

②2000円液晶、恐ろしい子
実際に見積もって見ます。

480×272×2 (16bitカラー) × フレームレート = 1秒辺りの転送量
イメージ 1
ヤバイ。

STM32F4が読み出せるSDカードの理論上の最大転送量はデータバス×クロックなので
0.5 (4bit) × 24MHz = 12MByte/secです。

つまり50フレーム以上は理論値を超えているのです。

③もはや運
次にSDカードをかき集めて実際の読み出し速度を調べてみました。
イメージ 2

この中で最も転送速度が速かったのがPQIの8GBカードで(下段、左から2番目)
9.4MByte/secでした。(マイコン側のバッファサイズは100kbyte)

マイコンでの読み出し速度はPCと違い、価格やスペックに全く比例しない所が厄介です。
取り出して使ってみるまで分からないのでSDカードというよりデュエルカードみたいです。

③フレームレートの決定
決定というより、むしろ30fpsしか選択肢はありません。
しかし、ここでコントローラ無し液晶の問題が立ちはだかります。
フレームレート=リフレッシュレートが低いと画面にチラつきが生じてしまうのです。

リフレッシュレートとチラつきの認識度合い
30fps:ハッキリ分かる。
40fps:かすかに分かる
50fps:全く分からない

葛藤しましたが、やはり綺麗に動画を再生したかったので50fpsを目標としました。

限界を超えねばなぁJOJO・・・


○SDカードのオーバークロック

実はとんすけさん,ねむいさんは転送速度の限界を既に破っています。
何をしているのかというとSTM32F4を下記のように設定して
SDカードへのクロックを24MHz→48MHzと倍増させているのです。

SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Enable;

これはSTM32F4のSDカード制御としてはオーバークロックでSDカードが壊れる可能性すらありますが
規格の中に納まっていたのでは達成できない転送量はやはり魅力的です。

という事で先ほどのSDカードを全てオーバークロックしてみました。
しかし読み出しができたのはなんとそのうち一つだけでした。
イメージ 3
シリコンパワー speed10 8GB

読み出し速度は12.8MByte/secで残念ながら目標に達成していません。
しかも読み出しが凄く不安定で開始後数秒で読み出しが出来なくなってしまいます。



○最強のSDカードとは

ここで数日間行き詰ってしまいました。
オーバークロック無しで複数のSDカードを使う事も考えましたがSPIによる
SDカードの転送量は3Mbyte/sec程度なのでそれでも足りません。
バッファを分ける事によって転送速度が逆に下がる可能性もあります。

煮詰まってたところでとんすけさんがカードを紹介してくれました。
『私が出会った中で最強のカードはKINGMAX製キティーちゃんの4GB CLASS4のものです。
 50MHzで18MB/sでました^^』

ティーちゃん!? と色んな意味で驚きを隠せませんでしたが、
本当に困っていたので早速amazonで購入しました。

イメージ 4
心なしか輝いて見えます。

ドキドキしながら転送量を調べたところ自分の環境では14.8MByte/secでした。
おお、50fpsの目標クリアです!

しかし、これも数秒後に読み出しが出来なくなってしまいました。
・・・困った。



オーバークロック対策

読み出しの不安定さを解決すべく調べて対策をしました。
結果、下記の対策により安定して読み出せるようになりました。

1.インダクタの除外
SDカードの回路は下記のようになっています。
イメージ 6

このうち電源ラインのインダクタはSDカードから発生する(マイコンボードへの)電源リプルを
低減させるフィルタの役割をしています。

しかし、オーバークロックによって消費電流が増した事で、インダクタが電流供給の妨げになり
十分な供給がされなくなっていたという事が分かりました。

そこでインダクタを除外して直接マイコンボードの電源をSDカードの電源へ接続しました。
電源リプルが100mV程度になりましたが、マイコンの動作に影響はありませんでした。
しかしオーディオを扱う際は注意したほうが良さそうですね。

2.配線は最短に
バスクロックが上がった事で信号線長による信号の反射が大きくなり、耐ノイズ性が低下しました。
DISCOVERYボードから5cm程度の配線でも読み出せなくなります。
フェライトコアを使っても効果はありませんでした。

そこでソケットピンに直接接続して配線長を最短にしました。
イメージ 5

Vddピン以外はソケットに直接差し込んでます。



○DMAの競合問題

読み出しは安定してできるようになったものの、
フレームレートを上げると再生中に画面上に液晶欠けのような白い点がポツポツと出るようになりました。

これはDMAの転送が競合している事によって起こる現象です。

LCD表示用の内臓SRAM→GPIOへのDMA転送と、
SDカード読み出し用のSDIO→内臓メモリへのDMA転送は共にDMA2のみアクセス可能で
DMAを使うと競合は避けられません。

そこでSDカードの読み出しをソフトウェアポーリングに変更しました。
SDIOのFIFOにデータが溜まるとフラグが立つのでそれを待ってCPUで内蔵メモリへデータを転送します。
効率の良いマルチブロック転送のポーリングプログラムをとんすけさんに教えていただきました。

ポーリング待ち部分のプログラムです。
    do {
        if (STA_RXFIFOHF_BB_FLAG) {
            pbuff[0] = SDIO->FIFO;
            pbuff[1] = SDIO->FIFO;
            pbuff[2] = SDIO->FIFO;
            pbuff[3] = SDIO->FIFO;
            pbuff[4] = SDIO->FIFO;
            pbuff[5] = SDIO->FIFO;
            pbuff[6] = SDIO->FIFO;
            pbuff[7] = SDIO->FIFO;
            pbuff += 8;
        }
    } while (!((sta = SDIO->STA) & SDIO_BLOCK_READ_STATUS_MASK) && timeout--);


DMAと比較しても速度に遜色ありませんでした。



○もう一声!!

これで50fpsで再生する為の読み出し環境がやっと整いました。
しかし・・・50fps・・・なんだか凄く中途半端です・・・

秋月300円液晶は60fpsだったというのもあるし、
60fpsの動画は再生できないという制約も気になります。

せっかくなのでさらに転送速度を上げる為にチューンする事にしました。

調べた結果、ボトルネックはやはりSTM32F4側のバッファサイズでした。
バッファサイズが小さいとマルチブロック転送で一度に読み込めるブロック数が少なくなり
転送速度が低下するのです。(詳しくはこちら
前回、秋月300円液晶の時も最後はバッファサイズを拡大して転送速度不足を解決しました・・・

バッファサイズを100kByteから120kByteまで拡大しました。
これはSTM32F4の内臓SRAM(DMAでアクセスできないCCM領域を除く)のほとんど全てになります。

マイコンのリソースをほぼ全てSDカード読み出しに注ぎ込んだ結果、
転送量は15.8Mbyte/secまで向上しました!
これでやっと60fpsで動画を再生する準備ができました!


○謝辞
今回、様々な過程で煮詰まった際に貴重なアドバイスをくれた
とんすけさんJ.SHIMADAさん、本当にありがとうございました!


○参考サイト

とんすけさん:SDカードのベンチ比較 マイコン工作で速いカードはどれ?
ねむいさん  :STM32F4シリーズを使ってみる3 -FatFsと下部レイヤ(SDIO・MMC)ドライバたちの実装-

共立電子2000円液晶で画像表示

こんばんわ。

先日、日本橋のシリコンハウスで購入したTFT液晶ディスプレイ「FG040346DSSWBG03-DJK」
液晶コントローラを使わずSTM32F4DISCOVERY単体で駆動しました。

イメージ 1

480×272bit 24bitカラー リフレッシュレート75Hz
外付けのSRAM,ROMは使っていません。
背面にあるのはロジアナのLAP-Cです。

今回は前回の秋月300円液晶での反省点を活かして駆動方法を工夫しました。

まず液晶の仕様を紹介した後で、STM32F4による駆動方法を説明します。


○液晶の仕様
共立液晶はいわゆる秋月3000円とほぼ同じ仕様の液晶です。
またPSPの液晶に近い仕様になっていますが電源電圧やピン配置はPSP液晶と異なるため
互換性はありません。

秋月液晶との違いは秋月液晶の画面がノングレアであるのに対し、
共立液晶はグレアタイプで光沢があります。
個人的にはグレアタイプの方が色が鮮やかに見えるので好みです。

イメージ 2

ピン配置です。
画素データ以外の信号はクロックのPCLKとデータのゲート信号のDEのみで
水平と垂直の同期信号は使用せずにNCとしても良い事になっています。
どうやって同期を取っているのかというと次のような仕組みになっています。

イメージ 3

ブランキング期間の記載はデータシートに無かった為、シャープのPSP液晶を参考にしました。

表示期間中にDEをHIGHレベルにして、
その間のPCLKの立下りクロックごとに1pixelを取り込むようになっています。
水平ブランキング期間は45PCLK以上,垂直期間中は14H以上の間 DEをLOWレベルにします。
DEのHIGH期間で画像の表示タイミングを同期できるのでLCDコントローラの付いていない
液晶の中では比較的簡単で使いやすいと思います。


○回路

1.STM32F4DISCOVERY
LCDとの接続は上記の表どおりですが、
私の使っているボードはピンを自由に使うためにボード上の加速度センサ以外の部品を取り除いています。

イメージ 4


2.昇圧・定電流回路


このLCDLEDバックライト用に24Vの電圧と20mAの電流を必要とします。
これを5Vから生成する為に、MC34063を使った昇圧 + 定電流回路を組みました。
定電流にしたのはDCDCのリプル電圧でバックライトがチラつかない様にする為です。
イメージ 10


C3までが昇圧回路でそこから右側が定電流回路です。
右端の2つのピンにLEDアレイをつなぐと、21mAの定電流が流れます。
この時入力には160mAの電流が流れたので出力から見た効率は63%です。
MC34063は安い割に昇降圧どちらにも使えるので手元にあると便利ですね。

3.FPCコネクタ
前回、秋月300円液晶で散々接続に苦労したので今回は最初からaitendoにて
40pinのFPCコネクタを購入しました。
接続は下接点です(一度間違ってしまいました)。


○STM32F4による駆動

○前回の反省点
前回、秋月300円液晶を駆動した時の反省点は下記のとおりです。

①DMAのソフトウェア制御
DMAで内臓SRAM→GPIOへデータを転送していたが、ブランキング期間にDMAリクエストを止める
必要があり、ソフトで制御していた為にタイミングの調整が非常にシビアで大変だった。

②不正確な1フレーム
内臓SRAMの容量が一画面に足りないので小刻みに画像データを送り出していた。
1フレーム(30FPSなら1秒に30フレーム)に画像一枚を対応させる必要があるので1フレームの期間が正確に1/30秒になっていないと動画を再生する際に、本来の再生時間とずれてしまう。
しかし液晶の1クロック単位の長さをソフトでうまく調整する事が出来なかった。

○分析
結局、数MHzの周期で動き続けているDMAデータ転送やクロックを、
無理にソフトウェアで止めたりタイミングを調整していた事が主な原因でした。
CORTEX-M3は割り込みルーチンに入るまでに12クロック掛かるので
とめたいLCDクロックを先読みしてルーチンに入り、ルーチンの中でもタイミングの微調整が必要で苦労しました。根性で動かしていましたがw



○タイマ最高
そういう訳で今回はタイミングの制御は一切ペリフェラルに任せられるようにしました。
結果、正確なタイミングで転送できるようになり、ソフトはサーキュラーバッファに画像データを供給すれば良いだけになりました。

STM32F4は高機能なタイマが合計10個もあるので非常に応用の幅が広く便利です。
FPS=60の場合を例にとり説明します。

1.使用タイマの概要
今回は以下のようにTIMを5つ使用しました。全てPWMモードで駆動しています。
イメージ 6

●用語
タイマのゲート機能について
ゲート機能においてマスターとなったタイマはスレイブのタイマにゲート信号を送ります。
そしてゲート信号がHighレベルの間のみ、スレイブにclock(今回はAPBクロック)が供給されます。

タイマのリセット機能について
マスターはスレイブにリセット信号を送ります。
スレイブのカウンタはリセット信号の立ち上がりエッジで、カウントをリセットします。

DMAリクエストについて
DMAはDMAリクエスト毎にメモリ上のデータをペリフェラルに転送できます。
今回はタイマのPWM立ち上がりエッジのタイミングでサーキュラーバッファのデータをGPIOの出力レジスタに転送し、LCDへ1画素分の信号を送っています。
サーキュラーバッファの半分もしくは完全にデータを転送した時点で割り込みが起こり、
CPUにデータのプッシュを要求します。

2.信号の全体像
イメージ 5
実際のブランキング期間は仕様よりも長くなっています。
これは内臓クロック84MHzからPCLKの1周期を作ると分解能が足らず端数が出てしまう為です。
例: 1PCLKに対する内臓クロック = 84MHz ÷ (480 + 45) ÷ (272 + 14) ÷ 60fps =  9.32
端数は切り捨てになるので、切り捨てた分の誤差をブランキング期間で調整しています。

5つのタイマーの中で実際にLCDに信号を送るのはTIM2の水平ゲートとTIM3のPCLKのみであり、
他は同期とDMAリクエスト用のタイマとなっています。
水平ゲートは画素の送出を制御し、垂直ゲートは水平ゲートを制御しています。
また、垂直ゲート用タイマはPCLKを画素の出力タイミングと同期させる役割もあります。

3.水平ゲートの説明
以下はロジックアナライザで測定した水平ゲートの立ち上がり,画素表示の開始部分の波形です。イメージ 7水平ゲートの立ち上がり後にDMAリクエスト用タイマのPWM波形が現れているのが分かります。
DMAリクエスト用タイマの立ち上がり時にDMAリクエストがDMAへ送られます。

DMAリクエスト用のタイマを二つ使用しているのは1つのGPIOポートが16bitなので24bitカラーを表示するために2つのGPIOが必要で、各々のDMAリクエストを送るタイマが必要だった為です。
本当はDMA1とDMA2を併用させたかったのですが、DMA1はGPIOとバスが繋がっていないためDMA2のみ利用しました。
各々のGPIOに対してサーキュラーバッファを用意してデータを供給しています。
(DMAにスキャッタギャザー機能が有ればバッファは一つで済んだかも知れませんが。)

TIM3は常にLCDにPCLKを供給し続けますが、DMAリクエスト用タイマは水平ゲートがHighの間のみ画素をLCDに送ります。
そして水平ゲートがLowの間、水平ブランキング期間を作ります。

LCDはPCLKの立下りエッジで画素を取り込むので、それまでにGPIOにデータをセットアップしなければなりません。(厳密にはLCD側に信号取り込みのセットアップ時間が必要なのでそれより12nsec早く)
PCLKの立下りまでの時間を稼ぐために、DMAリクエストのタイミングをPCLKの立ち上がりより早くなるよう周期をずらしています。

横向きの矢印がDMAリクエストからGPIOの出力までの期間を示していますが、PCLKの立下りよりも十分早く出力されています。
明らかにDMAの反応がSTM32F1より早くなっています。
GPIOがAHBバスに直結されて、APBバスを経由するレイテンシが無くなったおかげですね。

4.垂直ゲートの説明

以下は垂直ゲートの立ち上がり,1フレームの開始部分の波形です。
イメージ 8
垂直ゲートはLCDに信号を送っていませんが重要な役割を担っています。
垂直ゲートがLowの間、水平ゲートのクロックが停止し垂直ブランキング期間を作ります。
また、1フレームを正確に1秒/FPSの期間に調整しています。
1フレームをTIMクロック単位で調整すれば水晶振動子の精度で正確な1フレームが作れます。

ただし、PCLKはクロックと同期しているわけでは無いので、1フレームごとに調整しなければ
ゲートやDMAリクエストのタイマ周期とずれを起こしてしまいます。
そこで垂直ゲートの立ち上がり時にPCLKにリセット信号を送って同期を取っています。
リセット信号から実際のリセットが起こるまでは矢印で表されるように数クロック分の遅延があります。

水平ゲートのLow期間の中央で垂直ゲートが立ち下がるようにしているので、水平ゲートの立ち上がりは画面外のずっと先です。

○ハマったポイント

TIM1とTIM8はSTM32の中でも高機能タイマに分類され、
モータ制御用に使用されるBREAK入力機能がついているのですが、ここでハマりました。
このBREAK機能の中でoutputの有効化という機能があるのですが、これがデフォルトの設定では
タイマー出力ごとにoutputが無効になるように設定されていてPWM信号を止めてしまうのです。
他の汎用タイマのようにPWMを設定するとここでハマると思います。

解決策ですがタイマごとに下記のように設定して
タイマの更新イベントごとにoutputが自動的に再有効となるようにします。

    //These settings are needed for continuous PWM cycle.
    TIM_BDTRInitTypeDef bdtr;
    TIM_BDTRStructInit(&bdtr);
    bdtr.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
    TIM_BDTRConfig(TIM1, &bdtr);


○小技

☆DMAでGPIOの上位bitのみ操作する方法
今回GPIOBポートのB8 - B15までを8bitカラーに割り当てています。
STM32F4はGPIOがAHBに直結しているのでB0 - B7 に影響を与えずに
上位bitにアクセスする事が出来ます。 

具体的にはDMAの設定時に下記の通りペリフェラルアドレスを設定してバイト転送を行います。
DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t) ((uint8_t *) &(GPIOB->ODR) + 1);


なお、STM32F1はGPIOがAPBブリッジを経由している為、ワード未満のアクセスはワードに拡張されるので上記のようなアクセスは出来ないと思われます。(未確認)


○画質は?
今までに扱ってきた液晶の中で一番綺麗でした!

ただ、写真に撮るとどうしても画質が劣化してしまうのが残念です。
肉眼で見るともっと綺麗なのですが。
イメージ 9

画像データは無圧縮でSTM32F4の内臓ROMに収められ、1枚 480 * 272 * 3 = 391680byteです。
秋月液晶のときは16bitカラーで駆動したので 400 * 96 * 2 = 76800byteだったので5倍以上ですねw

これほど大量のデータを処理できるSTM32F4の能力は素晴らしいと思います。

それでは次は動画の再生にチャレンジします!

参考にさせて頂いたページ:
Chanさん    :秋月3000円液晶モジュールの試食
charanori さん:RX62Nで秋月3000円液晶 ATM0430D5の味見
Coocox forum :PWM STM32F4