www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | README

commit 5ae183464e9e5840264d16e791e6879d33c9aeeb
parent 46b7c7b43b255a2f20bf422d04beab549cdfd817
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Thu, 11 May 2023 12:06:01 +0900

update

Diffstat:
Mdata/weblog | 21+++++++++++++++++++++
Mman/computer/rp2040_2.html | 186++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mpub/computer/rp2040_2.html | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mpub/rss.xml | 104++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mpub/sitemap.xml | 2+-
5 files changed, 395 insertions(+), 16 deletions(-)

diff --git a/data/weblog b/data/weblog @@ -204,3 +204,24 @@ 1683644400 /computer/rp2040_2.html 1683644400 /computer/rp2040_2.html 1683644400 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html +1683730800 /computer/rp2040_2.html diff --git a/man/computer/rp2040_2.html b/man/computer/rp2040_2.html @@ -49,14 +49,186 @@ RP2040は電源を入れると、このリング発振回路を動作用のク <h2>UART</h2> -<h2>リング発振回路でUARTは動くんかな?<h2> +<h2>リング発振回路でUARTは動くんかな?</h2> <p>\ UARTの通信には正確なクロックが必要である。\ その為上では<code>clk_peri</code>として水晶発振子とPLLを用いた。\ -ところがpico-examplesのhello_uartのCのヲースでは水晶発振子を\ -設定していないように見える。\ -しかし実は水晶発振子もPLLも<code>main()</code>が呼ばれる前に\ -設定されているようだ。 +ところがpico-examplesのhello_uartでは<code>main()</code>関数で\ +水晶発振子を設定していない。そこでリング発振回路を用いてみたのだが、\ +どうもうまく通信できない。出力されている正確な周波数も分からないので\ +あきらめることにした。オシロスコープなんていうものは持っていない。\ +</p> + +<h3>pico-sdk</h3> +<p> +ところがどうも調べているとSDKを使った場合、\ +デフォルトではクロック周波数は125MHzになっているらしい。\ +どうやら水晶発振子もPLLも<code>main()</code>が呼ばれる前に\ +設定されているようである。\ +</p> +<p> +pico-examplesのサンプルプログラムはビルドすると自動で逆アセンブリした\ +ファイルを出力してくれる。これを見ると、最初の256バイトは前回説明した\ +boot2のコードで、その後ろにベクターテーブルが続く。\ +ベクターテーブルの最初は初期スタックポインタで、<code>0x20042000</code>\ +になっている。次はエントリーポイントで、<code>0x100001f7</code>である:\ +</p> +<pre><code>\ +10000100 &lt;__VECTOR_TABLE&gt;: +10000100: 20042000 .word 0x20042000 +10000104: 100001f7 .word 0x100001f7 +</code></pre> +<p> +Thumbモードなので実際のエントリーポイントは<code>1</code>引いた、\ +<code>0x100001f6</code>である。この場所ではまず自分のCPUIDを調べて、\ +<code>1</code>であれば待機状態に移行する。\ +RP2040はデュアルコアである。起動直後はCPUIDが<code>0</code>のコアだけで処理をして、\ +CPUIDが<code>1</code>のコアはプログラマが必要に応じて起動することになっている。\ +このためCPUIDが<code>1</code>のコアは起動してすぐに待機状態に入ることがデータシート\ +に書かれている。しかしこの処理はユーザーの書いたプログラムじゃなくて\ +内蔵ROMにある起動用プログラムが担当するみたいに書かれてるんやけど、\ +なんでSDKではユーザープログラムの一部として組み込んでるんかな? +</p> +<pre><code>\ +100001f6 &lt;_reset_handler&gt;: +100001f6: 481d ldr r0, [pc, #116] ; (1000026c &lt;hold_non_core0_in_bootrom+0xe&gt;) +100001f8: 6800 ldr r0, [r0, #0] +100001fa: 2800 cmp r0, #0 +100001fc: d12f bne.n 1000025e &lt;hold_non_core0_in_bootrom&gt; +</code></pre> +<p>\ +上のコードの最初の<code>ldr</code>は、<code>0xd0000000</code>\ +(M0PLUS: CPUIDレジスタ)をロードしている。\ +最後の飛び先<code>0x1000025e</code>はCPUIDが<code>1</code>のCPUを待機させる処理\ +である:\ +</p> +<pre><code>\ +1000025e &lt;hold_non_core0_in_bootrom&gt;: +1000025e: 4809 ldr r0, [pc, #36] ; (10000284 &lt;hold_non_core0_in_bootrom+0x26&gt;) +10000260: f001 fb9c bl 1000199c &lt;rom_func_lookup&gt; +10000264: 4700 bx r0 +10000266: 0000 .short 0x0000 +/* ... */ +10000284: 00005657 .word 0x00005657 +</code></pre> +<p>\ +内蔵フラッシュに書きこまれた関数を呼びだしている。呼びだしに使うコードは\ +<code>0x00005657</code>(<code>'W' | 'V' &lt;&lt; 8</code>)である。\ +データシートを見ると、この関数は<code>_wait_for_vector()</code>という名前で、\ +CPUIDが1のCPUを寝かしつけるのに使われると書いている。\ +この部分のソースコードをpico-sdkで探すと\ +<code>pico-sdk/src/rp2_common/pico_standard_link/crt0.S</code>\ +というのが見付かった:\ +</p> +<pre><code>\ +$ find pico-sdk/src -type f | xargs grep -l _reset_handler +pico-sdk/src/rp2_common/pico_standard_link/crt0.S +</code></pre> +<p>\ +このファイルによると: +</p> +<pre><code>\ + // Only core 0 should run the C runtime startup code; core 1 is normally + // sleeping in the bootrom at this point but check to be sure +</code></pre> +<p>\ +だそうである。やっぱり無駄やん。内蔵フラッシュのプログラムにバグがあっても\ +このコードのせいで見付かりにくくなってない?知らんけど。\ +</p> + +<p>\ +続いて<code>.data</code>領域と<code>.bss</code>領域のコピー、初期化のようである。\ +多分OSの本かなんかで習ったメモリマップの話:\ +</p> +<pre><code>\ +100001fe: a40d add r4, pc, #52 ; (adr r4, 10000234 &lt;data_cpy_table&gt;) +10000200: cc0e ldmia r4!, {r1, r2, r3} +10000202: 2900 cmp r1, #0 +10000204: d002 beq.n 1000020c &lt;_reset_handler+0x16&gt; +10000206: f000 f812 bl 1000022e &lt;data_cpy&gt; +1000020a: e7f9 b.n 10000200 &lt;_reset_handler+0xa&gt; +1000020c: 4918 ldr r1, [pc, #96] ; (10000270 &lt;hold_non_core0_in_bootrom+0x12&gt;) +1000020e: 4a19 ldr r2, [pc, #100] ; (10000274 &lt;hold_non_core0_in_bootrom+0x16&gt;) +10000210: 2000 movs r0, #0 +10000212: e000 b.n 10000216 &lt;bss_fill_test&gt; + +10000214 &lt;bss_fill_loop&gt;: +10000214: c101 stmia r1!, {r0} + +10000216 &lt;bss_fill_test&gt;: +10000216: 4291 cmp r1, r2 +10000218: d1fc bne.n 10000214 &lt;bss_fill_loop&gt; +</code></pre> + +<p>\ +最後にいろいろ呼びだす:\ +</p> +<pre><code>\ +1000021a &lt;platform_entry&gt;: +1000021a: 4917 ldr r1, [pc, #92] ; (10000278 &lt;hold_non_core0_in_bootrom+0x1a&gt;) +1000021c: 4788 blx r1 +1000021e: 4917 ldr r1, [pc, #92] ; (1000027c &lt;hold_non_core0_in_bootrom+0x1e&gt;) +10000220: 4788 blx r1 +10000222: 4917 ldr r1, [pc, #92] ; (10000280 &lt;hold_non_core0_in_bootrom+0x22&gt;) +10000224: 4788 blx r1 +10000226: be00 bkpt 0x0000 +10000228: e7fd b.n 10000226 &lt;platform_entry+0xc&gt; +/* ... */ +10000278: 10001819 .word 0x10001819 +1000027c: 100002dd .word 0x100002dd +10000280: 10001909 .word 0x10001909 +</code></pre> +<p>\ +一つめの<code>blx</code>は<code>0x10001818</code>(<code>runtime_init</code>)を、\ +二つめは<code>0x100002dc</code>(<code>main</code>)を、\ +最後のは<code>0x10001908</code>(<code>exit</code>)を、\ +それぞれ呼んでいる。\ +この<code>runtime_init</code>はアセンブリでは分かりにくいので\ +ソースコードを探してみると、以下のものが見付かった:\ +</p> +<pre><code>\ +$ find pico-sdk/src -type f | xargs grep -l runtime_init +pico-sdk/src/rp2_common/pico_runtime/runtime.c +pico-sdk/src/rp2_common/pico_standard_link/crt0.S +pico-sdk/src/common/pico_sync/include/pico/mutex.h +</code></pre> +<p>\ +最後の<code>mutex.h</code>は関係なさそう。\ +二つめの<code>crt0.S</code>は呼びだしてるだけ。\ +一つめの<code>runtime.c</code>が多分探しているものである。\ +これを見るとまず各種周辺機器を一度リセットし、リセット状態を解除している。\ +使わんやつも初期化してない?\ +その後<code>clocks_init()</code>を呼んでいる。\ +この関数は<code>pico-sdk/src/rp2_common/hardware_clocks/clocks.c</code>\ +で定義されている。これを見ると、<code>xosc_init()</code>を呼んで\ +水晶発振子を初期化した後、<code>clk_peri</code>を125MHzに設定している:\ +</p> +<pre><code> clock_configure(clk_peri, + 0, + CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, + 125 * MHZ, + 125 * MHZ); +</code></pre> +<p>\ +やっぱり水晶発振子じゃないとあかんのかな。\ +</p> + +<h2>CMake</h2> +<p>\ +上ではビルドしたバイナリを逆アッセンブルして読んだ。\ +わざわざこんなことをしなくてもMakefile読めばなにがどう\ +なって最終生成物に辿りつくのか分かればいいのだが、そうもいかない。\ +このSDKとpico-examplesにはビルドシステムとしてCMakeなるものが使われている。\ +これがどうも複雑でよく分からない。勉強する気にもならん。\ +上で見た<code>crt0.S</code>や<code>runtime.c</code>といったファイルも\ +<code>hello_uart</code>で本当に使われているものなのかもよく分からない。\ +こんな煩雑なものは本当に必要なのかな。無駄に複雑にしてるだけとちゃうんかな。\ +特に僕みたいに勉強用に使ってる人には、ソースコードの依存関係をもっと\ +分かりやすくしてくれないと、内部でなにがどうなってるのか理解しにくい。\ +何度か頑張って読もうとしたものの、面白くないのでやめた。\ +数百行のファイルをあっちからこっちから<code>include</code>してるし、\ +大文字ばかりの変数だらけで目が痛い。\ +こんなものを扱えるというのはえらいええ頭してはるんやね<sup>†</sup>。\ </p> @@ -77,5 +249,7 @@ UARTの通信には正確なクロックが必要である。\ <li> <a href="https://www5.epsondevice.com/ja/information/technical_info/osc.html">水晶発振器とは? 原理と仕組み、水晶振動子との違い、選び方のポイントを解説.エプソン水晶デバイス</a> </li> - </ul> + +<p><sup>†</sup>僕は和歌山の人間である。</p> + diff --git a/pub/computer/rp2040_2.html b/pub/computer/rp2040_2.html @@ -59,9 +59,99 @@ <h2>UART</h2> -<h2>リング発振回路でUARTは動くんかな?<h2> -<p>UARTの通信には正確なクロックが必要である。その為上では<code>clk_peri</code>として水晶発振子とPLLを用いた。ところがpico-examplesのhello_uartのCのヲースでは水晶発振子を設定していないように見える。しかし実は水晶発振子もPLLも<code>main()</code>が呼ばれる前に設定されているようだ。 +<h2>リング発振回路でUARTは動くんかな?</h2> +<p>UARTの通信には正確なクロックが必要である。その為上では<code>clk_peri</code>として水晶発振子とPLLを用いた。ところがpico-examplesのhello_uartでは<code>main()</code>関数で水晶発振子を設定していない。そこでリング発振回路を用いてみたのだが、どうもうまく通信できない。出力されている正確な周波数も分からないのであきらめることにした。オシロスコープなんていうものは持っていない。</p> + +<h3>pico-sdk</h3> +<p> +ところがどうも調べているとSDKを使った場合、デフォルトではクロック周波数は125MHzになっているらしい。どうやら水晶発振子もPLLも<code>main()</code>が呼ばれる前に設定されているようである。</p> +<p> +pico-examplesのサンプルプログラムはビルドすると自動で逆アセンブリしたファイルを出力してくれる。これを見ると、最初の256バイトは前回説明したboot2のコードで、その後ろにベクターテーブルが続く。ベクターテーブルの最初は初期スタックポインタで、<code>0x20042000</code>になっている。次はエントリーポイントで、<code>0x100001f7</code>である:</p> +<pre><code>10000100 &lt;__VECTOR_TABLE&gt;: +10000100: 20042000 .word 0x20042000 +10000104: 100001f7 .word 0x100001f7 +</code></pre> +<p> +Thumbモードなので実際のエントリーポイントは<code>1</code>引いた、<code>0x100001f6</code>である。この場所ではまず自分のCPUIDを調べて、<code>1</code>であれば待機状態に移行する。RP2040はデュアルコアである。起動直後はCPUIDが<code>0</code>のコアだけで処理をして、CPUIDが<code>1</code>のコアはプログラマが必要に応じて起動することになっている。このためCPUIDが<code>1</code>のコアは起動してすぐに待機状態に入ることがデータシートに書かれている。しかしこの処理はユーザーの書いたプログラムじゃなくて内蔵ROMにある起動用プログラムが担当するみたいに書かれてるんやけど、なんでSDKではユーザープログラムの一部として組み込んでるんかな? </p> +<pre><code>100001f6 &lt;_reset_handler&gt;: +100001f6: 481d ldr r0, [pc, #116] ; (1000026c &lt;hold_non_core0_in_bootrom+0xe&gt;) +100001f8: 6800 ldr r0, [r0, #0] +100001fa: 2800 cmp r0, #0 +100001fc: d12f bne.n 1000025e &lt;hold_non_core0_in_bootrom&gt; +</code></pre> +<p>上のコードの最初の<code>ldr</code>は、<code>0xd0000000</code>(M0PLUS: CPUIDレジスタ)をロードしている。最後の飛び先<code>0x1000025e</code>はCPUIDが<code>1</code>のCPUを待機させる処理である:</p> +<pre><code>1000025e &lt;hold_non_core0_in_bootrom&gt;: +1000025e: 4809 ldr r0, [pc, #36] ; (10000284 &lt;hold_non_core0_in_bootrom+0x26&gt;) +10000260: f001 fb9c bl 1000199c &lt;rom_func_lookup&gt; +10000264: 4700 bx r0 +10000266: 0000 .short 0x0000 +/* ... */ +10000284: 00005657 .word 0x00005657 +</code></pre> +<p>内蔵フラッシュに書きこまれた関数を呼びだしている。呼びだしに使うコードは<code>0x00005657</code>(<code>'W' | 'V' &lt;&lt; 8</code>)である。データシートを見ると、この関数は<code>_wait_for_vector()</code>という名前で、CPUIDが1のCPUを寝かしつけるのに使われると書いている。この部分のソースコードをpico-sdkで探すと<code>pico-sdk/src/rp2_common/pico_standard_link/crt0.S</code>というのが見付かった:</p> +<pre><code>$ find pico-sdk/src -type f | xargs grep -l _reset_handler +pico-sdk/src/rp2_common/pico_standard_link/crt0.S +</code></pre> +<p>このファイルによると: +</p> +<pre><code> // Only core 0 should run the C runtime startup code; core 1 is normally + // sleeping in the bootrom at this point but check to be sure +</code></pre> +<p>だそうである。やっぱり無駄やん。内蔵フラッシュのプログラムにバグがあってもこのコードのせいで見付かりにくくなってない?知らんけど。</p> + +<p>続いて<code>.data</code>領域と<code>.bss</code>領域のコピー、初期化のようである。多分OSの本かなんかで習ったメモリマップの話:</p> +<pre><code>100001fe: a40d add r4, pc, #52 ; (adr r4, 10000234 &lt;data_cpy_table&gt;) +10000200: cc0e ldmia r4!, {r1, r2, r3} +10000202: 2900 cmp r1, #0 +10000204: d002 beq.n 1000020c &lt;_reset_handler+0x16&gt; +10000206: f000 f812 bl 1000022e &lt;data_cpy&gt; +1000020a: e7f9 b.n 10000200 &lt;_reset_handler+0xa&gt; +1000020c: 4918 ldr r1, [pc, #96] ; (10000270 &lt;hold_non_core0_in_bootrom+0x12&gt;) +1000020e: 4a19 ldr r2, [pc, #100] ; (10000274 &lt;hold_non_core0_in_bootrom+0x16&gt;) +10000210: 2000 movs r0, #0 +10000212: e000 b.n 10000216 &lt;bss_fill_test&gt; + +10000214 &lt;bss_fill_loop&gt;: +10000214: c101 stmia r1!, {r0} + +10000216 &lt;bss_fill_test&gt;: +10000216: 4291 cmp r1, r2 +10000218: d1fc bne.n 10000214 &lt;bss_fill_loop&gt; +</code></pre> + +<p>最後にいろいろ呼びだす:</p> +<pre><code>1000021a &lt;platform_entry&gt;: +1000021a: 4917 ldr r1, [pc, #92] ; (10000278 &lt;hold_non_core0_in_bootrom+0x1a&gt;) +1000021c: 4788 blx r1 +1000021e: 4917 ldr r1, [pc, #92] ; (1000027c &lt;hold_non_core0_in_bootrom+0x1e&gt;) +10000220: 4788 blx r1 +10000222: 4917 ldr r1, [pc, #92] ; (10000280 &lt;hold_non_core0_in_bootrom+0x22&gt;) +10000224: 4788 blx r1 +10000226: be00 bkpt 0x0000 +10000228: e7fd b.n 10000226 &lt;platform_entry+0xc&gt; +/* ... */ +10000278: 10001819 .word 0x10001819 +1000027c: 100002dd .word 0x100002dd +10000280: 10001909 .word 0x10001909 +</code></pre> +<p>一つめの<code>blx</code>は<code>0x10001818</code>(<code>runtime_init</code>)を、二つめは<code>0x100002dc</code>(<code>main</code>)を、最後のは<code>0x10001908</code>(<code>exit</code>)を、それぞれ呼んでいる。この<code>runtime_init</code>はアセンブリでは分かりにくいのでソースコードを探してみると、以下のものが見付かった:</p> +<pre><code>$ find pico-sdk/src -type f | xargs grep -l runtime_init +pico-sdk/src/rp2_common/pico_runtime/runtime.c +pico-sdk/src/rp2_common/pico_standard_link/crt0.S +pico-sdk/src/common/pico_sync/include/pico/mutex.h +</code></pre> +<p>最後の<code>mutex.h</code>は関係なさそう。二つめの<code>crt0.S</code>は呼びだしてるだけ。一つめの<code>runtime.c</code>が多分探しているものである。これを見るとまず各種周辺機器を一度リセットし、リセット状態を解除している。使わんやつも初期化してない?その後<code>clocks_init()</code>を呼んでいる。この関数は<code>pico-sdk/src/rp2_common/hardware_clocks/clocks.c</code>で定義されている。これを見ると、<code>xosc_init()</code>を呼んで水晶発振子を初期化した後、<code>clk_peri</code>を125MHzに設定している:</p> +<pre><code> clock_configure(clk_peri, + 0, + CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, + 125 * MHZ, + 125 * MHZ); +</code></pre> +<p>やっぱり水晶発振子じゃないとあかんのかな。</p> + +<h2>CMake</h2> +<p>上ではビルドしたバイナリを逆アッセンブルして読んだ。わざわざこんなことをしなくてもMakefile読めばなにがどうなって最終生成物に辿りつくのか分かればいいのだが、そうもいかない。このSDKとpico-examplesにはビルドシステムとしてCMakeなるものが使われている。これがどうも複雑でよく分からない。勉強する気にもならん。上で見た<code>crt0.S</code>や<code>runtime.c</code>といったファイルも<code>hello_uart</code>で本当に使われているものなのかもよく分からない。こんな煩雑なものは本当に必要なのかな。無駄に複雑にしてるだけとちゃうんかな。特に僕みたいに勉強用に使ってる人には、ソースコードの依存関係をもっと分かりやすくしてくれないと、内部でなにがどうなってるのか理解しにくい。何度か頑張って読もうとしたものの、面白くないのでやめた。数百行のファイルをあっちからこっちから<code>include</code>してるし、大文字ばかりの変数だらけで目が痛い。こんなものを扱えるというのはえらいええ頭してはるんやね<sup>†</sup>。</p> <h2>参考</h2> @@ -81,8 +171,10 @@ <li> <a href="https://www5.epsondevice.com/ja/information/technical_info/osc.html">水晶発振器とは? 原理と仕組み、水晶振動子との違い、選び方のポイントを解説.エプソン水晶デバイス</a> </li> - </ul> + +<p><sup>†</sup>僕は和歌山の人間である。</p> + </article> </main> diff --git a/pub/rss.xml b/pub/rss.xml @@ -5,14 +5,14 @@ <description>ウェブページの更新履歴</description> <language>ja-jp</language> <link>https://www.mtkn.jp</link> -<lastBuildDate>Wed, 10 May 2023 20:20:52 +0900</lastBuildDate> -<pubDate>Wed, 10 May 2023 20:20:52 +0900</pubDate> +<lastBuildDate>Thu, 11 May 2023 12:05:55 +0900</lastBuildDate> +<pubDate>Thu, 11 May 2023 12:05:55 +0900</pubDate> <docs>https://www.rssboard.org/rss-specification</docs> <item> <title>RP2040 SDKなし2 Clock, UART</title> <link>https://www.mtkn.jp/computer/rp2040_2.html</link> <guid>https://www.mtkn.jp/computer/rp2040_2.html</guid> -<pubDate>Wed, 10 May 2023 00:00:00 +0900</pubDate> +<pubDate>Thu, 11 May 2023 00:00:00 +0900</pubDate> <description><![CDATA[<h1>RP2040 SDKなし2 Clock, UART</h1> <time>2023-05-10</time> <p> @@ -51,9 +51,99 @@ <h2>UART</h2> -<h2>リング発振回路でUARTは動くんかな?<h2> -<p>UARTの通信には正確なクロックが必要である。その為上では<code>clk_peri</code>として水晶発振子とPLLを用いた。ところがpico-examplesのhello_uartのCのヲースでは水晶発振子を設定していないように見える。しかし実は水晶発振子もPLLも<code>main()</code>が呼ばれる前に設定されているようだ。 +<h2>リング発振回路でUARTは動くんかな?</h2> +<p>UARTの通信には正確なクロックが必要である。その為上では<code>clk_peri</code>として水晶発振子とPLLを用いた。ところがpico-examplesのhello_uartでは<code>main()</code>関数で水晶発振子を設定していない。そこでリング発振回路を用いてみたのだが、どうもうまく通信できない。出力されている正確な周波数も分からないのであきらめることにした。オシロスコープなんていうものは持っていない。</p> + +<h3>pico-sdk</h3> +<p> +ところがどうも調べているとSDKを使った場合、デフォルトではクロック周波数は125MHzになっているらしい。どうやら水晶発振子もPLLも<code>main()</code>が呼ばれる前に設定されているようである。</p> +<p> +pico-examplesのサンプルプログラムはビルドすると自動で逆アセンブリしたファイルを出力してくれる。これを見ると、最初の256バイトは前回説明したboot2のコードで、その後ろにベクターテーブルが続く。ベクターテーブルの最初は初期スタックポインタで、<code>0x20042000</code>になっている。次はエントリーポイントで、<code>0x100001f7</code>である:</p> +<pre><code>10000100 &lt;__VECTOR_TABLE&gt;: +10000100: 20042000 .word 0x20042000 +10000104: 100001f7 .word 0x100001f7 +</code></pre> +<p> +Thumbモードなので実際のエントリーポイントは<code>1</code>引いた、<code>0x100001f6</code>である。この場所ではまず自分のCPUIDを調べて、<code>1</code>であれば待機状態に移行する。RP2040はデュアルコアである。起動直後はCPUIDが<code>0</code>のコアだけで処理をして、CPUIDが<code>1</code>のコアはプログラマが必要に応じて起動することになっている。このためCPUIDが<code>1</code>のコアは起動してすぐに待機状態に入ることがデータシートに書かれている。しかしこの処理はユーザーの書いたプログラムじゃなくて内蔵ROMにある起動用プログラムが担当するみたいに書かれてるんやけど、なんでSDKではユーザープログラムの一部として組み込んでるんかな? </p> +<pre><code>100001f6 &lt;_reset_handler&gt;: +100001f6: 481d ldr r0, [pc, #116] ; (1000026c &lt;hold_non_core0_in_bootrom+0xe&gt;) +100001f8: 6800 ldr r0, [r0, #0] +100001fa: 2800 cmp r0, #0 +100001fc: d12f bne.n 1000025e &lt;hold_non_core0_in_bootrom&gt; +</code></pre> +<p>上のコードの最初の<code>ldr</code>は、<code>0xd0000000</code>(M0PLUS: CPUIDレジスタ)をロードしている。最後の飛び先<code>0x1000025e</code>はCPUIDが<code>1</code>のCPUを待機させる処理である:</p> +<pre><code>1000025e &lt;hold_non_core0_in_bootrom&gt;: +1000025e: 4809 ldr r0, [pc, #36] ; (10000284 &lt;hold_non_core0_in_bootrom+0x26&gt;) +10000260: f001 fb9c bl 1000199c &lt;rom_func_lookup&gt; +10000264: 4700 bx r0 +10000266: 0000 .short 0x0000 +/* ... */ +10000284: 00005657 .word 0x00005657 +</code></pre> +<p>内蔵フラッシュに書きこまれた関数を呼びだしている。呼びだしに使うコードは<code>0x00005657</code>(<code>'W' | 'V' &lt;&lt; 8</code>)である。データシートを見ると、この関数は<code>_wait_for_vector()</code>という名前で、CPUIDが1のCPUを寝かしつけるのに使われると書いている。この部分のソースコードをpico-sdkで探すと<code>pico-sdk/src/rp2_common/pico_standard_link/crt0.S</code>というのが見付かった:</p> +<pre><code>$ find pico-sdk/src -type f | xargs grep -l _reset_handler +pico-sdk/src/rp2_common/pico_standard_link/crt0.S +</code></pre> +<p>このファイルによると: +</p> +<pre><code> // Only core 0 should run the C runtime startup code; core 1 is normally + // sleeping in the bootrom at this point but check to be sure +</code></pre> +<p>だそうである。やっぱり無駄やん。内蔵フラッシュのプログラムにバグがあってもこのコードのせいで見付かりにくくなってない?知らんけど。</p> + +<p>続いて<code>.data</code>領域と<code>.bss</code>領域のコピー、初期化のようである。多分OSの本かなんかで習ったメモリマップの話:</p> +<pre><code>100001fe: a40d add r4, pc, #52 ; (adr r4, 10000234 &lt;data_cpy_table&gt;) +10000200: cc0e ldmia r4!, {r1, r2, r3} +10000202: 2900 cmp r1, #0 +10000204: d002 beq.n 1000020c &lt;_reset_handler+0x16&gt; +10000206: f000 f812 bl 1000022e &lt;data_cpy&gt; +1000020a: e7f9 b.n 10000200 &lt;_reset_handler+0xa&gt; +1000020c: 4918 ldr r1, [pc, #96] ; (10000270 &lt;hold_non_core0_in_bootrom+0x12&gt;) +1000020e: 4a19 ldr r2, [pc, #100] ; (10000274 &lt;hold_non_core0_in_bootrom+0x16&gt;) +10000210: 2000 movs r0, #0 +10000212: e000 b.n 10000216 &lt;bss_fill_test&gt; + +10000214 &lt;bss_fill_loop&gt;: +10000214: c101 stmia r1!, {r0} + +10000216 &lt;bss_fill_test&gt;: +10000216: 4291 cmp r1, r2 +10000218: d1fc bne.n 10000214 &lt;bss_fill_loop&gt; +</code></pre> + +<p>最後にいろいろ呼びだす:</p> +<pre><code>1000021a &lt;platform_entry&gt;: +1000021a: 4917 ldr r1, [pc, #92] ; (10000278 &lt;hold_non_core0_in_bootrom+0x1a&gt;) +1000021c: 4788 blx r1 +1000021e: 4917 ldr r1, [pc, #92] ; (1000027c &lt;hold_non_core0_in_bootrom+0x1e&gt;) +10000220: 4788 blx r1 +10000222: 4917 ldr r1, [pc, #92] ; (10000280 &lt;hold_non_core0_in_bootrom+0x22&gt;) +10000224: 4788 blx r1 +10000226: be00 bkpt 0x0000 +10000228: e7fd b.n 10000226 &lt;platform_entry+0xc&gt; +/* ... */ +10000278: 10001819 .word 0x10001819 +1000027c: 100002dd .word 0x100002dd +10000280: 10001909 .word 0x10001909 +</code></pre> +<p>一つめの<code>blx</code>は<code>0x10001818</code>(<code>runtime_init</code>)を、二つめは<code>0x100002dc</code>(<code>main</code>)を、最後のは<code>0x10001908</code>(<code>exit</code>)を、それぞれ呼んでいる。この<code>runtime_init</code>はアセンブリでは分かりにくいのでソースコードを探してみると、以下のものが見付かった:</p> +<pre><code>$ find pico-sdk/src -type f | xargs grep -l runtime_init +pico-sdk/src/rp2_common/pico_runtime/runtime.c +pico-sdk/src/rp2_common/pico_standard_link/crt0.S +pico-sdk/src/common/pico_sync/include/pico/mutex.h +</code></pre> +<p>最後の<code>mutex.h</code>は関係なさそう。二つめの<code>crt0.S</code>は呼びだしてるだけ。一つめの<code>runtime.c</code>が多分探しているものである。これを見るとまず各種周辺機器を一度リセットし、リセット状態を解除している。使わんやつも初期化してない?その後<code>clocks_init()</code>を呼んでいる。この関数は<code>pico-sdk/src/rp2_common/hardware_clocks/clocks.c</code>で定義されている。これを見ると、<code>xosc_init()</code>を呼んで水晶発振子を初期化した後、<code>clk_peri</code>を125MHzに設定している:</p> +<pre><code> clock_configure(clk_peri, + 0, + CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, + 125 * MHZ, + 125 * MHZ); +</code></pre> +<p>やっぱり水晶発振子じゃないとあかんのかな。</p> + +<h2>CMake</h2> +<p>上ではビルドしたバイナリを逆アッセンブルして読んだ。わざわざこんなことをしなくてもMakefile読めばなにがどうなって最終生成物に辿りつくのか分かればいいのだが、そうもいかない。このSDKとpico-examplesにはビルドシステムとしてCMakeなるものが使われている。これがどうも複雑でよく分からない。勉強する気にもならん。上で見た<code>crt0.S</code>や<code>runtime.c</code>といったファイルも<code>hello_uart</code>で本当に使われているものなのかもよく分からない。こんな煩雑なものは本当に必要なのかな。無駄に複雑にしてるだけとちゃうんかな。特に僕みたいに勉強用に使ってる人には、ソースコードの依存関係をもっと分かりやすくしてくれないと、内部でなにがどうなってるのか理解しにくい。何度か頑張って読もうとしたものの、面白くないのでやめた。数百行のファイルをあっちからこっちから<code>include</code>してるし、大文字ばかりの変数だらけで目が痛い。こんなものを扱えるというのはえらいええ頭してはるんやね<sup>†</sup>。</p> <h2>参考</h2> @@ -73,8 +163,10 @@ <li> <a href="https://www5.epsondevice.com/ja/information/technical_info/osc.html">水晶発振器とは? 原理と仕組み、水晶振動子との違い、選び方のポイントを解説.エプソン水晶デバイス</a> </li> - </ul> + +<p><sup>†</sup>僕は和歌山の人間である。</p> + ]]></description> </item> <item> diff --git a/pub/sitemap.xml b/pub/sitemap.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url><loc>https://www.mtkn.jp/</loc><lastmod>2023-12-28</lastmod></url> -<url><loc>https://www.mtkn.jp/computer/rp2040_2.html</loc><lastmod>2023-05-10</lastmod></url> +<url><loc>https://www.mtkn.jp/computer/rp2040_2.html</loc><lastmod>2023-05-11</lastmod></url> <url><loc>https://www.mtkn.jp/computer/rp2040_1.html</loc><lastmod>2023-05-09</lastmod></url> <url><loc>https://www.mtkn.jp/computer/what-i-use.html</loc><lastmod>2023-05-02</lastmod></url> <url><loc>https://www.mtkn.jp/computer/xlib_playground6.html</loc><lastmod>2023-04-25</lastmod></url>