Zenn
🔎

Arduino UNO R4 Minima 用のブートローダーのソースコードを読む ( アプリケーション起動編 )

2024/12/19に公開

1. はじめに

前回の記事では、Arduino UNO R4 Minima (以下、Minima) 用ブートローダーのビルド手順の一例を記載しました。今回の記事は、このブートローダーがアプリケーション (スケッチ) を起動するまでの流れについて確認したときのメモです。

2. ソースコードを読む前に

2.1. makeログの作成

今回の記事は、前回の記事で作成したビルド環境が手元にあると読みやすいかと思います。また、どのファイルをコンパイルしたのかを把握しやすくするために、下記コマンドによってブートローダーの再ビルドをおこない、makeのログを残すと良いかもしれません。

cd ~/arduino-r4-bootloader/arduino-renesas-bootloader/
rm -rf ./_build
TINYUSB_ROOT=$PWD/../tinyusb make -f Makefile.minima --debug=v --print-data-base >& build.log

2.2. ブートローダー自体の起動について

ブートローダーのソースコードを読む前に、マイコンが内蔵フラッシュに書き込まれたプログラム (今回はブートローダー) を起動する流れについて確認します。
Arduino UNO R4 には、ルネサス エレクトロニクス社の RA4M1 MCU グループに属するマイコン「R7FA4M1AB3CFM#AA0」が搭載されています。このマイコンは Cortex-M4 コアを採用し、256 kB の内蔵フラッシュメモリを備えています[1]
このマイコンには、大きく分けて2種類の起動モードがあります。ひとつは内蔵フラッシュに書き込まれたプログラムを起動する「シングルチップモード」、もうひとつは内蔵フラッシュのプログラムを書き換える「SCI/USBブートモード」です。[2]。ブートローダーの起動では「シングルチップモード」が使用されます。一方の「SCI/USBブートモード」ですが、これは前回の記事でブートローダーを書き込んだ際に使用しました。

シングルチップモードで起動するプログラムは、Cortex-M4 コアが起動できる構造で作成する必要があります。Cortex-M4 は Armv7E-M アーキテクチャですが、この場合、プログラムのイメージにはその開始アドレス (今回の場合は内蔵フラッシュの先頭である 0000 0000h [3]) にベクタテーブルを配置する必要があります。

ベクタテーブルには以下の情報が格納されています[4] :

  • 先頭の4バイト: 初期スタックポインタ
  • 次の4バイト : 初期プログラムカウンタ (リセットベクタ)

Armv7E-M アーキテクチャでは、リセット時の処理の中で下記の操作が行われます[5] :

  1. ベクタテーブルから初期スタックポインタを読み取り、その値をメインスタックポインタ (MSP) に設定する。
  2. ベクタテーブルからリセットベクタを読み取り、その値をプログラムカウンタ (PC) に設定する。

3. リンカスクリプト

前述の通り、シングルチップモードで起動するプログラムは、今回のケースではベクタテーブルを内蔵フラッシュの先頭に配置する必要があります。ベクタテーブルだけでなく、変数や関数を特定の場所 (アドレス) に配置する処理はリンク処理で行われ、通常はリンカスクリプトを使用します。そのため、まずリンカスクリプトを確認し、ベクタテーブルがどのように配置されているかを調べます。

その前に、リンカスクリプトについて簡単に記述します。C言語のソースコードをコンパイルすると、プログラムは例えば以下のようなセクションに分類されます:

  • .text セクション:関数やプログラムの実行コード。
  • .data セクション:初期値が設定されたグローバル変数や静的変数。
  • .bss セクション:初期値が設定されていないグローバル変数や静的変数。
  • .rodata セクション:定数や読み取り専用のデータ。

また、特定のデータを独自のセクションに分類することも可能です。例として、以下のコードを GCC でコンパイルすると、app_ver という定数が .app_ver というセクションに分類されます:

const uint32_t app_ver __attribute__((section(".app_ver"))) = 0x00010000;

これらのセクションがメモリ上のどの位置に配置されるかは、リンク時にリンカが決定します。その際に使用されるのがリンカスクリプトです。リンカスクリプトは、各セクションを具体的にメモリのどこに配置するかを定義します。

前回の記事で作成したビルド環境では、リンカスクリプトは下記の場所にあります。

~/arduino-r4-bootloader/tinyusb/hw/bsp/ra/linker/gcc/fsp.ld
~/arduino-r4-bootloader/tinyusb/hw/bsp/ra/linker/gcc/ra4m1.ld
(以降、パスの先頭部分「~/arduino-r4-bootloader/」は省略します)

fsp.ld では、FLASH_STARTFLASH_LENGTH といった定数を利用して、メモリ領域 (例えば FLASHRAM など) の配置を抽象的に指定しています。一方、ra4m1.ld ではこれらの定数に具体的な値を割り当てています。たとえば、FLASH_START = 0x00000000FLASH_LENGTH = 0x40000 という設定です。

リンカスクリプトでは、MEMORY ブロックでプログラムが使用するメモリ領域を定義します。

https://github.com/hathach/tinyusb/blob/0.17.0/hw/bsp/ra/linker/gcc/fsp.ld#L71-L90

内蔵フラッシュはFLASHとして定義しています。ORIGINは開始アドレス、LENGTHはメモリのサイズ (ここではバイト単位) です。ORIGIN = FLASH_ORIGIN + NS_IMAGE_OFFSETLENGTH = LIMITED_FLASH_LENGTHとなっていますが、今回ビルドしたブートローダーではORIGIN = 0LENGTH = 0x40000となります。

ここから下に読み進めていくと、SECTIONS ブロックが出てきます。このブロック内で、.textセクションをFLASHの先頭に配置する設定が記述されています。

https://github.com/hathach/tinyusb/blob/0.17.0/hw/bsp/ra/linker/gcc/fsp.ld#L168-L232

さらに、この.textセクションの先頭にKEEP(*(.fixed_vector*))KEEP(*(.application_vector*))といった記述があります。この*はワイルドカードで、一番目の*は任意のファイル名 (例えばstartup.cをコンパイルしてできたstartup.o) を表し、二つ目は任意の文字列を表します。もし、startup.oの中に.fixed_vector123というセクションに分類されたデータがある場合、そのデータはKEEP(*(.fixed_vector*))の場所に保持されます。

ここでベクタテーブルの構造を確認します。ベクタテーブルは、Renesas のマニュアルに記載されています[6] 。今回のソースコードでは、表中の例外番号が0-15 (発生元が Arm) であるベクタテーブルと、16番以降のベクタテーブルを別々に定義しています。これらはそれぞれ、.fixed_vectorと.application_vectorに配置されています。初期プログラムカウンタであるリセットベクタはベクタテーブルの先頭から2番目 (例外番号1) に登録されます。そのため、次は.fixed_vectorセクションに配置しているベクタテーブルの定義を探します。

4. ベクタテーブル

.fixed_vectorに配置するベクタテーブルは下記の場所で定義されています。

tinyusb/hw/mcu/renesas/fsp/ra/fsp/src/bsp/cmsis/Device/RENESAS/Source/startup.c

https://github.com/renesas/fsp/blob/d52e5a6a59b7c638da860c2bb309b6e78e752ff8/ra/fsp/src/bsp/cmsis/Device/RENESAS/Source/startup.c#L129-L149

BSP_PLACE_IN_SECTION(BSP_SECTION_FIXED_VECTORS)__Vector.fixed_vectorに配置しています。この配列の先頭から二番目に登録されたReset_Handlerがリセットベクタです。なお、これらのマクロの定義はここにあります。

tinyusb/hw/mcu/renesas/fsp/ra/fsp/src/bsp/mcu/all/bsp_compiler_support.h

https://github.com/renesas/fsp/blob/d52e5a6a59b7c638da860c2bb309b6e78e752ff8/ra/fsp/src/bsp/mcu/all/bsp_compiler_support.h#L73-L85

5. Reset_Handler

Reset_Handlerもstartup.c内に定義があります。

https://github.com/renesas/fsp/blob/d52e5a6a59b7c638da860c2bb309b6e78e752ff8/ra/fsp/src/bsp/cmsis/Device/RENESAS/Source/startup.c#L61-L73

6. SystemInit

SystemInit関数は、システムが正しく動作するための初期設定を行います。具体的には、.bss や .data セクションの変数初期化、クロック設定、MPU(メモリ保護ユニット)の設定、FPU(浮動小数点演算ユニット)の有効化などが含まれます。ただ、これらの詳細はブートローダーがアプリケーションを起動する流れを確認した後でも問題ないかと思います。そのため、SystemInit関数内の処理は別の記事に記述し、本記事では割愛いたします。

7. main

main関数は arduino-renesas-bootloader のソースコードで定義されています。

arduino-renesas-bootloader/src/main.c

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L177-L208

7.1. board_init

まず、179行目のboard_init関数ですが、この定義は tinyusb に戻り下記の場所にあります。

tinyusb/hw/bsp/ra/family.c

https://github.com/hathach/tinyusb/blob/0.17.0/hw/bsp/ra/family.c#L100-L131

__enable_irq()による割り込みの有効化とR_IOPORT_Open(&port_ctrl, &family_pin_cfg);でピンの機能設定を行っています。family_pin_cfgは board.h で定義されています。

tinyusb/hw/bsp/ra/linker/gcc/board.h

https://github.com/hathach/tinyusb/blob/0.17.0/hw/bsp/ra/boards/uno_r4/board.h#L34-L47

41行目は、Minima ではシルクでLと書かれた LED 用の設定です。43-45行目は USB のピン設定となります。42行目では D12 を入力ピンに設定してますが、このブートローダーでは使用していないようです。

board_init関数に戻ります。定数TRACE_ETMは未定義のため108-116行目はコードから除外されます。
また、定数CFG_TUSB_OSはarduino-renesas-bootloader/src/tusb_config.hでOPT_OS_NONEとして定義されています。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/tusb_config.h#L59

そのため、board_init関数の残りのコードは、127行目のSysTick_Config関数と、130行目のboard_led_write関数の実行処理となります。後者は LED の消灯処理です。前者のSysTick_Config関数は tinyusb/lib/CMSIS_5/CMSIS/Core/Include/core_cm4.h にあります。

https://github.com/ARM-software/CMSIS_5/blob/20285262657d1b482d132d20d755c8c330d55c1f/CMSIS/Core/Include/core_cm4.h#L2022-L2036

SysTickについてはRenesasおよびArmのマニュアルに記載されています[7],[8]

CLKSOURCEビットを1としているため、クロックソースはprocessor clock (ICLK) が指定されています。ICLK の動作周波数の値は、SystemInit関数内でSystemCoreClock変数に格納されています。
SysTick->LOAD (SYST_RVRレジスタのRELOADフィールド) に(SystemCoreClock / 1000) - 1を設定することで、SysTick 割り込みの周期を1ミリ秒に設定しています [9] 。なお、SysTick 割り込みハンドラは下記の場所で定義されています。

tinyusb/hw/bsp/ra/family.c

https://github.com/hathach/tinyusb/blob/0.17.0/hw/bsp/ra/family.c#L171-L181

1ミリ秒ごとに変数system_ticksをカウントアップしています。この値はboard_millis関数で取得できます。このあと、500ミリ秒待機する処理が出てくるのですが、そこでこの関数が使われています。

7.2. ブートローダーモードについて

main関数に戻ります。board_init関数の実行後、ブートローダーモードに入るか、アプリケーションを起動するかを選択する分岐処理が行われます。ブートローダーモードは、USB 通信ができなくなるようなアプリケーションを書き込んでしまった場合に、システムを復旧する際に役立ちます。このモードは Minima の場合、電源投入後にリセットボタンをダブルタップすることで起動できます[10]。このモードにすることで、アプリケーションを起動せずにプログラムを書き換えることができます。なお、本記事では少し主題を広げ、このブートローダーモードの起動手順についても触れたいと思います。

まず、下記のif文を確認します。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L181-L185

このBOOT_DOUBLE_TAP_DATAの定義は下記のようになっています。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L118

このVBTBKRレジスタはバックアップレジスタで、VCC 端子または VBATT 端子から電源が供給されている限り、リセットボタンを押してもデータは保持されます[11] [12] [13]
このブートローダーでは、バックアップレジスタの値を読みブートローダーモードに入るかを判断します。

ブートローダーモードの処理はmain関数内のbootloaderラベル以降に実装されています。このif文内に入るとbootloaderラベルに飛んでブートローダーモードに入りますが、電源投入時はバックアップレジスタにマジック値が書かれていないため、この条件には入りません。

次のif文を確認します。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L187-L189

if文の条件式に書かれているR_SYSTEM->RSTSR0_b.PORF (パワーオンリセット検出フラグ) は、パワーオンリセット時 (リセットボタンを押さずに電源を投入したとき) にセットされます[14]
このフラグは、RES端子リセット (リセットボタンを押したとき) によって値がクリアされます[15] [16] [17]

if文の条件式は!R_SYSTEM->RSTSR0_b.PORFですので、パワーオンリセット検出フラグがクリアされている場合 (リセットボタンを押してブートローダーを起動したとき) に成立します。このif文に入るとバックアップレジスタにマジック値を書き込みます。なお、バックアップレジスタはプロテクトレジスタによって書き込みの許可・禁止を切り替えられるため[18]、バックアップレジスタへの書き込み処理の前後でプロテクトレジスタの操作を行っています。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L447-L455

次につづくmain.cの190-195行目のコードは Minima の場合は除外されます[19]。そのため、196行目以降を確認します。

500ミリ秒間待機したあとにバックアップレジスタの値を0クリアする処理があります。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L196-L199

待機中にリセットボタンを押すとバックアップレジスタのデータは保持したままブートローダーが再起動されます。このとき、バックアップレジスタにマジック値がかかれていると、182行目のif文内の処理に入り、ブートローダーモードに入ります。

電源投入後にリセットボタンをダブルタップしたときの動作を以下にまとめます:

  1. 電源を投入してブートローダーを起動したときは、バックアップレジスタにマジック値は書かれていなため、182行目のif文には入らない。また、パワーオンリセット検出フラグがセットされているため、187行目のif文にも入らない。
  2. リセットボタンを押してブートローダーを再起動すると、パワーオンリセット検出フラグがクリアされるため、187行目のif文に入りバックアップレジスタにマジック値を書き込む。
  3. 後続の500ミリ秒待機処理中に再びリセットボタンを押すと、バックアップレジスタにマジック値が書かれた状態でブートローダーが再起動するため、182行目のif文に入りブートローダーモードに入る。

500ミリ秒待機中にリセットボタンを押さない場合、バックアップレジスタの値をゼロクリアした後、アプリケーションの起動処理に移ります。

なお、このブートローダーモードはリセットボタンのダブルタップ以外の方法でも起動可能です。このモードは、Arduino IDE でスケッチ (アプリケーション) を書き換える際にも利用されています。具体的には、Arduino IDE でスケッチの書き込みを実行すると、USB通信経由で要求を受け取ったアプリケーションがバックアップレジスタにマジック値を書き込み、その後再起動してブートローダーモードを起動します。

7.3. アプリケーションイメージのチェック

アプリケーションの起動処理を行う前に、アプリケーションイメージの構造をチェックする処理があります。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L201-L208

アプリケーションプログラムは、内蔵フラッシュの先頭からSKETCH_FLASH_OFFSETバイト分離れた位置以降に書き込まれます。この値は下記の場所で定義されています。

arduino-renesas-bootloader/src/flash.h

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/flash.h#L1-L11

今回はBSP_FEATURE_FLASH_LP_VERSIONは3である (0ではない) ため[20]SKETCH_FLASH_OFFSETは7行目か9行目の値となります。また、DFU_LOADERはMakefile.minimaで-DDFU_LOADERとしてCFLAGSに追加していますが、BOSSA_LOADERについては未定義です。そのため、SKETCH_FLASH_OFFSETの値は9行目の(16 * 1024) = 0x4000になります。

アプリケーションプログラムのイメージも、ブートローダーと同様にイメージの先頭にベクタテーブルを配置するように作成されています。実際に、Blink を Minima 向けにビルドした際に生成された map ファイルを確認したところ、下図の通りでした。

そのため、イメージの先頭4バイトには、アプリケーションプログラムの初期スタックポインタが格納されています。main.c の201行目は、この初期スタックポインタの値を簡単にチェックする処理かと思います。具体的には、スタックポインタが内蔵 SRAM 内に配置されていることを確認しているのだと思います。RA4M1 グループの場合、内蔵 SRAM はアドレス範囲0x20000000から0x20008000に割り当てられています[21]。そのため、SRAM 上のデータのアドレスに0xFF000000でアンドをとると0x20000000になります。
この条件式が成立する場合は、アプリケーションイメージの先頭にベクタテーブルが正しく配置されていると判断して、アプリケーションの起動処理であるboot5関数の実行に進みます。成立しない場合は、正常なアプリケーションが書き込まれていないと判断し、ブートローダーモードに移行するようにしているのだと思います。

7.4. アプリケーションの起動

最後にboot5関数の内容を確認します。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L85-L113

まずR_BSP_MODULE_STOPマクロによって、USBFSに対してモジュールストップを実行しています。

tinyusb/hw/mcu/renesas/fsp/ra/fsp/src/bsp/mcu/all/bsp_module_stop.h

https://github.com/renesas/fsp/blob/d52e5a6a59b7c638da860c2bb309b6e78e752ff8/ra/fsp/src/bsp/mcu/all/bsp_module_stop.h#L58-L68
https://github.com/renesas/fsp/blob/d52e5a6a59b7c638da860c2bb309b6e78e752ff8/ra/fsp/src/bsp/mcu/all/bsp_module_stop.h#L134-L137

ただ、USBFSはリセット時はモジュールストップ状態であり[22]、ここまでの処理のながれではモジュール状態を解除する処理は見当たりませんでした。もしかするとこの処理は保険的な意味合いが強いかもしれません[23]。また USBFS 以外にも USBHS についてもモジュールストップ処理が実行されていますが、RA4M1 シリーズのマイコンには USBHS は非搭載です。そのため MSTPCRB レジスタの対応フィールドは予約扱いとなっています。ただ、この予約フィールドに1を書き込むことは問題ないようです[24]

次の処理を確認します。ここでは SystemInit関数内で設定した MPU によるスタックポインタの監視処理を無効化しています。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L92-L98

Minimaで使用しているマイコンには TrustZone は非搭載のため、無効化処理は96行目で行われます。R_MPU_SPMONは下記のヘッダに定義されています。

tinyusb/hw/mcu/renesas/fsp/ra/fsp/src/bsp/cmsis/Device/RENESAS/Include/R7FA4M1AB.h
https://github.com/renesas/fsp/blob/d52e5a6a59b7c638da860c2bb309b6e78e752ff8/ra/fsp/src/bsp/cmsis/Device/RENESAS/Include/R7FA4M1AB.h#L7115-L7126

最後の処理を確認します。

https://github.com/arduino/arduino-renesas-bootloader/blob/8898c7b7db3ac0ec86f4b69688df45de71bf007f/src/main.c#L99-L113

__disable_irq() によって割り込みを禁止した後、__DSB()__ISB() がこの順番で実行されています。__DSB() は、この命令より前に行われたメモリやレジスタへの書き込み操作が完了するまで待機する処理です[25]。一方、__ISB() はプロセッサのパイプラインをフラッシュする命令です[26]
割り込み禁止後に、Systick割り込みの無効化とベクタテーブルの変更とアプリケーションの起動処理が続くため、ブートローダー側での処理の影響を極力なくした状態でアプリケーションの起動処理を行う意図で__DSB()__ISB() が記述されているのかもしれません。

Systick割り込みの無効化を行った後は、参照するベクタテーブルをアプリケーション側のベクタテーブルに変更する処理が続きます。参照するベクタテーブルの変更は、VTOR レジスタに設定することで行えます[27]
アプリケーションのベクタテーブルはイメージの先頭アドレス (SKETCH_FLASH_OFFSET) に配置されているため、VTOR にこのアドレスを登録しています。そして、アプリケーション側のベクタテーブルにあるスタックポインタの初期値をロードして、メインスタックポインタに設定します。最後に、ベクタテーブルの先頭から4バイト離れた場所に格納されているリセットベクタへのアドレスをロードし、戻り値引数なしの関数として実行することでアプリケーションを起動しています。
なお、アーキテクチャは異なりますが、TrustZone を搭載した Armv8-M の資料によると、VTOR (ベクタテーブルオフセットレジスタ) の値を変更した後に、__DSB()__ISB() を実行することを推奨しているようです[28]。新しいベクタテーブルが VTOR に書き込まれた状態でアプリケーションを起動することを保証したい場合は、VTOR 変更後にも __DSB() と __ISB() を記述しても良いのかもしれません。

脚注
  1. Arduino "Arduino® UNO R4 Minima Product Reference Manual SKU: ABX00080", p1, "Description" ↩︎

  2. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.92, "3. 動作モード" ↩︎

  3. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.94, "図 4.1 メモリマップ" ↩︎

  4. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.280, "表13.3 割り込みベクタテーブル" ↩︎

  5. Arm "ARMv7-M Architecture Reference Manual Version: E.e", p.B1-530, "B1.5.5 Reset behavior" ↩︎

  6. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.280, "表13.3 割り込みベクタテーブル" ↩︎

  7. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.87, "2.9 SysTickシステムタイマ" ↩︎

  8. Arm "ARMv7-M Architecture Reference Manual Version: E.e", p.B3-621, "B3.3.3 SysTick Control and Status Register, SYST_CSR", ソースコード内のSysTick->CTRLSYST_CSRに対応します ↩︎

  9. 1秒間に SystemCoreClock回のクロックが発生するため、SystemCoreClock / 1000回のカウントダウンに要する時間は1ミリ秒。 ↩︎

  10. Arduino "Arduino® UNO R4 Minima Product Reference Manual SKU: ABX00080", p.17, "12.5 Board Recovery" ↩︎

  11. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.237, "11.1.5 バックアップレジスタ" ↩︎

  12. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.243, "11.2.6 VBATT バックアップレジスタ (VBTBKRn) (n = 0 ~ 511)" ↩︎

  13. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.256, "11.3.4 VBATT バックアップレジスタの使用法" ↩︎

  14. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.105, "5.3.2 パワーオンリセット" ↩︎

  15. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.95, "表 5.1 リセットの名称と要因" ↩︎

  16. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.96, "表 5.2 リセット要因ごとの初期化対象リセット検出フラグ" ↩︎

  17. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.99, "5.2.1 リセットステータスレジスタ 0(RSTSR0)" ↩︎

  18. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.262, "12.2.1 プロテクトレジスタ(PRCR)" ↩︎

  19. RENESAS_CORTEX_M23は未定義です。またTURN_OFF_CHARGER_LEDはarduino-renesas-bootloader/src/flash.hよりBSP_FEATURE_FLASH_HP_VERSIONが0以外のときに定義されますが、この定数はtinyusb/hw/mcu/renesas/fsp/ra/fsp/src/bsp/mcu/ra4m1/bsp_feature.hで0となっています。 ↩︎

  20. BSP_FEATURE_FLASH_LP_VERSIONの定義は以下の場所にあります:
    tinyusb/hw/mcu/renesas/fsp/ra/fsp/src/bsp/mcu/ra4m1/bsp_feature.h ↩︎

  21. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.94, "図 4.1 メモリマップ" ↩︎

  22. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.821, "27.4.1 モジュールストップ状態の設定" ↩︎

  23. ソースコードを見ると、USBFS のモジュールストップ状態は、ブートローダーモード内で実行されるtud_init関数内のdcd_init関数を通じて、rusb2_module_start関数で解除されています。
    tud_init: tinyusb/src/device/usbd.c
    dcd_init: tinyusb/src/portable/renesas/rusb2/dcd_rusb2.c
    rusb2_module_start: tinyusb/src/portable/renesas/rusb2/rusb2_ra.h
    そのため、ブートローダーモードに入った後にboot5関数を呼ぶ場合は、このモジュールストップ処理が必要になると思います。実際、main.c を見ると、以前はブートローダーモード中にboot5関数を実行することを検討していた形跡がありました。ただ、現在はコメントアウトされています。 ↩︎

  24. Renesas Electronics Corporation, "Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 Rev.1.10", 2023.09, p.201, "10.2.3 モジュールストップコントロールレジスタ B(MSTPCRB)" ↩︎

  25. Arm "ARMv7-M Architecture Reference Manual Version: E.e", p.A3-94, "Data Synchronization Barrier (DSB)" ↩︎

  26. Arm "ARMv7-M Architecture Reference Manual Version: E.e", p.A3-95, "Instruction Synchronization Barrier (ISB)" ↩︎

  27. Arm "ARMv7-M Architecture Reference Manual Version: E.e", p.B1-525, "B1.5.3 The vector table" ↩︎

  28. Arm "Armv8-M Memory Model and Memory Protection User Guide Version 1.1", p.17, "2.3.4 When do you need a DSB followed by an ISB?" ↩︎

Discussion

ログインするとコメントできます