フォトフレーム: ランダム表示とタクトスイッチでの制御
スライドショー機能は出来たが、電源を入れる度に最初の画像から同じ順番で表示されるのはフォトフレームとしては面白くない。より実用的であることをめざして追加機能の開発にもう少し時間をかけてみた。前回までの表示位置を覚えているレジューム機能や、ランダム表示機能、スタンドアロンで画像の切り替えができるタクトスイッチの実装などである。
忘れていたリニアPCMプレーヤーの改修(2/6/2011)
フラッシュROMを使ったレジューム機能開発のため、以前に開発したAVRのリニア(L)PCMプレーヤーのソースを久しぶりに覗いた。ここでは内蔵のEEPROMに、SDカードのディスク情報を記録し、10枚までのSDカードの頭出しができるようになっている。このやりかたのおさらいだ。
ソースを眺めているうち、このソフトで、Windows Media Player(以降WMP)でデコードしたWAVファイルのサポートが懸案になっていることを思い出した。これは、LPCMプレーヤーのソースコード公開後、Shuji009さんから指摘のあった不具合である。
WMPで、音楽CDからWAVファイルをリッピングすると、WAVファイルの基本的なパラメーターの入ったデータブロック(FMTチャンク)の前に、WMPは何故か附帯情報の入ったLISTチャンクをヘッダーの直後に入れてしまう。これが原因で不正なWAVファイルとみなされ再生されない。
チャンクなので、何処にあっても問題はないだろうと言うのがMSの言い分だろうが、これまでのWAVファイルで、ビットレートや、データレングスを規定する最も基本的なFMTチャンクが後に来たものを見たことはない。こういう業界常識を無視したいつもの横暴なMSの態度に腹が立って(というのは言い訳で、このときはたまたま猛烈に忙しかっただけ)、放ってあった。
修正が一年後というのも気の抜けた話だが、まあ修正しないよりはましだろうと、ソースを見直す。Shuji009さんの言うように修正はあっけなかった。FMTチャンクのサーチのための3ステップの追加とパラメータの入っているアドレスを固定値から相対値に変更する数ステートメントの修正で終わった。
これまでのWAVファイルが再生できることは確認したが、WMPが作ったテストするべきファイルを作ることが出来ない。WMPには、MP3や、WMAファイルをWAVに変換する機能がないのだ。やれやれどうしたものだろう。ウェブに尋ねる。何だと、WMPは音楽CDからリッピングすることができるだけで、PC上のファイルをいじることは出来ないのか。
いかにもMSらしい虫の良い仕様だ。あくまでも自分のところに囲いこんで外には行かせないのかなどと、悪態をつきながら、音楽CDを入れて短い曲をWAVファイルにする。バイナリエディターで確認する。CDタイトルなどの漢字テキストが入ったLISTチャンクが、しっかりヘッダーの後に納まっている。再生してみた。よーし、問題なく音が出た。これで心配なくリリースできる。
最初、1号機(パラレルLCD)のファームをブレッドボード上のミニLCD(2号機以降)の回路に書き込んでうんともすんとも言わず、動かない、動かないと悩んでいたことは秘密である。いや忘れること、忘れること。自分でも驚くばかりだ。LPCMプレーヤーのハードが2種類あることをすっかり忘れていた(修正したソースは、元記事、「量産を目指したリニアPCMプレーヤー3号機完成」に並べてファイルを置いてあります)。
スライドショーのランダム表示の開発(2/9/2011)
ランダム表示のためには、乱数を作る必要がある。ウェブを漁る。どうもUNIXの乱数関数rand()は余り評判が良くなさそうだが、とりあえずは今のところこれしかない。ARM用のgccにあるのか試しにコンパイルしてみた。ちゃんと入っていた。えらいもんだ。
ここを見本に実装する。最初はうまく動かなかったが、サンプルは実数なのに整数にしてしまったためオーバーフローが起きていたことがわかり、ワークを使ってオーバーフローを回避する。出た出た。ただ、乱数の初期値にすべき変数がどうもうまく入らない。UNIXの乱数関数rand()は、乱数の初期化関数(srand(初期値))で初期値を変えて与えないと、乱数の出てくる順番が一定になってしまうというので、ここは起動の度に違う値が欲しい。参考にしたウェブではRTC(リアルタイマークロック)の時刻を初期値に使っている。
まあ、あまりこだわることはないのだが、幸いこのM.Thomas氏のソースはfileシステム(FatFS)のタイムスタンプのため、RTCを実装している。それにこのCQ-STARM基板は、感心なことにRTCのバックアップ電源のVbatは、0オームの抵抗で分割できるようになっていて、以前、CPUチップの上に、コイン電池のフォルダーを両面テープで固定し、ちゃんとした時刻が出るようにしてある。折角動いているRTCだ。利用しない手はない。
しかし、ソースリストの中のTimeDisplayとかcurrent_timeといったそれらしい変数を試すが全部0。なんだ定義しているだけで何にも入れていないじゃないか。さらに探し回る。やっとのことで、現在秒を32ビットバイナリに出す関数RTC_GetCounter()を見つけた。これで実装する。うむ、同じ順番でない乱数が出始めた。しかし、いくつか乱数を出すと同じファイル番号(32ビットの乱数をファイルの数で割っている)が出てくることは避けられない。このままでは、何回も出てくる写真と、一回も出てこない写真がでてくる。
重複しないランダム表示のロジックを考える(2/11/2011)
ランダムにはなっているが、これでは見ていて飽きてしまう。 シャッフルしたトランプをめくっていくように、一回表示された画像は、全部の画像が出来切るまで重複しないようにしたい。
このロジックは結構、複雑になる。不揮発メモリはいらないが、出てくる乱数を配列に蓄積しながら、初めての数かどうか判断していかないといけない。まあ、FPGAと違って、printfデバッグが出来るので、いざとなったら変数を全部出して解析していけるので気分が楽だ。
何もデータがないときや、JPEGファイルが1枚だけの時などの特殊な条件でも動くようにロジックを考える。昔を思い出して夢中になる。午後からの半日で、ほぼ想定どおりの動きをするランダム表示機能が完成した。電源を入れると、UARTには、乱数を出しては重複を調べ、次のファイル番号を調べるメッセージが次々に流れ、SDカードにはいっているJPEGファイルがランダムに表示されていく。乱数なので見ていて飽きない。最後の方になると重複が増えて何回も乱数を出しているのがわかる。少しづつフォトフレームが実用品に近づいていくのが楽しい。
タクトスイッチの実装(2/14/2011)
ランダム表示機能の開発はうまくいった。次はレジューム機能の予定なのだが、フォトフレーム画像をランダム表示してしまうと、前回の状況を保存するレジューム機能の目的が良くわからなくなってきた。ランダム表示では前の状況に戻すことに意味がない。
折角、I2Cフラッシュを揃えたのだが、ここの開発は先送りし、それよりニーズの高いタクトスイッチを先に実装することにした。これはスタンドアロンでフォトフレームを動かすには欠かせない機能である。3ヶ並んだボタンのうち、中央ボタンの長押しでランダム/順次表示の切り替えをし、両側のボタンでLPCMプレーヤーのように画像を前後に切り替える。
タクトスイッチは秋月で売っていた¥10のカラフルなスイッチだ。値段が安いせいかスイッチの押し具合が少しぎこちないが、まあご愛嬌である。場所は、STM32基板の端に並べる。10KΩのプルアップ抵抗を各スイッチにつけて、スイッチの実装はあっさり終わった。残るはスイッチ制御のソフト開発である。
スイッチ制御で想定される必要な機能は、
(1)スイッチ入力の検知機能
(2)スイッチ入力による外部割込み制御
(3)チャタリングなどを防ぐ時間測定
である。いずれもAVRでは、簡単に実装できる機能だが、32ビットプロセッサーのSTM32ではそれぞれ、相当な準備が必要だ。以前買った「STM32マイコン徹底入門」には(2)の割り込みを除いた機能については解説がある(チャタリングのところが特に詳しい)が、入門書なので、全体を俯瞰するのには役に立っても実際のコーディングには残念ながら余り役に立たない。
結局、STマイクロの標準ペリフェラルライブラリの中のHelpファイル(これは全部を網羅しているので役に立つ)が一番役に立った。とりあえずは(1)だけでも動きそうなので、これを実装する。参考までにソースの一部を紹介する。
/* まずポートGPIOEのクロックを立ち上げる */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); // Eポート
/* PE7からPE9をタクトスイッチの入力ピンに。GPIO_Mode のIN_FLOATINGが入力 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* 以上は初期化。 次のステートメントでピンの値がcに入る(0か1) */
c = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_7);
長たらしいステートメントを連ねてやっとのことでタクトスイッチが動いた。 チャタリング防止機能はまだついていない。これまでの値を常に保存していて、立ち上がりと立下りを検知し、UARTに出力する。盛大なON/OFFの行が出るのかと思ったら、不思議なことにチャタリングが全くない。忠実にスイッチのON/OFFが一回しか表示されない。
STM32のピンはチャタリングを吸収する機能がついているのか、このスイッチが元々チャタリングがないのか。どうも(3)は考える必要がなさそうである。(2)は、画像を表示している時にスイッチを押してもあとから機能してくれるためには必要だが、どうしても必要と言うものではない。
となると、長押しの検出だけが残った。これは、これまでのSystickタイマーで出来そうなので(押された時タイマー値をリセットし、離れた時その値を調べる)、タイマーをあらためて設定する必要はなさそうだ。実装を続ける。
タクトスイッチのコーディングは思いのほか早くすんだ。フォトフレームはスタンドアロンでほぼ想定した動きをするようになった。電源を入れるとフォトフレームは、ランダム表示モードで立ち上がり、Bスイッチを押すとスライドショーを中止して、A、Cスイッチを押すと、現在表示しているファイルの前後のファイルを表示する。
Bスイッチを更に押すとスライドショーを再開する。スライドショーの順序表示とランダム表示はBスイッチの長押し(1秒以上)でトグルする。これでUARTなどを使わなくても自由に画像を選んで表示ができる。
ソースを公開することは迷った。雑誌付録のCQ-STARM基板とはいえ、JPEGライブラリ実装のためにCPUを換装しているので、オリジナルのCQ‐STARM基板では動かない。FPGAの部分はまだ公開していないので、このままではフォトフレームは作れない。SPIで16ビットRGBデータが送られるだけだ。
でも、ランダム表示や、DMAを使ったSPI、JPEGデコードルーチンや、BMPファイルの読み出しロジックなどは、最近沢山の種類が出回ってきたSTM32基板で色々なものを開発する時の何かの参考になるかもしれない。とにかく公開してみることにした。公開するファイルは、Eclipseのプロジェクトファイルの形になっている。コンパイル等は、以前の記事を参考(2009/6/1)にしていただきたい。
以下のZIPファイルは、ここのブログの1MBという制限を越えるため、FatFSのオプションファイルを削除してあります。LFNを使うときは正規のサイトからダウンロードしてください。また、UARTは沢山のテストメッセージが出るようになっていますが、UARTをつながなくても動きます。
| 固定リンク
「AVR」カテゴリの記事
- ソフトI2Cはクロックストレッチまで手を出してあえなく沈没(2017.09.02)
- オシロのテストどころかソフト開発で大はまり(2017.07.26)
- 超音波方式の人感センサーI2C化と新しいオシロ(2017.06.29)
- motionの動体検知はRaspi3の電源が安定しない(2017.04.16)
- 赤外線学習リモコンはデータ再現で挫折したまま進まず(2016.07.21)
「ARM」カテゴリの記事
- 心電計プロジェクト:スケールが出ると心電計らしくなる(2015.01.08)
- 心電計プロジェクト:TFT液晶に念願の心電波形が出た(2014.12.18)
- 心電計プロジェクト:STM32F103の心電波形表示で悪戦苦闘(2014.12.03)
- 心電計プロジェクト:CooCoxでARMの表示系ソフトを開発する(2014.10.16)
- 心電計プロジェクト:表示部のARM基板の開発環境を一新する(2014.09.19)
コメント
また引き合いに出してしまい、すみません。
shuji009さんの言うとおり簡単な修正だったので、意地をはらず、もっと早く直すべきだったと反省しています。
MSの横暴は、この程度なぞ可愛いほうです。ディスクの規格、インターネットのプロトコルなどでの傍若無人ぶりはつとに有名です。昔は、「がんばれゲイツ君」というサイトがありました(今もありますが、少しネタ切れ、というより、もうMSの時代じゃないですね)。
投稿: がた老 | 2011年2月19日 (土) 12時17分
書くタイミングを逃しましたが、wav対応、済みません。
確かに、MSのやったことは酷すぎですね。MP3だと、曲名
等の情報が入るので、それに対抗してのことだとは、思い
ますが、それが、とんでもな幹部がいるのか、弁護士か、
株主かは別にして、ちょっと酷すぎだと思いました(怒)。
STM32の安価なボードは買っているのですが、mbedには
まっていて(正確にはmbed+VGA)、抜け出せません。
FPGAのフォトフレームは、凄いと思います。
(今回、DE0のソースとかも読んだのですが、正直、参考に
なっていません・・orz)。
投稿: shuji009 | 2011年2月18日 (金) 11時46分
みなさん、コメントありがとうございました。
STM32だとフラッシュ、SRAMとも十分あるので楽しめましたね。
->そら。さん
>配列に並べて、それを乱数を使って並べ替えて
これ、面白そうだけどやっぱり面倒な感じもしますね。
-> hiraさん
投稿: がた老 | 2011年2月16日 (水) 22時20分
楽しく拝見させてもらってます~♪
乱数でシャッフルするのなら、再生予定のインデックスを配列に並べて、それを乱数を使って並べ替えて、最初から順番に再生する方法がシンプルです。
チャタリングの除去を合理的に行うのなら、50Hzくらいでタイマー割り込みをかけ、割り込み内で、スイッチの状態を読み取りワークに保存し、割り込み外でワークの状態を取り込むと、チャタリングを取り除く事が出来ます。
※自分のHPにAVR用ですが参考になるソースコードがあります。(flicker_src.tgz とかの mainloop.c など)
投稿: hira | 2011年2月16日 (水) 02時53分
重複しないランダムって面倒ですよね。
私も苦労しました。
私の場合は、最初の開発がAVRで、メモリが少ないので配列ではなくビットに割り当てました。
投稿: そら。 | 2011年2月15日 (火) 23時27分