STM32CubeIDEでブートローダ＋アプリをデバッグする

# はじめに
今回、STMicroelectronics社員の方による、ブートローダ＋アプリ構成でデバッグする記事が見つかりましたので、情報保全と日本語化、それと若干の補足追加を目的としてまとめます。
記事：[ethanhuanginst/STM32CubeIDE-Workshop-2019](https://github.com/ethanhuanginst/STM32CubeIDE-Workshop-2019/tree/master/hands-on/09_BOOT-APP)

# 開発環境
OS:Windows 10 Pro 2004
ツール本体：STM32CubeIDE Version 1.3.0 ([ダウンロード](https://www.st.com/ja/development-tools/stm32cubeide.html))
追加プラグイン：Pleiades 日本語化プラグイン ([参考](https://qiita.com/forest1/items/30a0fe08dd256a247ff0))
ターゲットボード：Nucleo-F103RB

# APP(ターゲットアプリ)作成
## プロジェクト作成
STM32CubeIDEにSTM32CubeMXが統合されているのでこれを使用するのがお勧めです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/49c44636-405d-6bf9-0b76-c00e2a989d7e.png)

ターゲットボードを選択しプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/c6487d9b-7048-9cd5-e0c9-14a4892dcc36.png)

アプリとして必要な設定を行います。
この時、以下図のように Serial Wire などの使用するデバッガを設定しておきます。(しておかないと後でデバッガが繋がらなくなります)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/54edaa93-cd05-ac0a-546b-0547d9bf3ee8.png)
ポート設定は後からでもAPP.iocを開いて再編集出来ます。

## main関数名変更
BOOTとシンボル名が被るとデバッグに支障が有るので変更します。

main.c のユーザコードブロックに以下を追加します。(以下同様)
元記事にはapp_mainに変更する旨記載が有りますが、APP.ioc再編集時にmainに戻ってしまうのでマクロで置き換えます。

```
/* USER CODE BEGIN 0 */
#define main app_main
/* USER CODE END 0 */
```

スタートアップファイル(startup_stm32f103rbtx.s)も併せて変更します。

```
bl __libc_init_array
bl  app_main
bx  lr 
```

## メモリマップ変更
ブートローダに上書きしないように、APPをロードするFLASH領域を設定します。

リンカスクリプト(STM32F103RBTX_FLASH.ldなど)のMEMORY定義

```
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8002000,   LENGTH = 120K
}
```

ここでは8KB(0x2000)ずらしています。
設定するアドレスはフラッシュ書き換えのページ境界にします。
[プログラミング マニュアル](https://www.stmcu.jp/design/document/programming_manual/)

ベクトルテーブルの配置アドレスも併せて変更します。
system_stm32f1xx.c にて 0x8000000 からのオフセットを設定します。

```
#define VECT_TAB_OFFSET  0x2000
```

## 動作確認
まだブートローダは書き込んでいませんが、このままデバッグ実行出来ます。

# BOOT(ブートローダ)作成
## プロジェクト作成
APPと同じです。

## main関数名変更
APPと同様に以下を設定します。

main.c

```
/* USER CODE BEGIN 0 */
#define main bl_main
/* USER CODE END 0 */
```

スタートアップファイル(startup_stm32f103rbtx.s)

```
bl __libc_init_array
bl  bl_main
bx  lr 
```

## APP(ターゲットアプリ)起動関数追加
BOOTのmain.cに以下を追加します。
APPのベクタ領域からリセットハンドラとスタックポインタのアドレスを読み取ってAPPを起動する仕組みです。

```
/* USER CODE BEGIN 0 */
typedef void(*pFunction)(void);
pFunction JumpToApplication;
#define APP_ADDRESS	0x08002000
#define APP_STACK	(APP_ADDRESS + 0)
#define APP_RESET_HANDLER (APP_ADDRESS + 4)

void JumpToAPP(void)
{
    uint32_t JumpAddress = *(__IO uint32_t*)APP_RESET_HANDLER;
    JumpToApplication = (pFunction)JumpAddress;
    __set_MSP(*(__IO uint32_t*)APP_STACK);
    JumpToApplication();
}
/* USER CODE END 0 */
```

## APP起動
必要なタイミングで JumpToAPP(); を呼び出します。

```
JumpToAPP();
```

## 動作確認
ここまでで、デバッガを動作させずに電源OFF->ONで、BOOTからAPPが呼び出されて動作するはずです。

# BOOT+APPをデバッグする
## BOOTプロジェクトからデバッガ起動する場合
### デバッグ設定
プロジェクトエクスプローラでBOOTを選択した状態から、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/4119a6f7-8532-2681-04b1-a7fe772c7f87.png)

メニュー[実行]-[デバッグの構成] を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/52cbcdd1-13bd-6ac5-cd59-625d85dab2c7.png)

[STM32 Cortex-M C/C++ Application]をダブルクリック(もしくは新規作成)します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/a243a97f-4b35-93db-4333-0b4393167d3c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/c9087cc3-3f79-b403-126e-e7daea4b3574.png)
[Set breakpoint at:] を main から bl_main に変更します。
[Run Commands] には以下を記載します。

```
add-symbol-file ../APP/Debug/APP.elf 0x0800210c
b app_main
```

bはブレークポイントを設定しています。

add-symbol-fileで設定するAPPの値(0x0800210c)は、Build Analyzerから取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/d7414d33-f56c-84b7-a5f0-c85ef0dd4c19.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/36d57462-fea4-4205-3f8e-7ab1a943055b.png)

### デバッグ実行
ツールバーの虫アイコンをドロップダウンして、先ほど作成した「BOOTデバッグ」を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/6913a36c-ad80-25b2-f5f5-075901f704be.png)
実行すると、BOOTのmainとAPPのmainで自動的に止まります。

## APPプロジェクトからデバッグ
### デバッグ設定
BOOTと同様にAPPの設定を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/94041b29-517f-ef84-b751-280dbc1f70db.png)
[Set breakpoint at:] を main から app_main に変更します。
[Run Commands] には以下を設定します。

```
add-symbol-file ../BOOT/Debug/BOOT.elf 0x0800010c
b bl_main

set *0xE000ED08 = 0x08000000
set $sp = *(unsigned int*)0x08000000 
set $pc = *(unsigned int*)0x08000004
```

add-symbol-fileのアドレス値はBOOTの .text 値を調べて設定します。

setについては、デバッグ開始時のベクタテーブル、スタックポインタ($sp)、プログラムカウンタ($pc)を設定しています。
これが無いとBOOTが無視されて直接APPのリセットハンドラが呼び出されてしまいます。

### デバッグ実行
BOOT同様に、虫アイコンから「APPデバッグ」を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120192/2f7be0b8-82c1-9ef0-084c-e1bfab4c5e21.png)
実行すると、BOOTのmainとAPPのmainで自動的に止まります。

# 参考記事
[ethanhuanginst/STM32CubeIDE-Workshop-2019](https://github.com/ethanhuanginst/STM32CubeIDE-Workshop-2019/tree/master/hands-on/09_BOOT-APP)