マイコン工作実験日記

Microcontroller を用いての工作、実験記録

Cover Artに再挑戦 -- その2

2025-01-21 22:16:46 | DoomPlayer

前記事で書いたようにSportifyを使うとアルバム画像(Cover Art)が時折表示されないという問題に遭遇していました。YTube Musicを使えばちゃんと表示されるし、コミュニティの投稿を読むと他のサービスのアプリを使った場合でもちゃんと表示されているようで、Sportifyのアプリ側に問題があるようです。投稿では、アプリの接続先としてカーナビを使っている人が多いようです。

曲が変わった時に、曲名やアーティスト名は正しい情報が取得できるのに、アルバム画像だけは取得できないというのが、この問題の症状です。何度か連続して画像取得に成功することもあれば、連続して失敗することもあるのが、これまた困ったチャンです。YTube Musicの無料版ではバックグラウンド再生ができないので、やはりSportifyの無料版でちゃんとCover Art表示が安定して動くようにしたい... というわけで問題の原因調査と、その対処について検討、実装してみました。

まずは、AVRCP 1.6の仕様書から正常な画像取得シーケンスを見てみましょう。

GetElementAttributeCmd を送信して AttributeID=0x08 のDefault Cover Artの画像情報を要求します。すると、その応答として長さ7バイトのイメージハンドルが返ってきます。このハンドルを使って実際の画像イメージを GetLinkedThumnail で取得するという手順になっています。

ところが、取得に失敗した時のシーケンスを見ると、次のようになっていました。

イメージハンドルを正しく取得することができないので、実際の画像のダウンロードまで進めていないのでした。そこで、ハンドルの取得に失敗した場合には、GetElementAttributesCmd を再送してみたところ....

1回目の送信で失敗しても2回目では成功する場合があることがわかりました!!  しかしながら、失敗応答を受信してからすぐに再送を行ったのでは、5回再送しても5回とも失敗することもありました。そこで失敗応答を受信したら、120ms待ってから再送し、それでも失敗したならばさらに 240ms待って送信というように、120msずつ間隔を増やして5回までの再送を試みることにしました。

結果として、多くても2回再送すれば成功応答を受信できるようになりました! 2時間以上連続してSportifyを流してみましたが、曲が切り替わると問題なくアルバム画像が更新されるようです。

このように、ちょっと待ってから再送してやることで問題が解決することが判明しました。スマホアプリ側の挙動を想像するに、タイトルやアーティスト名を取得した後で画像のハンドルを要求しても、アプリ側ではまだ画像が準備できていない場合があるのではないでしょうか? スマホアプリ側もネットワーク経由でサーバから画像を取得する必要があり、その処理が間に合わない場合に失敗応答を返していると考えれば、問題の発生状況と挙動が一致します。あらかじめタイトルやアーティスト名情報収集と共に、アルバム画像も用意してからアプリから プレーヤに対してTrack Changedイベントを通知すれば、このような問題は発生しないでしょうから、YTube Music等のアプリはそのような動作をするのに対し、Sportifyはそうなっていないのではないでしょうか? このようにプレーヤー側で対処できることはわかりましたが、既存のカーナビのプレーヤーはそう簡単にアップデートは望めないでしょうから、やはりアプリ側で対応して欲しいところですね。

 


Cover Artに再挑戦

2025-01-17 22:00:30 | DoomPlayer

以前、STM32H7B3I-DKで試したAVRCPのCover Art機能ですが、今度はLVGLPlayerのBluetooth Player機能に追加すべく再挑戦しています。以前試した時には、Sportifyを使った場合に正しい画像が表示されない問題があったのですが、現在は改善されたのか正しい画像が表示されるようなのです。しかしながら、時折画像がダウンロードされない問題に遭遇しています。Sportityのコミュニティでも1年半以上前からのスレッドで延々と不具合報告が続いているようです。

当初はCover Art表示機能については、使用できるSRAMが減ってきたのでサポートできないだろうと思っていたのですが、各所で使用するメモリを削ったりして問題なくJPEGの画像データをダウンロードして表示できるようになりました。本記事では、メモリを節約した方法について書き残しておくことにします。

スタック領域の共有 LVGL Playerでは3つのアプリケーションを走らせることができますが、これらのアプリケーションは、複数のタスクにより構成されています。各アプリケーションは同時に実行されることはありませんから、タスクが使用するスタック領域を共有することによりメモリを節約できます。FreeRTOSではスクのスタック領域を動的に割り当てることも可能ですが、LVGLPlayerではメモリ管理の都合上静的にわりあてることにしていますので、共通の領域を使うことで節約しています。

変数領域の共有 各アプリケーションは同時に実行されることはないので、各アプリケーションが使用するメモリ領域も共有することが可能です。これを実現するためには、Linkerスクリプトで、OVERLAYコマンドを使って各アプリを構成するオブジェクトファイルをまとめてグループとすることで、同一メモリ領域に配置してやります。

TJegDecを使う STM32U575にはハードウェアJPEGデコーダは用意されていませんので、ソフトウェアでデコードを行う必要があります。デコードにTJegDecを使うことでlibjpegを使う場合に比べて使用するメモリを削減することができます。

Draw Bufferのサイズを減らす LVGLでは画面描画のためのバッファには、画面サイズの1/10程度のバッファでも充分な速度で動作可能とされています。使用しているLCDは 480x320の RGB565フォーマットですが、ダブルバッファリングで使っていますので、1ラスタ分減らせば2KB近くのメモリを削減できます。

LVGLでは元々TJpegDecがライブラリのひとつとして用意されていますが、そのAPIはAVRCPで使うには向いていないので、用意されているライブラリは使わないことにしました。TJpegDecは約3.5KBのRAMがあれば動作可能とされていますが、AVRCPのCovert Artで使うには  1) ダウンロードしたJPEGデータを保管しておくためのバッファ、2) デコード結果の画像ビットマップを保持しておくためのバッファ の2つのメモリ領域が追加で必要となります。1番目のバッファについては、JPEGデータを受信しながら並行してデーコードを進めるように工夫してやれば、不要にできます。2番目のバッファは、LCDに直接書き込むような使い方であれば不要にできますが、LVGLではImage widgetを使って描画したいので、そうもいきません。結局、2つのバッファともPSRAM上に用意すること(チカラ技!)で対応していますが、1番目のバッファを不要とする対策については後ほど挑戦したいと思います。

Doom Music Playerでは、FFTの表示演出としては回転する放射状バーと低音の強さに応じて大きさが変化する中心画像がありましたが、これらの画像描画にかなりのCPUタイムが消費されていることがわかったので、こちらではアルバム画像は静止表示したままで、FFTも4つのバー表示にとどめることで表示負荷を軽減することとしました。

Sportify Free Planでは時折入る広告表示にもスポンサー名や画像が入るのでそれなりに楽しめるのですが、広告が連続した時に画像取得が失敗することが多いような気もします。曲の入れ替わり(AVRCP的には Track Change)のイベント通知をきっかけとして画像取得を行うのですが、そのタイミングも関係しているのかもしれません。


FreeRTOSV11とSystemView -- その2

2025-01-03 15:12:14 | DoomPlayer

前記事で書いたようにMusic PlayerやBluetooth Playerの実行時にはguitaskがCPU時間のかなりの部分を使ってしまっていることがわかりました。そこでguitaskの動き方をもう少し詳しく調べてみることにしました。

実行時に何度か止めてみると、かなりの頻度でlv_timer_handler() が呼ばれていることに気づきました。5ms程度の間隔で呼ぶことにしていたので、この間隔を20msまで延ばしたところかなりIdleタスクが動くようになりました。

Idle時間が生まれたとはいえ、やはりguitaskの実行時間が支配的であることがわかります。そこで、さらにlv_conf.hにて、

#define LV_USE_OS LV_OS_FREERTOS

を設定。以前は、lvglDrawタスクにスタックを8KBも取られてしまうので使うのをためらっていましたが、今はLV_DRAW_THREAD_STACK_SIZE でスタックサイズを指定できるようになったので、4KBに減らしてみました。

lvglタスクのうち、描画のためのレンダリング処理の部分がlvglDrawタスクとして分離されることにより、その部分の比重を知ることができます。上図に見れるようにlvglDrawタスクの割合が半分以上を占めていることがわかりました。現在はレンダリング処理はすべてソフトウェアになっていますので、やはりこの部分をGPUのようなハードウェアによって処理できれば、かなり助かることがわかります。現在もv9.3に向けての開発が進んでいるmainブランチでは DMA2Dのサポートが復活しているので、開発の様子をみながら対応することを考えてみるつもりです。


FreeRTOSV11とSystemView

2024-12-25 20:49:34 | DoomPlayer

先ごろ、STM32N6の発表に伴いSTM32CubeMXのアップデートがありました。ほぼ時を同じくしてX-Cube-FreeRTOSも新しくなっていたので内容を確認してみたのですが、使用されているFreeRTOSのバージョンは10.6.2となっており、ちっとも新しい感じがしません。

LVGLPlayerではCubeMXが生成してくれるFreeRTOSを使っていたのですが、V11が使えないままなのにはがっかり。そこで方針転換して CubeMXが生成するFreeRTOSは使わないことにして、GItHubから直接V11を持ってくることにしました。ソースコードでは、RTOS APIとしてはCMSIS RTOS2を使っているのですが、その部分だけはX-Cube-FreeROTSに含まれているコードを流用しています。

さて、どうしてFreeRTOSV11が使いたかったかと言うと、それはSystemView が使いたかったからです。FreeRTOSV10でもSystemViewが使えるのですが、そのためにはFreeRTOSのソースにパッチを当てる必要がありました。それが面倒なので、SytemViewを使うのをためらっていたのですが、FreeRTOSV11ではカーネルソースへの変更が不要になり、FreeRTOSConfig.h を編集するだけで済むようになりました。

実際に使ってみるとトレース情報が多すぎてすぐにイベントバッファのオーバフローが発生してしまします。そこでSEGGER_SYSVIEW_Conf.h に 

#define TRACERETURN_ENABLE            ( 0 )

の一文を追加。これで細かいFreeRTOS APIのトレース情報出力を抑止することができます。

まっとうに動くようになったので、以前から気になっていたMusic PlayerでDOOM音楽を再生中の動作をキャプチャしました。

全体的に紫色で示されるguitaskの実行時間が多いことが一目瞭然です。というか、guitaskで埋め尽くされているために、Idle時間が全く生じていないことがわかります。guitaskは LVGLの処理を担当するタスクであり、画面の更新とその再描画にかなりの時間がとられていることになります。

もう少し拡大してみます。。。

中央部分に見られる緑色の flacreaderは、音楽データであるFLACファイルをSDカードから読み出して展開デコードする処理を担当しています。これにもそこそこの時間が取られていることがわかります。FLACファイルを展開して得られたPCMデータは、mixplayerによってFFT解析されて画面上に廻る放射状のバーとして表示されます。このタスクは青緑で表示されていますが、それほど時間がかかっているわけでもありません。つまり、FFTの演算処理は十分に短い時間で終了しているものの、それを画面に反映するための guitask処理に多くの時間が取られているということがわかります。

次の例は、Doom PlayerではなくBluetooth Playerを実行して音楽を再生した場合の様子。

SDカードからFLACファイルを読むわけではないのでflacreaderタスクは動いていません。A2DPで音楽データを受信してデコードしているので、btstackタスクの実行時間が増えているのがわかります。それでも、やはりguitaskの実行時間が圧倒的に支配的なのが良くわかります。うーん、これ以上高速化をはかるためには、DMA2Dを使うしかないかな。LVGLのレンダリング処理にDMA2Dを使っても効果は限定的らしいのですが。。

最後の例はOscilloscope Musicを実行した場合です。

ここではflacreaderタスクはSDカードからWAVファイルを読み込んでいますが、中身は16bit PCMですのでデコード処理は必要ありません。そのため、サンプリング速度が192Kと高速でも処理時間は短くて済んでいます。一番時間をとっているのはやはりguitaskですが、前の例と違ってしCPU Loadの表示に白い余白部分(すなわち Idleタイム)ができており余裕で処理できていることがわかります。


N-SPHERES

2024-11-29 18:51:41 | DoomPlayer

当初は10月31日にリリースされる予定だった oscillosopemusic.comの最新アルバムN-SPERESですが、2週間遅れて11月14日にリリースされました。早速ダウンロードして、問題なく再生できることを確認済でしたが、GUI画面やゲームパッドを使っての操作を変更したりする作業を続けていました。一区切りついたので、動作の様子を示す動画を用意しました。

回路図とソースコードはGitHubにアップロードしてありますが、まだ説明のためのWikiページは作成途上です。