Arm Cortex-M55搭載 STM32N657でプログラムを作成 (1) 1stステージ・ブートローダ

**※ [更新 2025.4.4] IDE等のバージョンアップに伴い更新しました。**

STM32N657は2024年末にリリースされたArm Cortex-M55コア搭載のSTM32マイコンです。メーカ純正の開発ボード STM32N6570-DK (Discovery kit) を使用してみたところ、最初からTrustZoneが有効となっており、これまでのSTM32のプログラム開発と少し違いがったので記事としてまとめておきます。
執筆時点で実際に試した内容ですが、新しいマイコンなのでこれから変わる可能性もあるので注意してください。随時更新していく予定ですので変更点は履歴をご確認ください。

今回は開発環境を立ちあげ、FSBL(First Stage Boot Loader)から簡単なアプリケーションをデバッグ実行するまでを記載します。

# 使用した開発環境・ツール
以下を使用しました。バージョンは本稿で確認したものです。

- 開発ボード STM32N6570-DK
https://www.st.com/ja/evaluation-tools/stm32n6570-dk.html
ST-LINKデバッガをボードに備えていますので、USBケーブルでPCに接続するだけでデバッグが可能です。
![20250123_134758.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/a986e82d-9396-77de-3b5c-e1ecd9ea1338.jpeg)
写真1 STM32N6570-DK  

- IDE(統合開発環境)　STM32CubeIDE v1.18.0
https://www.st.com/ja/development-tools/stm32cubeide.html
ダウンロードしてインストールしておいてください。Windowdsであればインストーラでインストールできます。  

- 開発ツール　STM32CubeProgrammer　v2.19.0
https://www.st.com/ja/development-tools/stm32cubeprog.html
ダウンロードしてインストールしておいてください。Windowdsであればインストーラでインストールできます。今回は使用しませんが次回以降で使用します。  

- ファームウェア　STM32CubeN6 MCU Package v1.1.0
https://www.st.com/ja/embedded-software/stm32cuben6.html
STM32CubeN6は、HALやBSPなどのパッケージです。各種プロジェクトのテンプレートも含まれています。ダウンロードして展開しておきます。  

# 基本事項
プログラム開発を行うにあたって必要最小限の事項を説明します。
マイコンやボード、各種ツールの詳細はそれぞれのマニュアルを参照してください。

## アドレス空間とTrustZone
STM32N657のアドレス空間はIDAUにより下表のように256MB単位で分けられ、最上位桁が偶数の空間は非セキュアであり、その次の奇数のセキュアな空間にエイリアスされています。
IDAUの設定は変更できません。SAUにより上書きは可能です（詳細はArmのTrustZoneの仕様を参照）

|先頭アドレス|Secre/Non Secure|対象|
|-|-|-|
|0x0000_0000|NS|Boot ROM, ITCM|
|0x1000_0000|S|Boot ROM, ITCM|
|0x2000_0000|NS|内蔵RAM, DTCM|
|0x3000_0000|S|内蔵RAM, DTCM|
|0x4000_0000|NS|ペリフェラル|
|0x5000_0000|S|ペリフェラル|

外部メモリは0x6000_0000以降にマップされエイリアスは存在しません。SAUにより非セキュアに割り当て可能です。

## メモリ構成
STM32N657は以下のメモリを内蔵しています。
|種別|先頭アドレス(NS/S)|サイズ|
|-|-|-|
|ITCM|0x000_00000 / 0x1000_0000|64KB|
|Boot ROM|0x0800_0000 / 0x1800_0000|128KB|
|DTCM|0x2000_0000 / 0x3000_0000|128KB|
|AXISRAM|0x2400_0000 / 0x3400_0000|4.2MB|
|Backup SRAM|0x2C00_0000 / 0x3C00_0000|8KB|

STM32N6570-DKボードには以下の外部メモリが搭載されています。
- 128MB Octo‑SPI FLASH メモリ
- 32MB Hexadeca‑SPI PSRAM

## 開発プロジェクトの種類
STM32N657はTrustZoneが有効となっていますので、開発するプログラムはTrustZoneの利用形態によって異なった形式となります。
STM32CubeN6には、4種類のプロジェクトのテンプレートが用意されていますので、それぞれ簡単に説明します。

どのテンプレートのプロジェクトにおいても、マイコンのリセット後はBoot ROMのプログラムにより、FLASHメモリ上のFSBL(First Stage Boot Loader)が内蔵SRAMに転送されて実行されます。

### Template プロジェクト
BootROMからFSBLを内蔵SRAMに転送し実行するだけの最も単純なプロジェクトです。
FSBLはセキュアモードで実行されます。

### Template_FSBL_LRUN(Load & Run) プロジェクト
Boot ROMから実行されたFSBLが、FLASHメモリ上のアプリケーションを内部SRAMに転送し実行するプロジェクトです。FSBLとアプリケーションの二つのサブプロジェクトから構成されます。
すべてセキュアモードで実行されます。

### Template_FSBL_XIP プロジェクト
Boot ROMから実行されたFSBLが、FLASHメモリ上のアプリケーションを外部メモリに転送し実行するプロジェクトです。FSBLとアプリケーションの二つのサブプロジェクトから構成されます。
すべてセキュアモードで実行されます。

###  Template_Isolation_LRUN プロジェクト
Boot ROMから実行されたFSBLが、FLASHメモリ上のセキュアおよび非セキュアのアプリケーションを内蔵SRAMに転送し実行するプロジェクトです。FSBLと2つのアプリケーションのサブプロジェクトから構成されます。
FSBLからはセキュア・アプリケーションが実行され、セキュア・アプリケーションが必要な設定を終えた後に非セキュア・アプリケーションを実行します。

### Template_Isolation_XIP プロジェクト
Boot ROMから実行されたFSBLが、FLASHメモリ上のセキュアおよび非セキュアのアプリケーションを外部メモリに転送し実行するプロジェクトです。FSBLと2つのアプリケーションのサブプロジェクトから構成されます。
FSBLからはセキュア・アプリケーションが実行され、セキュア・アプリケーションが必要な設定を終えた後に非セキュア・アプリケーションを実行します。

## テンプレートの実行
各テンプレートはボードで実行することができます。どれもボード上のLEDを点滅させるプログラムとなっています。所謂Lチカです。
まずは環境の確認も兼ねて、以下の手順でTemplate プロジェクトを実行してみるとよいでしょう。

(1) STM32CudeIDEを実行し、[File]メニューから[Import]を選択します。
(2) ダイアログで[Exinsting Project into Workspace]を選択し、[Next]を押下します。
(3) [Select root directory]の[Browse]を押下し、テンプレートのディレクトリを指定します。Template プロジェクトは以下のパスとなります。

`en.stm32cuben6-v1-1-0\STM32Cube_FW_N6_V1.1.0\Projects\STM32N6570-DK\Templates\Template`

(4) [Finish]を押下すると、STM32CudeIDEのProject Explorerにインポートされたプロジェクトが表示されます。
図1はTemplate プロジェクトと、Template_FSBL_LRUNプロジェクトの二つのプロジェクトをインポートした画面です。STM32CubeIDEは複数のプロジェクトを一つのワークスペースにインポートすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/eace53be-5f80-761a-0361-578a260983de.png)
図1 インポートしたプロジェクト

(5) Template プロジェクトはその中にTemplate_FSBLというサブプロジェクトが生成されています。Template_FSBLを右クリックし、メニューから[Build project]を選択すると、プログラムがビルドされます。
注意点は、ルートのプロジェクトではなく、サブプロジェクトを右クリックすることです。

(6) [Debug]メニューから[Debug Configurations]を選択します。開いたダイアログで[STM32 C/C++ Application]をダブルクリックすると、直前にビルドしたプロジェクトのデバッグ構成が生成されます。
図2のように[C/C++ Application]に実行ファイル(ELFファイル)が設定されていれば成功です。失敗した場合はデバッグ構成をいったん削除し、ビルドからやりなおしてください。直前にビルドの成功したプロジェクトが対象となります。手動で設定することもできますが、これが一番簡単な方法だと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/1b8195dd-6f63-a3d3-9216-1343cd98db4e.png)
図2 [Debug Configurations]ダイアログ

(7) PCとボードをUSBケーブルで接続します。USBコネクタはSTLINKと書かれている方です。
ボード上のSW1(BOOT1) が1-3側にしてDevelopment bootのモードとします。

(8) [Debug]を押下します。実行プログラムがボードに転送され、デバッグ画面に変わった後、実行を開始します。
初期の設定ではFSBLのmian関数でブレーク(一時停止)します。[Run]メニューから[Resume]を選択するとプログラムは実行を再開します。うまくいっていればボード上のLEDが点滅します。

# 新規プロジェクトの作成とデバッグ実行
新規にプロジェクトを作成してデバッグ実行するまでを行います。まずは、Template プロジェクトと同等、つまりFSBLを実行して、その上でHALとBSPを使用してLEDを点滅させます。

## 新規プロジェクトの作成
以下の手順でプロジェクトを作成していきます。すべてSTM32CubeIDEでの作業となります。

(1) [File]メニューから[New]->[STM32 Project]を選択します。
(2) [Board Selector]タグを選び、`STM32N6570-DK`を選択します。「STM32N6」で検索するとすぐに見つかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/bda70a7d-c2c8-d4ae-0725-6a11e841e42b.png)
図3 Board Selector

(3) [Next]を押下して進み、[Project Name]に任意のプロジェクト名を入力、その他はデフォルトの設定のまま[Finish]を押下します。一つのワークスペースに同一のプロジェクト名は使用できないので注意が必要です。
図4の例では[Project Name]に`test`と入れています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/e9490fda-918a-e048-d49a-89a6df70b780.png)
図4 STM32 Project

(4) プロジェクトが生成されるのでしばらく待ちます。何か聞かれてきたら基本は「Yes」と答えます。

(5) プロジェクトが生成されるとハードウェアの設定画面(***.iocファイル)が表示されます。ボードを選択してプロジェクトを生成した場合、基本的な設定は済んでいます。
しかし、STM32N6570-DKでは、クロック設定にエラーの警告が表示されます。たぶんバグだと思われるので、この先修正されるかもしれません。
[Clock Configuration]タブを選び、[Resolve Clock Issues]を押下すると、問題点を修正してくれます。どうやらOTGHS1とOTGHS2のクロック設定に問題があるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/2e754d91-f00d-2472-0d4d-95407c47f1e5.png)
図5 Clock Configuration

(6) その他、端子設定やクロック設定をアプリケーションに応じて変更します。今回のLED点滅では不要です。iocファイルを閉じる、またはセーブすると、図6のようにコードを自動生成するか聞いてきますので[Yes]と答えます。これでハードウェアの設定に基づいてプロジェクトのコードが生成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/3e7e6f85-c1d3-e460-3019-be29e63507fe.png)
図6 コード生成

(7) ここまでうまくいくと、Project Explorerに作成したプロジェクトが図7のように表示されているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/6de6585d-8548-53ac-d7d0-2e78fefe4e5c.png)
図7 新規プロジェクト

実際のファイルシステム上のディレクトリ構成は以下のようになります。サブプロジェクト名がディレクトリ名と異なっている点に注意してください(`test_FSBL`≠`FSBL`)。

```
├─Drivers
│  ├─CMSIS
│  │  ├─Device
│  │  │  └─ST
│  │  │      └─STM32N6xx
│  │  │          ├─Include
│  │  │          └─Source
│  │  │              └─Templates
│  │  └─Include
│  └─STM32N6xx_HAL_Driver
│      ├─Inc
│      │  └─Legacy
│      └─Src
└─FSBL
    ├─.settings
    ├─Core
    │  ├─Inc
    │  ├─Src
    │  └─Startup
    └─Drivers
        └─STM32N6xx_HAL_Driver
```

(8) 確認のため、FSBLサブプロジェクトを右クリックし、[Build Project]を選択して実行プログラムをビルドしてみましょう。図7では`test_FSBL`と表示されているのがFSBLのサブプロジェクトです。

(9) 本来、自動生成したプロジェクトはそのまま実行できるはずなのですが、このプログラムは実行するとmain関数のペリフェラルの初期化中にハングします。クロックかペリフェラルの設定に誤りがあるのではと思われます。たぶんバグか知れませんので、この先修正されるかもしれません。
~~今回は以下のファイルを修正します~~（※ [追加 25/02/27]を参照。こちらの方が後々良いかと）

`(project)\FSBL\Core\Src\main.c`

ファイル中のmain関数の中の `MX_SDMMC2_SD_Init()` と`MX_USB2_OTG_HS_HCD_Init()`の呼び出しをリスト1のようにコメントアウトするか削除します。

```C
/* リスト1  main.cのmain関数の一部修正 */

  MX_SAI1_Init();
  // MX_SDMMC2_SD_Init();  << これ
  MX_UCPD1_Init();
  MX_USART1_UART_Init();
  MX_USB1_OTG_HS_USB_Init();
  // MX_USB2_OTG_HS_HCD_Init();  << これ
  MX_XSPI1_Init();
```
(注意) この修正はソースコードを自動生成すると上書きされてしまいます。抜本的にはプロジェクトの設定を変更すべきでしょう。ここは暫定対策ということで。

**[追加 25/02/27]** ソースコードの自動生成による上書きを避けるには、コンフィギュレーションでSDMMC2とUSB2を以下にように無効にすることにより、コード生成自体と止められます。

(1) ***.iocを開き設定画面(Devaice Configuration Tool Perspective)を開きます。
(2) [Pinout & Configuration]の[Categories]の[Connectivity]の中の[SDMMC2]と[USM2_OTG_HS]のチェックマークを外します(図7.5)。
(3) ***.iocをセーブしてコードを自動生成させれば、SDMMC2とUSB2のコードは生成されなくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/18048c7f-2db2-474a-8e76-b045cb468f8f.png)
図7.5 ハードウェアの設定変更

## BSPのインストール
STM32N6570-DKにはメーカからBSP(Board Support Package)が提供されており、これを使うとボードの各種操作を行うAPIが使用できるようになります。
ただし、現時点ではSTM32CubeIDEはSTM32N6570-DKのBSPには対応してないので手動でBSPを取り込む必要があります。他のボードではBSPに対応しているものもあるので将来改善されるかもしれません。
LDEの点滅程度はBSPを使わずとも難しくありませんが、今後を考え手動でBSPを導入してみます。BSPの組み込み方はいくつか考えられますが、本稿ではSTM32CubeN6の方式になるべく沿ってみます。
以下の手順で進めます。

(1) プロジェクトにBSPを格納するディレクトリを作成します。
`(project)\Drivers\BSP\STM32N6570-DK`

(2) STM32N6570-DKのBSPはSTM32CubeN6の以下のディレクトリにあります。
`en.stm32cuben6-v1-1-0\STM32Cube_FW_N6_V1.1.0\Drivers\BSP\STM32N6570-DK`
上記のディレクトリ内のファイルをすべて(1)で作成したディレクトリにコピーします。
実際には使用するファイルのみでかまいませんが、後から使用することも考えて全部コピーしてよいでしょう。

(3) サブプロジェクトにBSPのディレクトリを追加します。今回はFSBLサブプロジェクトに以下のようにディレクトリを作成します。
`(project)\FSBL\Drivers\BSP\STM32N6570-DK`

(4) サブプロジェクトで使用するBSPのファイルのリンクを(3)で作成したディレクトリに作成します。
LDE制御で使用するBSPのファイルは`stm32n6570_discovery.c`です。
リンクの作成は、Project ExplorerでAltキーを押しながら、対象ファイルをドラッグ&ドロップします。図8のようにリンクを作成するか聞かれますので[OK]と答えます。Altキーを押していないとファイル移動になるので注意してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/0b15f8d4-f10f-d7b3-be1c-ce267d59fe37.png)
図8 BSPファイルのリンク

## プログラムの追加
自動生成したプロジェクトには何もしないプログラムが書かれています。ここにボードのLEDを点滅されるプログラムを追加します。

### インクルードパスの追加
main関数からBSPを使用するために、サブプロジェクトのインクルードパスに以下の手順でBSPディレクトリを追加します。

(1) Project ExplorerでFSBLサブプロジェクトを右クリックし[Properties]を選択します。
(2) 左側の[C/C++ Build]->[Settings]を選択し、[Tool Settings]タブの[MCU/MPU GCC Compiler]->[Include paths]を選択します。
(3) 図9のようにBSPのインクルードパス`../../Drivers/BSP/STM32N6570-DK`を追加します。
(4) [Apply and Close]を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179541/48e44a07-8334-3385-f62f-56ea8e5bb747.png)
図9 Settings

### インクルードファイルの追加
main関数からBSPを使用するために、BSPの定義ファイルを以下のmain.hファイルにインクルードします。
`(project)\FSBL\Core\Inc\main.h`

上記のmain.hファイルの中に`USER CODE BEGIN Includes`という記述がありますので、そこにリスト2のようにインクルードを記述します。
```C
/* リスト2　main.hにインクルードファイルを追記*/

/* USER CODE BEGIN Includes */
#include "stm32n6570_discovery.h"   << これ
/* USER CODE END Includes */
```
### コンフィギュレーションファイルの作成
BSPのコンフィグレーションファイルを以下に作成します。
`(project)\FSBL\Core\Inc\stm32n6570_discovery_conf.h`

コンフィギュレーションファイルのテンプレートはBSPのディレクトリにありますので、これをベースに設定を記述します。
`(project)\Drivers\BSP\STM32N6570-DK\stm32n6570_discovery_conf_template.h`

今回はSTM32CubeN6のTemplate プロジェクトのコンフィグレーションファイルをそのまま使用しました。
`en.stm32cuben6-v1-1-0\STM32Cube_FW_N6_V1.1.0\Projects\STM32N6570-DK\Templates\Template\FSBL\Inc\stm32n6570_discovery_conf.h`

### main関数の変更
前述のmain.cのmain関数の最後にはリスト3のように無限ループのコードが記載されています。

```C
/* リスト3　main関数の一部 */

  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
```
`USER CODE BEGIN`と`USER CODE END`の間にプログラムを記述することができます。それ以外の場所に記述すると、プロジェクトの設定を変更しコードを自動生成する際に上書きされてしまう可能性がありますので注意しましょう。

リスト4のようにHALとBSPのAPI呼び出しを追加します。
```C
/* リスト4　LED点滅プログラムの追記 */

  /* USER CODE BEGIN 2 */
  BSP_LED_Init(LED_GREEN);    // LEDの初期化
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    HAL_Delay(1000);             // 1秒待ち
    BSP_LED_Toggle(LED_GREEN);   // LEDを反転
  }
  /* USER CODE END 3 */
```

## ビルドとデバッグ実行
### サブプロジェクトのビルド
FSBLのサブプロジェクトをビルドします。サブプロジェクトを右クリックし、メニューから[Build project]を選択すると、プログラムがビルドされます。
実行プログラムのメモリへのアサインは以下のファイルに記述されています。
`(project)\FSBL\STM32N657X0HXQ_AXISRAM2_fsbl.ld`

上記ファイル中に以下の記述があります。
```
MEMORY
{
  ROM    (xrw)    : ORIGIN = 0x34180400,   LENGTH = 255K
  RAM    (xrw)    : ORIGIN = 0x341C0000,   LENGTH = 256K
}
```
ROM、RAMとありますが、どちらも内蔵SRAM上に配置されています。FSBLはBootROMにより内蔵SRAMに配置されますのでこれで問題ありません。

### デバッグ実行
デバッグ実行は、「テンプレートの実行」で述べた手順と同じです。成功するとボード上のLEDが点滅するはずです。

# 次回は
長くなりましたので今回はここまでとします。
次回はFSBLからセキュアアプリケーションを内蔵SRAM上でデバッグ実行するまでを説明します。

[第2回目 セキュアアプリ実行](https://qiita.com/y_toyoyama/items/107f62d694e97022000b)