STM32 ARTアクセラレータで高速化してみる。

stm32 Advent Calendar 2017 16日目の記事です。

100MHz越えのマイコン使ってるけど思ったより計算速度が出ない・・・・っていう問題があって色々調べたらフラッシュの速度が原因だった。
そこでSTのARTアクセラレータの機能を使って信号処理の高速化をやってみたって話です。
あくまでSTがすごいだけで僕はその機能を使ったってだけなので悪しからずw


ART Accelerator(Adaptive real-time memory accelerator)

f:id:gsmcustomeffects:20171005182840p:plain

ART Acceleratorは図の赤の部分についてるTCMバス経由でのフラッシュの読み出しウェイトを事実上0にするキャッシュ群みたいなもの。

実際flashの速度って80MHz程度が限界なので高速動作する場合はRAMにコードを置いたりする。(LPCなんかがそう

そこで下の図のようにflashから大量に先読みしてバッファするっていう脳筋ハードウエアペリフェラル
俗にいうインストラクションプリフェッチとか言われている奴をメモリで殴った感じ
f:id:gsmcustomeffects:20171005184126p:plain

インストラクションプリフェッチにもいろいろ問題があって例えばに実行時にキャッシュ上に必要なデータがあってうまくヒットした場合はいいが何かのデータを当てに分岐命令を書いている場合必ずしもヒットしない。
この場合再リロードを行う必要がある。この際flashからの応答にコアはwaitで待つことになる。

そういうことも見越してART内にはブランチキャッシュというものを持っておりある程度の緩和を行っているものだと思う。

実際の流れでは以下のようになる。

インストラクションプリフェッチなし

f:id:gsmcustomeffects:20171005185743p:plain

128bit読み出しを行っているので4命令までは連続フェッチ行けるがそのあとFlashをwaitしている。
この図はF4のなのでF7では256bit

インストラクションプリフェッチあり

f:id:gsmcustomeffects:20171005190302p:plain

一方こちらではインストラクションキャッシュがFIFO的に働くので送りながら次の命令をプリフェッチできている。
なのでCPU的には連続で実行できる。

AXIMのこと忘れてね?

おっとそうでした。
図に示す通りにFlashへのアクセスはTCMだけではなくAHBのバスマトリックスを経由したAXIMからでも行えます。
f:id:gsmcustomeffects:20171005191031p:plain

そもそもCortexM7にはI/Dキャッシュがあります。(0~64KBの間でベンダーが決定して搭載)
こっちを有効にすれば命令、データともにキャッシュが有効になります。

実質この機能だけでだいぶ高速になります。

このAXIMってバスはペリフェラルバスと同一なレーンにいるため渋滞を招くことも懸念されます。
そのためSTはTCIM経由でキャッシュできる構造を取ったのでしょう。

おまけ1:その他の高速化

とりあえずここまででARTが何なのか?がわかったと思うので僕が感心しているDTCMメモリでも話そうと思います。

f:id:gsmcustomeffects:20171005193349p:plain

要するにCPUから最速アクセス可能な密結合メモリのことです。

場所としてはここ

f:id:gsmcustomeffects:20171005193753p:plain

クリティカルなコードやデータをここに配置することで高速化を図れる。
おき方としてはリンカーでアドレスくくって定義てそこに対して起動時にコピーすれば行ける。

その他DTCMにはGPDMAでも書けるのでCPUとペリフェラルで書き換えが頻繁なものはこのアドレスに対して書き込ませれば処理時間が少しは早くなるかもしれない。
またこの領域はキャッシュの影響を受けないのでその点でも結構使いやすい。

各種配置による速度差はIAR様のこの資料がわかりやすいです。
https://www.iar.com/globalassets/pdf/st-kits-kk/8_work_with_effective_software_development_for_cortex-m7_201504.pdf

やりかた

やりかただけ書いておく。

CubeMXでCortexM7の欄を開く

f:id:gsmcustomeffects:20171005194738p:plain

このように設定する。

次にリンカスクリプトでROMの開始アドレスを0x00200000に変更する。

これで実行した時のプログラムカウンタがそれっぽい番地に来てればいいはず

f:id:gsmcustomeffects:20171005195433p:plain

ちなみに有効になってるか確認するにはFlashレジスタを確認するといいです。

f:id:gsmcustomeffects:20171215205512p:plain

ちなみにONとOFFでFIRフィルタを回した時はこんな感じだいぶ処理時間が変わってくる。

f:id:gsmcustomeffects:20171002073035p:plain

2018/11/24追記
いつの間にかCubeMXもVer5になっていますが・・・・
F4ではRCCのメニューで有効にできるみたいです。
f:id:gsmcustomeffects:20181124214419p:plain

各社CortexM7のひかくてきなやつ

Kinetis® KV5x MCU

f:id:gsmcustomeffects:20171005195903p:plain

SAM V70

f:id:gsmcustomeffects:20171005200000p:plain

i.MX RT1050

f:id:gsmcustomeffects:20171118001020p:plain

これに関してはキャッシュが32KBもあるので強すぎかな?w

まとめ

CortexM7のキャッシュについて理解を深めた。
ARTが何なのかがわかった気がした。
関連してこの記事もどうぞ
gsmcustomeffects.hatenablog.com




参考文献

ネットの記事

APS様CortexM7解説
www.aps-web.jp

ねむいさんのブログ
ねむいさんのぶろぐ | STM32F7を使ってみる5 -AXIMとITCM-

CQ出版の解説ページ
www.kumikomi.net

マイナビニュース
news.mynavi.jp

書籍

  • ARMマイコンCortexM教科書
  • Interface2016年12月号付録 STM32便利帳2016

STM32のタイマークロックについて

ここ最近タイマーを結構使うようになってクロック源について悩んだのでメモ

僕が普段使っているSTM32F7のタイマーのクロック源としてはAPB1、APB2の二つがある。


んでCubeでクロック設定をしている僕は気にしていなかったのだけどたくさん使うようになってどれがどこからもらってきているかがわからなくなった。
そんなわけでメモを残す。

うだうだ言ったけど結構簡単でRCC関連のレジスタをみれば書いてある。

f:id:gsmcustomeffects:20170827085138p:plain

f:id:gsmcustomeffects:20170827085206p:plain

ここに書いてある通りに割り振られてるのでCubeでこの辺いじると各種タイマーがどうなるのかわかると思う。

f:id:gsmcustomeffects:20170827085307p:plain

あと注意するのがRCC_DCKCFGR1レジスタのタイマークロックプリスケーラ(タイマーのカウントプリスケーラとは別のやつ)のビットをいじった時はこのへん読む

f:id:gsmcustomeffects:20170827085712p:plain

STM32のUSBCDCでMicroShellを動かす

前回まででUSBCDC(コミュニケーションデバイスクラス)でVCP(VirtualCOMPort)の動作は確認できたので今回はこれにMicroShellを使える状態していく作業になります。
CDCのやり方はこの記事みてください。
gsmcustomeffects.hatenablog.com

やることは

  • 1文字送受信APIの準備
  • 受信バッファサイズの設定
続きを読む

WEAKシンボルについて

ここ最近ARM系のお勉強を頑張っています。


今日はWEAK修飾子についてです。
STを例に話すと割り込み後に呼ばれるコールバックってのがWEAKマクロを使って記述されてます。
定義先に行くと

__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(htim);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */

}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	  //i2c_lcd_writeCommand(ClearDisplay);
	  i2c_lcd_writeCommand(ReturnHome);
	  HAL_Delay(2);
	  xprintf("Count:%d",count);
	  count++;
}


のように記述されている。

これをMainで呼び出すとこのように使う。



要は同じ関数が二個あったらWEAKがついてる側が譲るということである。
こうすることで関数の上書き的なことができる。これがないとmain文で定義しなければコンパイルエラーになってしまうのでこうやって回避しているわけである。


ちなみにI2C系のデバイスライブラリ作るときもI2Cの送信APIを上書きで定義できるようにすれば汎用性を持たせられるので便利

__weak void i2c_write(){
	//This Section  is User function
}
void i2c_write(){
	HAL_I2C_Master_Transmit(&hi2c1,addri2c,(uint8_t*)data,2,0xFF);
}

これでi2c_lcdの制御部分を記述してます。
1文字送信コマンドが2byteなのでこういった回りくどいことしてます。
f:id:gsmcustomeffects:20170603224309j:plain

STM32でSPI通信をやってみる1(ポーリングでマイコン同士で通信編)

今回はCubeHALライブラリを用いてSPI通信をやってみる記事です。

STM32のSPIは全二重、半二重、単方向、マルチマスターモードなどいろいろ対応してますが今回は一般的な全二重でやってみようと思います。

f:id:gsmcustomeffects:20170510195127p:plain

Pin Name description
MOSI マウターアウトスレーブイン
MISO マスターインスレーブアウト
SCK シリアルクロック
NSS スレーブセレクトピン
続きを読む

ZOOM MS50g,MS70CDRのMIDI制御

今回はZOOM社のマルチストンプのMIDI制御についてです。

一年前ぐらいにUSBHOSTでMIDI制御しましたがいろいろ発見があったので今回こうして書いているわけです。


続きを読む