メイン・コンテンツまでスキップ

2. CPU動作

動機

このセクションでは、マイクロコントローラ・コア、内蔵RAM、Flashが目的とするクロック速度で動作していることを確認します。

TouchGFXは、どのようなマイクロコントローラ速度でも動作可能ですが、クロック設定を誤ると、必要な性能を満たせない可能性があります。 この後のボードの立ち上げでは、タッチ・コントローラのI2Cクロックなど、特定のタイミング・パラメータを設定する必要があります。 そのような設定は、マイクロコントローラが正しい速度で動作していることが保証されない限り、行えません。

STM32マイクロコントローラではシステム・クロックを設定します。 このクロックは分周されて、FCLKコア・クロックや、APB1などの各種ペリフェラル・クロックを生成します。

目標

このセクションの目標は、クロックが適切に設定されるようにプロジェクトを変更することです。 さらに、内蔵RAMおよびFlashが期待通りの速度で動作していることも確認します。

検証

次の表に、このセクションの検証ポイントを示します。

検証ポイント検証内容
SystemCoreClock変数の値が正しいマイクロコントローラが、目的の周波数で動作するように設定されていること。
内蔵RAMを読み出せるマイクロコントローラが期待される容量の内蔵RAMを備え、これが読出し可能で、その速度を測定できること。
内蔵Flashを読み出せるマイクロコントローラが期待される容量の内蔵Flashを備え、これが読出し可能で、その速度を測定できること。
キャッシュが無効化されているキャッシュを無効にして実行すると、システムの複雑さが抑えられ、動作がわかりやすくなること。

前提条件

以下に、このステップの前提条件を示します。:

  • ハードウェアのクロック・ソースに関する情報。 クリスタルを使用するのが一般的ですが、その他の方法も可能です。

作業内容

ここからは、必要なマイクロコントローラ周波数を得るために、プロジェクトのクロック設定を調整するステップを進めていきます。 その後、内蔵Flashの読出し速度の測定方法を説明します。

システム・クロック

STM32CubeMXの[Clock Configuration]タブをクリックします。 使用する特定マイクロコントローラのクロック・ツリーの概要が表示されます。

クロック設定

この例では、クロック・ソースとしてHSIが選択されています。 多くのプロジェクトで外部クリスタルを使用しますが、その場合はHSEを適切な分周回路(/M) や逓倍回路(/N) とともに使用する必要があります。 クロック設定に関するアドバイスは、本ガイドの対象外です。 クロック設定を変更したら、STM32CubeMXでプロジェクトを再生成する必要があります(右上隅の[Generate Code]をクリック)。

コア・クロック(HCLK) は、生成されるコードにより、実行時に計算され、変数に保存されます。 この変数をアプリケーション・コードで使用すれば、クロック・サイクル数と秒数や起動タイマなどの間の正確な変換が可能になります。 変数を再計算するには、SystemCoreClockUpdate()関数を呼び出す必要があります。 Call文は、main.c(ユーザ・コード・セクション)に挿入します。

SystemCoreClockUpdate

その関数の最後にブレークポイントを設定しておけば、コア・クロックを確認(設定に応じて) できます。

SystemCoreClock

もう一つの重要なテスト・ポイントはシステム・タイマです。 このタイマは、HCLKで動作し、1msごとに割込みを発生するように分周されています。 STM32Cubeファームウェアは、ミリ秒単位の遅延を実現するために、このタイマを使用します。

タイマの動作は、mainにたとえば5秒の遅延を挿入することでテストできます。 遅延時間はストップ・ウォッチなどで検証します。

遅延の測定

FlashとRAMのサイズおよび速度

システム・タイマを使用すれば、メモリの読出し速度の確認は簡単です。 システム・タイマの割込みにより、1ミリ秒ごとに変数がインクリメントされます。 コードの前後でこの変数を読み出すことで、コードの実行時間を(1ms単位で) 測定できます。 この方法を使用して、アプリケーションの各所で時間を測定できます。 精度は、それほど高くありませんが、オシロスコープなどの外部デバイスなしで測定することが可能です。

このためには、まず結果を保存するための2つのvolatile変数が必要です。 ここで結果を保存しないと、最適化コンパイラで測定用のコードが削除される場合があります。

測定結果を保持するグローバルなvolatile変数

以下に、Flashの0x08000000から0x08020000まで(128Kb) を読み出し、そのコードの時間を測定する例を示します。

読出しループの時間測定

このようなコードは、各種メモリの速度の検証に使用できます。 STM32CubeMXで設定を作成したら、読出し速度を測定して結果を記録します。 この測定は、後で繰り返し検証できます。 メモリバンド幅(kb/s単位での読出し速度) を測定する場合は、データ量と測定された時間を比較します。

16MHzのSTM32F429では、コードは12msで実行されます。したがって、(この方法による) 内蔵Flashの読出し速度は、128kb / 0.012s = 10,666kb/sになります。

上記のループを変更することで、内蔵Flashの全領域が有効化され読出し可能であることを簡単に検証できます。 変更するのは、開始アドレスと終了アドレスだけです。

このコードで内蔵RAMも確認できます。 F429の場合、RAMはアドレス0x20000000から始まります。 コア直結メモリは0x10000000です。 使用する特定のマイクロコントローラのデータシートで、これらに該当するメモリ・アドレスを確認してください。

さまざまなメモリについて、何度か測定を行い、結果を記録してください。 RAMについては読出しと書込みの両方の速度をテストします。

リンカ・スクリプト

もう一つの注目すべきものとしてリンカ・スクリプトがあります。 この設定ファイルは、システム上のRAMとFlashのアドレスをリンカに伝えます。 リンカ・スクリプトは、プロジェクトとともにCubeMXによって生成されますが、内容を確認しておくことを推奨します。 多くの場合、今後、プロジェクトのニーズに合わせて変更する必要が生じます

F7およびH7のキャッシュ

Arm Cortex-M7ベースのSTM32F7とSTM32H7マイクロコントローラには、データおよび命令のキャッシュが含まれています。 安定したプラットフォームが得られるまで、少なくともデータ・キャッシュは無効化しておくことを推奨します。 データ・キャッシュは多くの場合、性能を大幅に向上させますが、テストを複雑にする要因にもなります。

プラットフォームが安定したら、データ・キャッシュを有効化して構いません。 その段階になれば、問題の原因がデータ・キャッシュ管理であることを容易に特定できます。そうでなければ、プラットフォームは正常に機能するからです。

データ・キャッシュの複雑さは、マイクロコントローラ・コアがキャッシュに対して読み書きを行うのに対し、DMA2やLTDCなどのペリフェラルは(キャッシュではなく) メモリから直接読み出すことに起因します。 そのため、たとえばフレームバッファにデータを書き込んでも、そのデータの一部はディスプレイに表示されないような状況が発生します。 これは、その時点で新しいデータがまだキャッシュにしか書き込まれていないため、LTDCがRAMからそのデータを見つけられなかったためです。 解決策は、プロジェクトの特定の時点でキャッシュを書き込むことですが、そのような処理はもっと後で行うことを推奨します。

キャッシュ動作は、STM32CubeMXのシステム・コアのセクションで無効化 / 有効化できます。

TouchGFX内部のDCacheステート・マシン

TouchGFXエンジンは、現在および直近のレンダリング動作を記録します。HARDWARESOFTWAREの2つの状態があります。 描画動作の大部分がハードウェアによって実行されるため、初期状態はHARDWARE に設定されます。 状態遷移が発生すると、ステート・マシンが適切な仮想関数を呼び出し、キャッシュの無効化を処理します。 状態がHARDWAREからSOFTWAREに遷移する場合は、仮想メソッド void touchgfx::HAL::InvalidateCache()を呼び出し、SOFTWAREからHARDWAREへの遷移の場合は仮想メソッドvoid touchgfx::HAL::FlushCache()を呼び出します。 これら2つの関数の機能の派生HALクラスへの実装はユーザに委ねられています。

TouchGFXエンジンの内蔵DCacheのステート・マシン

TouchGFX Generatorを使用する場合は、これらの派生メソッドがDCache無効化の関数呼び出しとともにTouchGFXGeneratedHALクラス内に実装されるため、特段の作業は不要です。

参考資料

ここにリンクされているドキュメントには、STM32CubeMXとSTM32のキャッシュに関する詳細情報が掲載されています。