STM32H7を使ってみる3 -キャッシュ・ワンダリング(前篇)-
←前回 次回→
今から4年以上前、STM32F7ではぢめてキャッシュという概念に対峙し、分かった
つもりでお茶を濁してきましたがH7になった今どうしても正面から向き合わざるを
得ない事態になってしまいました…それも最悪な形で!!
●Cortex-M7のキャッシュにエラッタ発覚!
オイオイオイ死ぬわ私。(一般には今年春くらいに知れ渡った内容です)
要約しますとCortex-M7系マイコンでキャッシュポリシーをライトスル―にした状態で
Double-WORD(ARMの場合8バイト)の読み書きを同一のアドレスで行った時に、読み
出しの時にデータが壊れる事があるという内容…しかも現行の全リビジョン…
そしてカテゴリーAとかいうフュージョンジャックした剣崎さんでも不覚をとりかねない
クリティカルっていうか実質使用禁止設定判定なエラッタ…すざけんな!!111!
全文はこちらで読めますので各自把握しておいてください。
※おきぱのSTM32F7/H7向けFatFsデモはライトバックを
使用するように すでにコードを修正済ですので安心してお使いいただけます。
STM32F7/H7側の障害情報ではF7はもちろん最新のH745/755に至るまで当エラッタが
網羅され、全滅状態ですorz
つまり、STM32F7/H7でキャッシュを使用する際はキャッシュの取り扱いが面倒な
ライトバック以外にキャッシュポリシーがとれないことを示しますorz
ぁーぁ…
●ひとまずSTM32H7のキャッシュのおさらいっ
まずはけしかん様のブログ記事も熟読の上で…
STM32F7/H7に搭載されてたキャッシュメモリは命令(I)とデータ(D)用に独立した
キャッシュが設けられております。キャッシュの方式はI/D両者ともセット・
アソシエイティブという回路規模とキャッシュ性能を折半した方式が採られていて、
とりわけデータ用では4ウェイセット・アソシエイティブという方式となっています。
ウエーイが4つもあってどんだけリア充なんだYO!
そしてキャッシュポリシーとしてはSTM32F7/H7は下記の3タイプ存在します。
1.ライトスルー(ライトアロケート無し固定)
キャッシュに書き込みと同時に実メモリにも常に書きこむ。
キャッシュの取り扱いは簡単だが動作は一番遅い。
使い勝手一番良かったのにエラッタのせいで使用不能!!11!1
2.ライトバック・ライトアロケート有り
キャッシュラインがいっぱいになるかCleanしないと実メモリに書きこまない。
書き込み時キャッシュミスした場合1ライン分実メモリから読みだして
キャッシュラインに展開する。ちょっと遅い。
頻繁に読み書きする変数領域向けなのでフレームバッファのような書きっぱの
用途では著しく不利になるのでむやみに設定してはならない。
3.ライトバック・ライトアロケート無し
キャッシュラインがいっぱいになるかCleanしないと実メモリに書きこまない。
書き込み時キャッシュミスした場合も実メモリから読みだす動作はしない。
理論上一番早い。ライトスルーが封じられた今これが一番無難。
1〜3のいずれも読み込み側動作(リードアロケート)はすべて同様に行われる。
1.はエラッタのせいで死に設定なので2.や3.を選びます。尤もライトバック・ライト
アロケートありでもmemset等の関数で同じデータを書いていくような動作を検知して
自動的にライトアロケート無しに動的に切り替わりキャッシュが動くらしいです
(↑ほんまかいな)
詳しい解説はAPSさんのサイトにあります。
Cortex-Aのキャッシュについての解説ですがCortex-M7も動作や設定は同一です。
●で、具体的な設定はどうすればよいのか
Cortex-M7に置いてはMPU(メモリプロテクションユニット)からキャッシュポリシーの
設定を行います。ねむいさんのいつもののhw_config.cにあるMPU設定のサブルーチン
より、AXI-SRAMの設定を例に紹介します。
/* Configure the MPU attributes as Write-Back/No-Write-Allocate for AXI-SRAM D1 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
AXI-SRAMの512kByte丸々ライトバック・ライトアロケート無しの設定をする場合上記のようにします。
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
↑特にこの3行は重要です。ライトバッファ有効・キャッシュ有効でライトバック
となります。また、SHAREABLEの設定は必ずMPU_ACCESS_NOT_SHAREABLEに
しておいてください!ここをMPU_ACCESS_SHAREABLEにするとキャッシュを
無効にしたのと同じになってしまいます。実に罠設定です。
ちなみにこの超重要な情報はNXPのM7コアのマイコンiMXのアプリケーションノートに
明記されております。
しかしSTのマニュアルやアプリケーションノートには何所にも全く書いておらず、
罠にはまってキャッシュの効力殺してるの気づいてない人多いんじゃないかと☠
SHAREABLE有効にしつつキャッシュ動作を有効させる方法もありますが今回の
システムではまだ利用価値が無いので割愛します。
また、ライトアロケート有りで行きたい場合は
MPU_TEX_LEVEL0->MPU_TEX_LEVEL1に変更します。
でもCortex-M7コアでライトアロケートありするくらいならエラッタ付き
ライトスルーにした方が10000000000倍マシです☠
こちらの比較も次回以降解説しますね。
/* Configure the MPU attributes as Write-Back/No-Write-Allocate for AHB-SRAM1 D2 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure the MPU attributes as Write-Back/No-Write-Allocate for AHB-SRAM2 D2 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30020000;
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure the MPU attributes as Write-Back/No-Write-Allocate for AHB-SRAM3 D2 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER3;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure the MPU attributes as Write-Back/No-Write-Allocate for AHB-SRAM4 D3 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x38000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER4;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
残りの内蔵SRAMの設定もライトバック・ライトアロケート無しの設定としました。
AHB-RAMはAXIバスマトリクス上にはないので意味なさそうですが実はキャッシュの
恩恵にあずかることができます。
/* External-Memories cache setting */
/* Configure the MPU attributes as Write-Back/No-Write-Allocate for External SDRAM */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xD0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32MB; /* STM32H747I-Disco have 32Mbyte SDRAM */
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER6;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; /* MUST be No-WriteAllocation to avoid collision LTDC-Hostage */
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* External-Memories cache setting */
/* Configure the MPU attributes as Write-Back for QSPI-DirectRemapping(ReadOnly) */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x90000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_128MB; /* STM32H747I-Disco have 64*2=128MByte QSPI-ROM */
MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RO_URO;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER7;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
外部メモリ領域のSDRAMやQSPIはAXIバスでつながっているので当然のことながら
大きな影響を受けます。しっかりキャッシュ設定をしておきましょう。
また、SDRAMをLTDCのフレームバッファに使用したい場合は必ずライトアロケーション
なしを選択してください。ライトアロケーションありだといちいちCleanをしてやる
必要が出来てしまい、それを怠るとDMAの時のようにデータの一貫性が保たれ
なくなり表示がおかしくなります。フレームバッファはデータを読みだすことは
ほぼ無く書きっぱなしなのでライトアロケーションなしの方が都合が良いのです。
QSPIはメモリマップドモードのリードオンリーで使用するためどうでもよいですが
AccessPermission以外はSDRAMとキャッシュ設定を合わせておきましょう。
そしてSAI等の周期的にデータ投げる用途ではAXI-SRAMをライトアロケート有りにして
いるとキャッシュコントロールを今よりさらに厳格にしないと高ビットレートでポツポツ
ノイズが入りやがることが分かったので・・・#####
もう全部一律ライトアロケート無しでやります!111!!!
次回は上記キャッシュポリシーの設定別に実動作をさせたときの性能の比較を
行ってみたいと思います!
-
免責・連絡先は↑のリンクを
↓SNSもやってます↓
powered by まめわざ- ARM/STM32 (116)
- OpenOCD (27)
- ARM/NxP (34)
- ARM/Cypress (5)
- ARM/Others (3)
- ARM/Raspi (1)
- AVR (13)
- FPGA (4)
- GPS/GNSS (19)
- MISC (81)
- STM8 (2)
- Wirelessなアレ (16)
- おきぱ (1)
- ブラウザベンチマーク (28)
- 日本の自然歩道 (25)
- STM32U0はぢめました
⇒ ねむい (08/07) - STM32U0はぢめました
⇒ ひかわ (07/28) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ねむい (05/17) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ どじょりん (05/16) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ どじょりん (05/16) - いろいろ試す61(と今年の反省会)
⇒ ねむい (01/02) - いろいろ試す61(と今年の反省会)
⇒ ひかわ (01/02) - いろいろ試す61(と今年の反省会)
⇒ ひかわ (01/01) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ねむい (12/31) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ひかわ (12/31)
- October 2024 (1)
- September 2024 (1)
- August 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (1)
- April 2024 (1)
- March 2024 (1)
- February 2024 (2)
- January 2024 (1)
- December 2023 (4)
- November 2023 (2)
- October 2023 (2)
- September 2023 (1)
- August 2023 (2)
- July 2023 (1)
- June 2023 (2)
- May 2023 (3)
- April 2023 (1)
- March 2023 (1)
- February 2023 (1)
- January 2023 (1)
- December 2022 (2)
- November 2022 (1)
- October 2022 (1)
- September 2022 (1)
- August 2022 (1)
- July 2022 (1)
- June 2022 (1)
- May 2022 (1)
- April 2022 (1)
- March 2022 (1)
- February 2022 (1)
- January 2022 (1)
- December 2021 (2)
- November 2021 (2)
- October 2021 (1)
- September 2021 (1)
- August 2021 (1)
- July 2021 (1)
- June 2021 (1)
- May 2021 (1)
- April 2021 (1)
- March 2021 (1)
- February 2021 (1)
- January 2021 (1)
- December 2020 (3)
- November 2020 (1)
- October 2020 (1)
- September 2020 (1)
- August 2020 (1)
- July 2020 (1)
- June 2020 (2)
- May 2020 (1)
- April 2020 (1)
- March 2020 (1)
- February 2020 (1)
- January 2020 (1)
- December 2019 (3)
- November 2019 (1)
- October 2019 (1)
- September 2019 (2)
- August 2019 (1)
- July 2019 (1)
- June 2019 (1)
- May 2019 (1)
- April 2019 (1)
- March 2019 (1)
- February 2019 (1)
- January 2019 (1)
- December 2018 (3)
- November 2018 (2)
- October 2018 (1)
- September 2018 (1)
- August 2018 (1)
- July 2018 (1)
- June 2018 (1)
- May 2018 (1)
- April 2018 (2)
- March 2018 (1)
- February 2018 (1)
- January 2018 (1)
- December 2017 (2)
- November 2017 (2)
- October 2017 (1)
- September 2017 (1)
- August 2017 (1)
- July 2017 (1)
- June 2017 (1)
- May 2017 (1)
- April 2017 (1)
- March 2017 (2)
- February 2017 (2)
- January 2017 (2)
- December 2016 (7)
- November 2016 (2)
- October 2016 (2)
- September 2016 (1)
- August 2016 (1)
- July 2016 (1)
- June 2016 (1)
- May 2016 (2)
- April 2016 (1)
- March 2016 (2)
- February 2016 (1)
- January 2016 (1)
- December 2015 (3)
- November 2015 (1)
- October 2015 (3)
- September 2015 (2)
- August 2015 (2)
- July 2015 (3)
- June 2015 (3)
- May 2015 (4)
- April 2015 (2)
- March 2015 (4)
- February 2015 (1)
- January 2015 (3)
- December 2014 (3)
- November 2014 (2)
- October 2014 (1)
- September 2014 (2)
- August 2014 (2)
- July 2014 (3)
- June 2014 (2)
- May 2014 (1)
- April 2014 (1)
- March 2014 (4)
- February 2014 (4)
- January 2014 (3)
- December 2013 (5)
- November 2013 (4)
- October 2013 (3)
- September 2013 (2)
- August 2013 (2)
- July 2013 (2)
- June 2013 (3)
- May 2013 (2)
- April 2013 (2)
- March 2013 (2)
- February 2013 (2)
- January 2013 (3)
- December 2012 (4)
- November 2012 (2)
- October 2012 (2)
- September 2012 (4)
- August 2012 (1)
- July 2012 (3)
- June 2012 (2)
- May 2012 (3)
- April 2012 (3)
- March 2012 (2)
- February 2012 (3)
- January 2012 (3)
- December 2011 (5)
- November 2011 (3)
- October 2011 (2)
- September 2011 (2)
- August 2011 (2)
- July 2011 (2)
- June 2011 (2)
- May 2011 (2)
- April 2011 (2)
- March 2011 (2)
- February 2011 (2)
- January 2011 (3)
- December 2010 (7)
- November 2010 (1)
- October 2010 (1)
- September 2010 (1)
- August 2010 (3)
- July 2010 (4)
- May 2010 (1)
- April 2010 (2)
- March 2010 (2)
- February 2010 (2)
- January 2010 (3)
- December 2009 (3)
- November 2009 (8)
- October 2009 (7)
- September 2009 (5)
- August 2009 (4)
- July 2009 (6)
- June 2009 (6)
- May 2009 (14)
- January 1970 (1)
Copyright(C) B-Blog project All rights reserved.