新しい組み込みDSPの検討、LPC55S69のmbed化

Pocket

発端はオーディオでオリジナルの信号処理やサンプルレートの管理を実現したいというものでした。今までDACを作るときは以下のようなルーティングでこれを実現していましたが、それぞれ問題がありました。最もシンプルで一般的なものから、徐々に複雑なパターンを紹介します。構成を増やす理由はどれも別角度になりますが音質面の配慮が中心です。

  1. デジタルレシーバ(USB、SPDIF等)>DAC >内部FIR >内部オーバーサンプリング
  2. デジタルレシーバ(USB、SPDIF等)>何らかのリクロック >DAC >内部FIR >内部オーバーサンプリング
  3. デジタルレシーバ(USB、SPDIF等)>ASRC処理用IC >ASRCでFIRアップサンプル >DAC >内部オーバーサンプリング
  4. デジタルレシーバ(USB、SPDIF等)>DSPやFPGA >等倍SRCでFIRアップサンプル >何らかのリクロック >DAC >内部オーバーサンプリング

大体このような構成と処理になります。

1の構成ですとデジタルレシーバやUSBのクロック性能が支配的になり、これらの性能が悪いとDAC出力の性能が低下します。主にSNです。無音のときはSNが良いのにフルスケールの信号を出力するとノイズフロアが上がるなどの症状の場合、クロックに含まれる位相雑音や、DAC内部のエレメント誤差などが出力に現れたものです。現代の⊿Σ系DACはマスタークロックの性能がそのまま出力性能に影響を与えますから、クロックの性能はとても大事です。

この性能劣化を防ぐためには何らかのリクロック処理(信号のタイミングを揃える、ジッターや位相雑音を減らす処理)が必要になります。現在のDACで殆どの場合は(ESSを除く)下記のASRCではなくPLLのリクロックが主流だと思います。ASRCはデータを変更するので、実際の音質劣化以上にイメージ的に忌避されやすいようです。

ASRCについてはこちらに記事を書きました。

ASRCによる弊害と実益

現代ではあまり評価されていないように思いますが、実際にはデメリットよりメリットのほうが上回ります。データを改変するというイメージが独り歩きしているように思います。ですがこれを使うとDAC側に高精度のクロックを置くことができ、それを基準にDACが動作しますから出力の性能はASRCによって実際に高くすることが出来ます。これについてはデータが優位性を証明しているということです。

その上で私がこれから独自実装のDSPで解決したい課題があります。それは以下の内容です。これは同期型のSRCでも共通でDAC内部のオーバーサンプリングでも同じ課題があります。

  • インターサンプルピークの問題 フルスケールデジタル信号でSRC処理をするとレベルオーバーするため、事前にレベルを下げてからSRCする必要がある
  • デジタルフィルター特性の問題 DAC内蔵や既存のIC類を使うとフィルター特性が自由にならない、常識的なフィルターしか選べない

以上です。これらは独自実装でしか解決が出来ません。AK4499-DACではADAU1452という比較的扱いやすい覚えやすいDSPをつかって独自フィルターを実装しましたが、内部の重要ブロックに音質劣化を招くものがあったこと(後に対策)、次に原因不明のバグのような不具合があり今後も修正される見込みがないこと、これらの理由からADAU1452は今後使わないでより安定していて理想に近い信号処理をできるような新しいプラットフォームを検討することにしました。

検討した内容

ここまでの調査で有力な候補だったのは、どちらもi.mx RT1050とLPC55S69でした。今までずっとmbedで足回りの開発を行っていたので、過去の資産が流用できるmbed対応を中心に選ぶとこうなりました。これらのチップが優秀なのはI2Sを直接ハードウェアで扱うことができる点です。マニュアルを読むと外部同期クロックで送受信するので勝手にSRCされるなどもありません。その辺はすべて自由に作ることが出来ます。

以下はRT1050の資料、600Mhz動作とかなりの高機能です。マイクロコントローラとしては申し分ない性能というか、過去の常識で考えると明らかに過剰な位の性能だと思います。この方法ならDSPチップを外部で用意する必要がなくなり、DSP機能とI2S信号管理や切り替えとさらにI2CやSPIやUIやピン制御も全部ワンチップに統合することが出来ますから、全体の構成もシンプルにすることが出来ます。特にRT1050はSPDIFも直接扱えるのが良くてデジタルレシーバチップも不要になります。上のDACのルーティングで言えば以下のようにできるわけです。

  • MPUで信号受信からDSP処理アップサンプルまで >リクロックまたはASRC >DAC >内部オーバーサンプリング

画像

もう一つのLPC55S69を見てます。

こちらは基本機能は地味です。あまりオーディオ用という感じではないですが、実はしらべてみると搭載されているDSPが意外と高性能なことがわかります。PowerQuadという名前でこちらに解説と、演算性能の測定データがあります。

https://www.digikey.jp/ja/articles/leveraging-markets-first-arm-cortex-m33-based-mcu-part-1

ここからの引用によると、

PowerQuadアクセラレータは、内部的には複数のレジスタとインターフェースを一連のハードウェアエンジンと組み合わせ、高速フーリエ変換(FFT)、離散コサイン変換(DCT)、無限インパルス応答(IIR)、有限インパルス応答(FIR)、そして三角関数を効率的に計算するために使用される座標回転デジタルコンピュータ(CORDIC)アルゴリズムなどの主要な信号処理機能を提供します(図2)。

NXP SemiconductorsのLPC55S6xマイクロコントローラファミリの図

図2:NXP SemiconductorsのLPC55S6xマイクロコントローラファミリは、信号処理アプリケーションで通常必要とされるアルゴリズムの実行を高速化するために専用エンジンを使用する、同社のPowerQuadコプロセッサを統合しています。(画像提供:NXP Semiconductors)

PowerQuadアクセラレータの使用によって、開発者は、ホストプロセッサがリアルタイムイベントに応答したり、一連の動作を完了するなどの能力を犠牲にすることなく、複雑な信号処理操作を実行できます。ホストプロセッサは、要求される信号処理機能によってPowerQuadレジスタを設定し、転送元、転送先、および作業メモリ領域のメモリアドレスを指定します。起動後、PowerQuadアクセラレータは、AHBマトリクスを使用してバスマスターとして128ビットメモリ転送を実行する、真のコプロセッサとして動作します。その間、ホストプロセッサは即座にメイン処理タスクに戻り、定期的にPowerQuadのビジービットをポーリングするか、単にPowerQuad完了割り込みに応答して結果にアクセスすることができます。

ただし、開発者にとっては、PowerQuadの動作はほぼ透過的です。開発者は、Arm Cortexマイクロコントローラ ソフトウェアインターフェース標準(CMSIS)DSPライブラリ用の標準API(アプリケーションプログラミングインターフェース)を使用します。NXP SemiconductorsのMCUXpressoソフトウェア開発キット(SDK)に含まれるNXPのPowerQuad対応バージョンのライブラリは、ソフトウェアに実装されている低レベルの数学関数をPowerQuad APIの呼び出しで置き換えます。

たとえば、複雑なFFTを計算するには、開発者は標準のCMSIS-DSP関数arm_cfft_q31()を使用します。これは、符号用に1ビット、指数用に31ビットを使用する32ビット固定小数点数を表すQフォーマットのデータです。純粋なソフトウェア実装では、arm_cfft_q31()関数を呼び出すと、CMSIS DSP FFTバタフライソフトウェア関数arm_radix4_butterfly_q31()とend関数arm_cfft_radix4by2_q31()、または複素逆FFTの逆バージョンが呼び出されます。

ただし、NXP DSPライブラリとPowerQuadを使用している場合は、通常arm_cfft_q31()を呼び出すと、PQ_TransformCFFT()が呼び出され、ハードウェアで同じ計算が処理されます。その結果、Cortex-M33コアの処理負荷が軽減されるだけでなく、DSP機能の実行が高速化されます(図3)。

MCUXpressoソフトウェア開発キットのグラフ

図3:MCUXpressoソフトウェア開発キットは、低レベルのCMSIS-DSP関数を、PowerQuadアクセラレータの呼び出しに透過的に置き換えることによって、標準のArm CMSIS DSPライブラリへの高レベルの呼び出しとの互換性を維持しながら、一般的なDSPアルゴリズムの実行を大幅に高速化します。(画像提供:NXP Semiconductors)

以上です。こちらの記事も良かったです。画像はここから借りてます。

How the PowerQuad Co-processor Frees Up CPU Cores within the LPC55S69 MCU – Trade Articles

単純なDSP機能の性能を見ると、実はLPC55S69がよりハイスペックなRT1050より、FIR演算だけ見たら優位のようです。RT1050では600Mhzで上記のCMSIS-DSPを実行することになりますので、単純なクロック比で見ると100MHzのPowerQuadのほうが倍以上早いということになります。

これをみてLPC55S69への興味が一気に湧いてきました。勢いで開発ボードを購入しました。あとの問題は開発環境です。mbedは現在独自の開発環境に移行(mbed-cli, mbed studio)しており、NXPの提供する標準IDEでは使えません。標準IDEはDSP用のSDKのインポート機能や各種サポート機能、デバッグ機能が揃っており、それらはmbed標準環境には欠けているものです。LPC55S69のハードウェアの深層に触れるためにはmbed環境は不足があります。なのでできればmbedをNXPxpressoで使うことが望ましいです。

本来mbedのオンラインコンパイラには外部IDE用のエクスポート機能を提供していますが、調査したところによるとLPC55S69はこの機能をサポートしていませんでした。これは不運です。となるとmbed OSをZipソースファイルから自力でNXPxpressoに移植しなければならないということです。実はこれは簡単ではありません。かなり大変な作業です。しかし結構な時間を費やしてなんとかやり遂げました。

頑張って移植した成果物をここに紹介します。このためにまるごと数日費やしましたが、最終的にビルドに成功し実機で動作するところまで持っていきました。

公式フォーラムのログと引用

このノウハウ自体は直接役に立ちませんが、Eclipseに異なる環境から移植する際の何らかの参考になるかもしれませんので、日本語情報としてこちらに引用して記録を残すことにします。これを参考にすれば他のエクスポート非対応の環境を、公式IDEに移植することができるかもしれません。

https://forums.mbed.com/t/unable-to-export-lpc55s69-to-eclipse-or-gcc/12420

私はついにMCUxpressoでmbedosコンパイルに成功しました。これについての十分な情報がなかったので、私は苦労しました。そこで、この困難を克服する方法をここに記録します。この情報が、MCUXpressoとEclipseでmbed開発環境を実現したい人に役立つことを願っています。

  1. すべてのソースを静的ライブラリにします

mbedcliとGCC-ARMを使用して静的ライブラリを生成します。mbed studioはGCC-ARMを使用できるようですが、静的ライブラリの作成方法に関する情報はまだ見つかりませんでした。

mbed compile –library –source = mbed-os

結果はlibmbed-os.aです。gccがライブラリを呼び出すときは、lib“ mbed-os” .aのようなmbed-os部分のみを使用します。私が原因を突き止めるまで、エラーは永遠に発生しました。

静的ライブラリを作成する理由はいくつかあります。最大の理由は、e = 87エラーを回避することです。mbed OSの膨大な量のオブジェクトリンクは、Windowsの32000文字の制限によってトラップされます。いずれにせよ、Eclipseでは毎回コンパイルするのに時間がかかるので、最終的にはこの問題を回避する必要があります。

しかし、Eclipseでe = 87エラーを回避する方法は次のとおりです。

  1. MbedCLI環境からGCC-ARMアーティファクトを取得する

静的ライブラリ、コンパイル、およびこれら2つのアーティファクトには、ヘッダーとディレクトリ構造があります。それらをEclipseプロジェクトにコピーします。これらは静的ライブラリを参照するために必要です。

mbed osの元のソースには多くの不要なファイルが含まれており、公式のmbedコンパイルではそれらのリンクが自動的に解除されているようです。しかし、Eclipseはそれらを処理できず、すべてエラーが発生します。それらはすべて手動で削除する必要があります。ただし、これは大変な作業です。

静的ライブラリを使用する場合、それを行う必要はありません。私はこれを使います。

次。また、インクルード、シンボル、およびリンカー関連の情報をアーティファクトから流用します。これらの情報を取得するためのファイルは次のとおりです。

  • .profile-asm
  • .profile-c
  • .profile-cxx
  • .profile-ld
  • .link_options.txt
  • .link_script.ld
  • mbed_config.h

この後、ここから取得した情報をEclipse環境にインポートする必要があります。ただし、これはEclipseGUIでは困難な作業です。ここでは、外部テキストエディターでの連続処理によってインポートするXMLファイルを作成し、それをEclipseにインポートする必要があります。必要に応じて、Eclipseで.cprojectを直接編集して追加できます。(「メイクファイルを使用する必要があります。」その点は正しいです。)

.link_script.ldは、問題のあるCコードを含まないメモリアドレスマップアーティファクトです。元のLPC55S69_cm33_core0_flash.ldには、エラーの原因となる内部Cコードが含まれています。目的はこれを回避することです。誰かがそれをオリジナルのように扱うために事前に構築することができるかもしれませんが、それは不要です。Eclipseで単一のMPU用に開発する場合、link_script.ldを直接編集できます。

すべてが正しければ、コンパイルは問題なく通過します。

  1. リンカーエラーと戦う

ただし、リンカにはまだ多くのエラーがあります。リンカーエラーは神経質なので、それらを殺すには注意と大胆さの両方が必要でした。

  • arm-none-eabi / lib / thumb / v8-m.main + fp / softfp \ libc.a(lib_a-sbrkr.o):関数_sbrk_r':sbrkr.c:(.text._sbrk_r+0xc): undefined reference to _sbrk ‘内。

リンカフラグに「-lnosys」を追加します。

  • arm-none-eabi / lib / thumb / v8-m.main + fp / softfp \ libc.a(lib_a-malloc.o):関数free': malloc.c:(.text.free+0x6): undefined reference to __wrap__free_r内
  • arm-none-eabi / lib / thumb / v8-m.main + fp / softfp \ libc.a(lib_a -__ call_atexit.o):関数register_fini': __call_atexit.c:(.text.startup.register_fini+0x6): undefined reference to __wrap_atexit ‘内。

これらのエラーに対処する方法。

  • `__wrap__free_r ‘への未定義の参照。
  • `__wrap__malloc_r ‘への未定義の参照。
  • `__wrap__calloc_r ‘への未定義の参照
  • `__wrap__realloc_r ‘への未定義の参照。

リンカオプションから以下を削除することで問題を解決しました。

  • -Wl、–wrap = _free_r
  • -Wl、–wrap = _malloc_r
  • -Wl、–wrap = _calloc_r
  • -Wl、–wrap = _realloc_r

これは、元のオプションとは異なるオプションです。理由はわかりませんが、次に進みます。

  • /irq_armv8mml.S:105:`TZ_StoreContext_Sへの未定義の参照
  • /mbed-os\rtos\source\TARGET_CORTEX\rtx5\RTX\Source/rtx_kernel.c:85:`TZ_InitContextSystem_Sへの未定義の参照
  • /mbed-os\rtos\source\TARGET_CORTEX\rtx5\RTX\Source/rtx_thread.c:1094:`TZ_FreeModuleContext_Sへの未定義の参照
  • /mbed-os\rtos\source\TARGET_CORTEX\rtx5\RTX\Source/rtx_thread.c:717:`TZ_AllocModuleContext_Sへの未定義の参照

これらは、Eclipseのリンカーその他のオブジェクトに以下を追加することで解決できます。

{workspace_loc:/ {ProjName} /mbed-os/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC55S69/TARGET_M33_NS/prebuilt/cmse_lib.o}」

これからは、原因を見つけるのにとても苦労しました。

  • arm-none-eabi / lib / thumb / v8-m.main + fp / softfp \ libc.a(lib_a-signalr.o):関数_kill_r': signalr.c:(.text._kill_r+0x12): undefined reference to _kill内
  • arm-none-eabi / lib / thumb / v8-m.main + fp / softfp \ libc.a(lib_a-signalr.o):関数_getpid_r': signalr.c:(.text._getpid_r+0x0): undefined reference to _getpid ‘

これらをリンカフラグに追加します。

-Wl、–start-group -lstdc ++ -lsupc ++ -lm -lc -lgcc -lnosys -Wl、–end-group

また、同じ宣言をEclipseのライブラリに追加します。これで問題は解決しますが、2回宣言する必要があります。原因は、オブジェクトがロードされる順序への依存性にあるようです。

残りのエラーへの対処。

  • /mbed-os\targets\TARGET_NXP\TARGET_MCUXpresso_MCUS\TARGET_LPC/sleep.c:33:`POWER_EnterDeepSleepへの未定義の参照
  • /mbed-os\targets\TARGET_NXP\TARGET_MCUXpresso_MCUS\TARGET_LPC55S69\TARGET_LPCXpresso/clock_config.c:90: `POWER_SetVoltageForFreq ‘への未定義の参照。
  • /mbed-os\targets\TARGET_NXP\TARGET_MCUXpresso_MCUS\TARGET_LPC55S69\TARGET_LPCXpresso/clock_config.c:139:「POWER_SetVoltageForFreq」への未定義の参照。

リンカに「-lpower」を追加します。ライブラリ検索パスに「-lpower」を追加します。

{workspace_loc:/ {ProjName} / mbed-os / targets / TARGET_NXP / TARGET_MCUXpresso_MCUS / TARGET_LPC55S69 / device / TOOLCHAIN_GCC_ARM}」

これは、事前の知識がなければ明らかではありません。

動作します!リンカオプションは次のようになります。(個人的なパスを省略)

-DDOMAIN_NS = 1 -DTFM_LVL = 1 -DXIP_ENABLE = 0 -Wl、–wrap、_memalign_r -Wl、–wrap、exit -Wl、–wrap、main -Wl、-n -march = armv8-m.main + dsp -Wl 、–start -group -lpower -lstdc ++ -lsupc ++ -lm -lc -lgcc -lnosys -Wl、–end-group -Xlinker -Map =“ LPC55S69_mbed.map” -Xlinker –gc-sections -Xlinker -print- memory-使用法-mcpu = cortex-m33 -mfpu = fpv5-sp-d16 -mfloat-abi = softfp -mthumb -T link_script.ld -L“ \ MCU \ LPC55S69_mbed” -o“ LPC55S69_mbed.axf”。/main.o/MCU/LPC55S69_mbed/mbed-os/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC55S69/TARGET_M33_NS/prebuilt/cmse_lib.o-。lmbed-os -lpower -lstdc ++ -lsupc ++ -lm -lc -lgcc -lnosys

  1. 最後に

ここに書けなかった詳細情報がいくつかあります。これは、誰もが同じ結果を得るのに十分ではないかもしれません。そこで、LPC55S69 mbedos用のMCUXpressoプロジェクトをどこかにアップロードしたいと思います。稼働したら報告します。

実機で動作したソース一式

https://github.com/yohine/LPC55S69-mbed5-MCUxpresso

mbed os5.15.6を搭載したLPC55S69用のMCUxpresso11.3.0プロジェクト

LPC55S69_mbed.zipをダウンロードすると、MCUxpresso関数により、圧縮されたプロジェクトファイルからワークスペースにインポートできます。

https://stackoverflow.com/questions/51014565/download-zip-file-from-github-and-import-in-eclipse

結局どうなったのか

mbed os 5の評価途中だったのですが、とりあえず現時点ではLPC55S69ベースの開発は見限りました。ここまで苦労したのですが重要なことに最初に気づけなかったので仕方ないです。

いろいろな理由があるのですが、最大の理由はmbed osそのものの問題、そしてこちらの将来的に達成したい目標と現実性の兼ね合いです。それは大規模なソフトウェアを自力で開発する是非にあります。上記の最初のきっかけとなったDSP処理については、LPC55S69でも性能的には問題なさそうなんですが、よくよく考えてみるとDSP以降にやりたいことを全部盛り込むためにはやや窮屈なプラットフォームかもしれないと感じました。

理想は現状のモノクログラフィック液晶や赤外線リモコンを排除があります。Bluetoothで携帯から操作したり、ネットワーク関連機能にも対応したり、DSPもただのSRCじゃなくてもっと高度な処理を将来的にできるようにしたいです。さらにマイコンとしての周辺IO制御と信号処理を統合し、さらに高度なユーザーインターフェースも提供することです。これら次世代の体験をもたらしたい。

ですがこれらの全てを自力で開発するのは果たして現実的かと考えました。元々プログラムはそんなに好きではないので何でも自力で開発をやりたいわけではありません。機能は実現したいけど、その過程は楽しくないです。なのでプログラミングはどちらかというとやりたくないが、必要だから仕方なくやっているが現実です。この調子では壮大な目標など達成不可能だと考えました。

特にmbed OSベースの開発では現実的ではない大変な労力がかかることがわかりました。mbedの歴史には問題があります。それはmbedの過去資産の互換性です。mbedそのものは歴史もありますしユーザーも多かったのですが、そのコミュニティの成果物がOSのバージョンアップによって過去の資産が使えなくなってしまっている、さらにユーザーが激減していてそれらの情報が整理更新されていないということです。これは正直致命的です。いちいちソースを見て直すか、自分で作るしかありません。

このような伝統的なマイクロコントローラ的発想の開発は、膨大な過去ライブラリがなければその性能を活かしきれません。マイコンで大規模なソフトウェア開発を行うためには過去の資産を使えなければ大変なことになります。ないものは全て自力で開発しなければなりません。幸いmbed OSにはファイルシステム、ネットワーク、各種通信の基本機能は用意されていますが、その動作自体は自分で書く必要があります。OSといってもシンプルでハードウェアに近い制御命令が用意されているだけですので、動作自体は全て記述する必要があります。大規模な動作を実現するためには結構大変な工数が必要ということです。

これらの作業が本当に自分にとって必要か、やりたいことなのか。それを冷静に考えるとそこまでプログラミングが好きではないので現実的じゃないという結論に至りました。完全に放棄するわけではないですがmbedを基本にしたマイクロコントローラ的アプローチは一旦保留にします。

今は組み込みLinuxを検討中です。アプリケーションプロセッサを使ってLinuxなら過去の資産も実績も十分です。正直ファイルシステムやネットワークや各種制御機能、音声の基本的な処理も、グラフィック関係も、基本的な全ては伝統的なOSを使えば自分で制御する必要はありませんでした。過去の資産が膨大なので確かに使いこなすのは大変なのですが、自分で上記を全部プログラミングする必要はありません。より強力な足回りは用意されているようなものです。マイコンSDKのみが徒歩、mbed OSが自転車、Linuxならバイクでしょうか。ということで現在進行系で色々試しているところです。まだ報告できることはありません。

一応ですがマルチの対応は今の時点では積極的ではありませんが自宅で色々試してみようとは思っています。FIRのタップ数も増えれば自宅システムの低域にIIRを使っている現状から改善できるかもしれません。特にLinuxなら既存のソフトでそういう処理もできそうなので現実的だと思いました。基本的な機能は既存のソフトでできるのが良いです。マイコンだとこれらも全部自分で組まないといけません。

そのうち面白い成果を報告できればと思います。

Subscribe
Notify of
guest

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

3 Comments
Inline Feedbacks
View all comments
kei
kei
1 month ago

完全にはフォローできていないのですが、開発環境としては、platformio はいかがでしょうか。https://platformio.org/
よくメンテナンスされていますし、私は愛用しています。
私は CLI (Command Line Interface)での利用ですが。

Last edited 1 month ago by kei
kei
kei
1 month ago

Teensy4.0 は5Vトレラントが必要なければ、衝撃的な性能・価格でしたね。私も自宅で使っています。