commit 39ee3e691c1fb6d849c0f9ca6a7b3a5a1c2f2c95
parent 46e08a7fceb7b64373fe34e5fe25fab6deb653a1
Author: Matsuda Kenji <info@mtkn.jp>
Date: Fri, 21 Apr 2023 19:12:08 +0900
update
Diffstat:
3 files changed, 171 insertions(+), 6 deletions(-)
diff --git a/man/draft/rp2040_1.html b/man/draft/rp2040_1.html
@@ -43,8 +43,8 @@ RP2040は電源を入れるといくつかの段階(ここでは関係ないの
に変換することが必要である。
</p>
<pre>\
-source code ---------> object ------> elf ------> crc32 ----> uf2
- compile link crc32 uf2
+source code ---------> object ------> elf -------->----->---> uf2
+ compile link objcopy crc32 uf2
</pre>
<h2>CRC32(巡回冗長検査)</h2>
@@ -451,6 +451,112 @@ defer:
下位バイトから順に書き込む関数である。バイトオーダーとかややこしそうなので\
作っておいたけど必要なのかな?あと名前が気に入らない。\
</p>
+<p>
+CRC32のチェックサムが書き込まれたバイナリファイルを、このプログラムでUF2に\
+変換し、生成されたファイルをUSBストレージとして接続したRP2040にコピーすれば\
+フラッシュROMに書き込まれる。
+</p>
+
+<h2>Flash Second Stage</h2>
+<p>
+RP2040に電源を投入し、CRC32のチェックが通った後、フラッシュROMからコピー\
+されたプログラムの先頭から実行が開始される。このコピーされた部分で\
+その後の動作に必要な各種の設定を行うことになる。\
+RP2040のデータシートには、この部分でフラッシュROMとSSIコントローラのXIP\
+を設定するようにと書かれている。\
+XIPはExecute in Placeの略で、フラッシュROMの内容をCPUから\
+直接実行するものである。SSIはSynchronous Serial Interfaceの略で、\
+周辺機器と情報のやりとりをする通信方式である。\
+RP2040はチップに内蔵されたこのSSIコントローラを通して、\
+外部のフラッシュROMと通信しているのだが、このコントローラを適切に設定すれば\
+フラッシュROMの内容がCPUから直接アクセスできる<code>0x10000000</code>番地以降\
+にマップされる。これによりフラッシュROMから内部のSRAMにデータをコピーする\
+ことなく命令を実行できるので、速くて便利だという。
+</p>
+<p>
+しかしこのSSIコントローラはSynopsysという会社のDW_apb_ssiというIPを\
+使っているようで、データシートのSSIコントローラの章は多分Synopsysの\
+人が書いている。その他の章はRaspberry Pi財団の書いたブリティッシュイングリッシュ\
+だが、この部分だけ多分中国人の書いたいい加減な英語である。誤植も多い。\
+何日かかけて理解しようとしたが、あまりにも必要な情報が書かれていないので\
+よく分からん。不毛なので一旦諦めた。\
+</p>
+<p>
+RP2040には内部にもROMがあり、中にはバージョン情報や、電源を投入した時の動作、\
+その他便利な関数が書き込まれている。この関数のなかに外部のフラッシュROMと\
+SSIコントローラを設定するものも含まれているので今回はこれを利用した。\
+ただしこの方法だとフラッシュROMとの通信方式がStandard SPIのままなので少し\
+遅い。詳しくはデータシート<sup>[3]</sup>の2.3.8. 「Bootrom Contents」を参照。
+</p>
+<p>
+RP2040の内蔵ROMの<code>0x00000018</code>番地に関数を検索するための関数がある。\
+この関数に<code>0x00000014</code>番地の<code>rom_func_table</code>と、\
+各関数に割り当てられた二文字の文字列を渡せば、欲しい関数へのポインタが\
+返ってくる。なお、二文字の文字列はそれぞれASCIIコードで現し、二文字目を\
+8ビットシフトしたものと1文字目のORを取ったものを渡すことになっている。\
+今回欲しい関数はフラッシュROMをXIPに設定するもの\
+(<code>_flash_enter_cmd_xip()</code>)なので、<code>'C', 'X'</code>を渡す。\
+関数のポインタが返ってきたら、それを呼び出せばフラッシュROMとSSIはXIPモード\
+になる。
+</p>
+<pre><code>\
+ ldr r4, rom_base
+
+ ldrh r0, [r4, #0x14] // rom_func_table
+ ldr r1, =('C' | 'X' << 8) // _flash_enter_cmd_xip()
+ ldrh r2, [r4, #0x18] // rom_table_lookup
+ blx r2
+ blx r0
+/* ... */
+rom_base:
+ .word 0x00000000
+</code></pre>
+
+<p>
+XIPの設定が完了すれば、次はメインのプログラムを実行するための準備である。\
+エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブル\
+の設定である。初期スタックポインタとエントリーポイントはベクターテーブルの\
+<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている[要出展]。\
+また、ベクターテーブルはメインのプログラムの先頭に擱くおとにする。\
+メインのプログラムはFlash Second Stageが占有する256バイトの直後、\
+フラッシュROMの257バイト目から配置することにする。
+RP2040のベクターテーブルは<code>M0PLUS: VTOR(0xe0000000 + 0xed08)</code>という\
+レジスタに書き込むことで設定する。以上をまとめると以下のコードになる:
+</p>
+<pre><code>\
+ ldr r0, flash_main
+ ldr r1, m0plus_vtor
+ str r0, [r1, #0] // vector table
+ ldr r1, [r0, #4] // entry point
+ ldr r0, [r0, #0] // stack pointer
+ mov sp, r0
+ bx r1
+/* ... */
+flash_main:
+ .word 0x10000000 + 0x100
+m0plus_vtor:
+ .word 0xe0000000 + 0xed08
+</code></pre>
+
+<h2>メインのコード<h2>
+<p>
+メインのコードの最初には上で説明したベクターテーブルを配置する。\
+ここでは割り込みの処理は考えないので、初期スタックポインタと\
+エントリーポイントだけである。初期スタックポインタはSRAMの最後\
+(<code>0x20040000</code>)、エントリーポイントはエントリーポイントの\
+ラベルを用いて設定した。ただしこのCPUはThumbモードなので、\
+ラベルに<code>0x1</code>を足している[要説明]:
+</p>
+<pre><code>\
+.cpu cortex-m0plus
+.thumb
+
+ .section .vectors
+vectors:
+ .word 0x20040000 // initial SP
+ .word (reset+1)
+</code></pre>
+
<h2>参考</h2>
<ul>
diff --git a/pub/draft/rp2040_1.html b/pub/draft/rp2040_1.html
@@ -41,8 +41,8 @@ RP2040は電源を入れるといくつかの段階(ここでは関係ないの
<p>
以上のことから、プログラムを実行するためにはCRC32を計算し、UF2という形式に変換することが必要である。
</p>
-<pre>source code ---------> object ------> elf ------> crc32 ----> uf2
- compile link crc32 uf2
+<pre>source code ---------> object ------> elf -------->----->---> uf2
+ compile link objcopy crc32 uf2
</pre>
<h2>CRC32(巡回冗長検査)</h2>
@@ -403,6 +403,65 @@ defer:
}
</code></pre>
<p><code>fwrite32l()</code>関数は指定されたファイルに32ビットの整数を下位バイトから順に書き込む関数である。バイトオーダーとかややこしそうなので作っておいたけど必要なのかな?あと名前が気に入らない。</p>
+<p>
+CRC32のチェックサムが書き込まれたバイナリファイルを、このプログラムでUF2に変換し、生成されたファイルをUSBストレージとして接続したRP2040にコピーすればフラッシュROMに書き込まれる。
+</p>
+
+<h2>Flash Second Stage</h2>
+<p>
+RP2040に電源を投入し、CRC32のチェックが通った後、フラッシュROMからコピーされたプログラムの先頭から実行が開始される。このコピーされた部分でその後の動作に必要な各種の設定を行うことになる。RP2040のデータシートには、この部分でフラッシュROMとSSIコントローラのXIPを設定するようにと書かれている。XIPはExecute in Placeの略で、フラッシュROMの内容をCPUから直接実行するものである。SSIはSynchronous Serial Interfaceの略で、周辺機器と情報のやりとりをする通信方式である。RP2040はチップに内蔵されたこのSSIコントローラを通して、外部のフラッシュROMと通信しているのだが、このコントローラを適切に設定すればフラッシュROMの内容がCPUから直接アクセスできる<code>0x10000000</code>番地以降にマップされる。これによりフラッシュROMから内部のSRAMにデータをコピーすることなく命令を実行できるので、速くて便利だという。
+</p>
+<p>
+しかしこのSSIコントローラはSynopsysという会社のDW_apb_ssiというIPを使っているようで、データシートのSSIコントローラの章は多分Synopsysの人が書いている。その他の章はRaspberry Pi財団の書いたブリティッシュイングリッシュだが、この部分だけ多分中国人の書いたいい加減な英語である。誤植も多い。何日かかけて理解しようとしたが、あまりにも必要な情報が書かれていないのでよく分からん。不毛なので一旦諦めた。</p>
+<p>
+RP2040には内部にもROMがあり、中にはバージョン情報や、電源を投入した時の動作、その他便利な関数が書き込まれている。この関数のなかに外部のフラッシュROMとSSIコントローラを設定するものも含まれているので今回はこれを利用した。ただしこの方法だとフラッシュROMとの通信方式がStandard SPIのままなので少し遅い。詳しくはデータシート<sup>[3]</sup>の2.3.8. 「Bootrom Contents」を参照。
+</p>
+<p>
+RP2040の内蔵ROMの<code>0x00000018</code>番地に関数を検索するための関数がある。この関数に<code>0x00000014</code>番地の<code>rom_func_table</code>と、各関数に割り当てられた二文字の文字列を渡せば、欲しい関数へのポインタが返ってくる。なお、二文字の文字列はそれぞれASCIIコードで現し、二文字目を8ビットシフトしたものと1文字目のORを取ったものを渡すことになっている。今回欲しい関数はフラッシュROMをXIPに設定するもの(<code>_flash_enter_cmd_xip()</code>)なので、<code>'C', 'X'</code>を渡す。関数のポインタが返ってきたら、それを呼び出せばフラッシュROMとSSIはXIPモードになる。
+</p>
+<pre><code> ldr r4, rom_base
+
+ ldrh r0, [r4, #0x14] // rom_func_table
+ ldr r1, =('C' | 'X' << 8) // _flash_enter_cmd_xip()
+ ldrh r2, [r4, #0x18] // rom_table_lookup
+ blx r2
+ blx r0
+/* ... */
+rom_base:
+ .word 0x00000000
+</code></pre>
+
+<p>
+XIPの設定が完了すれば、次はメインのプログラムを実行するための準備である。エントリーポイントの指定、スタックポインタの初期値の設定、ベクターテーブルの設定である。初期スタックポインタとエントリーポイントはベクターテーブルの<code>0x0</code>バイト目と<code>0x4</code>バイト目に書くことになっている[要出展]。また、ベクターテーブルはメインのプログラムの先頭に擱くおとにする。メインのプログラムはFlash Second Stageが占有する256バイトの直後、フラッシュROMの257バイト目から配置することにする。
+RP2040のベクターテーブルは<code>M0PLUS: VTOR(0xe0000000 + 0xed08)</code>というレジスタに書き込むことで設定する。以上をまとめると以下のコードになる:
+</p>
+<pre><code> ldr r0, flash_main
+ ldr r1, m0plus_vtor
+ str r0, [r1, #0] // vector table
+ ldr r1, [r0, #4] // entry point
+ ldr r0, [r0, #0] // stack pointer
+ mov sp, r0
+ bx r1
+/* ... */
+flash_main:
+ .word 0x10000000 + 0x100
+m0plus_vtor:
+ .word 0xe0000000 + 0xed08
+</code></pre>
+
+<h2>メインのコード<h2>
+<p>
+メインのコードの最初には上で説明したベクターテーブルを配置する。ここでは割り込みの処理は考えないので、初期スタックポインタとエントリーポイントだけである。初期スタックポインタはSRAMの最後(<code>0x20040000</code>)、エントリーポイントはエントリーポイントのラベルを用いて設定した。ただしこのCPUはThumbモードなので、ラベルに<code>0x1</code>を足している[要説明]:
+</p>
+<pre><code>.cpu cortex-m0plus
+.thumb
+
+ .section .vectors
+vectors:
+ .word 0x20040000 // initial SP
+ .word (reset+1)
+</code></pre>
+
<h2>参考</h2>
<ul>
diff --git a/pub/rss.xml b/pub/rss.xml
@@ -5,8 +5,8 @@
<description>ウェブページの更新履歴</description>
<language>ja-jp</language>
<link>https://www.mtkn.jp</link>
-<lastBuildDate>Fri, 21 Apr 2023 14:55:46 +0900</lastBuildDate>
-<pubDate>Fri, 21 Apr 2023 14:55:46 +0900</pubDate>
+<lastBuildDate>Fri, 21 Apr 2023 19:11:58 +0900</lastBuildDate>
+<pubDate>Fri, 21 Apr 2023 19:11:58 +0900</pubDate>
<docs>https://www.rssboard.org/rss-specification</docs>
<item>
<title>Xlibで遊んでみる6</title>