rp2040_2.html (23968B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width,initial-scale=1"> 6 <link rel="stylesheet" type="text/css" href="/style.css"> 7 <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> 8 <title>RP2040 SDKなし2 Clock、UART</title> 9 </head> 10 <body> 11 <header> 12 <a href="/">主頁</a> | 13 <a href="/about.html">自己紹介</a> | 14 <a href="/journal">日記</a> | 15 <a href="/farm">農業</a> | 16 <a href="/kitchen">台所</a> | 17 <a href="/computer">電算機</a> | 18 <a href="/poetry">詩</a> | 19 <a href="/books">本棚</a> | 20 <a href="/gallery">絵</a> | 21 <a href="https://git.mtkn.jp">Git</a> 22 </header> 23 <main> 24 <article> 25 <h1>RP2040 SDKなし2 Clock、UART</h1> 26 <time>2024-02-22</time><br /> 27 <time>2024-02-27</time>: リセット解除の間違いを修正。 28 <p> 29 今回はClockとUARTを設定してパソコンに繋ぎ、キーボードからの入力をオウム返しするプログラムを作成する。 30 <p> 31 <p> 32 前回: <a href="rp2040_1.html">RP2040 SDKなしでLチカ</a><br> 33 ソースコード: <a href="https://git.mtkn.jp/rp2040">git</a>/ex2 34 </p> 35 36 <h2>動作環境</h2> 37 <ul> 38 <li>Void Linux 39 <ul> 40 <li>cross-arm-none-eabi-binutils-2.32_2</li> 41 <li>GNU Make 4.4.1</li> 42 <li>minicom version 2.7.1</li> 43 </ul> 44 </li> 45 <li><a href="https://akizukidenshi.com/catalog/g/g108461/">FT234X 超小型USBシリアル変換モジュール</a> 46 </li> 47 </ul> 48 49 <h2>Clock</h2> 50 51 <h3>リング発振回路</h3> 52 <p>RP2040にはリング発振回路というのが内蔵されている。これは自分の出力を反転させようとするもので、不安定だが高速で消費電力の少ないクロックとして用いられる。RP2040は電源を入れると、このリング発振回路を動作用のクロックとして用いている。この発振回路の周波数は、チップの製造過程での誤差、動作時の電圧、動作温度によって変動するので、正確な周波数が必要な用途には向かない。</p> 53 54 <h3>水晶発振子</h3> 55 <p>秋月電子通商で購入したRP2040マイコンボードには外部クロックとして、12MHzの水晶発振子が付属する。水晶発振子はリング発振回路より電力を消費するが、より正確である。</p> 56 57 <h3>PLL</h3> 58 <p>水晶振動子を入力として、周波数を数倍にしたものを出力するもの。電気的な話はよく知らない。データシートの「2.18.2. Calcurating PLL parameters」によると、入力周波数を<code>FREF</code>としたときの出力周波数は<code>(FREF / REFDIV) × FBDIV / (POSTDIV1 × POSTDIV2)</code>となる。これらの変数はそれぞれ設定用のレジスタに値を保存することで変更できる。</p> 59 60 <h2>UART</h2> 61 <p> 62 Universal Asynchronous Receiver/Transmitterの略。2本の線だけで通信できる。プロトコルは詳しく知らないが、rp2040がよしなにやってくれる。rp2040では同時に二個まで利用できる。どのGPIOピンを使うかもある程度自由に選べる。どのピンが使えるかはデータシートの「2.19.2. Function Select」に書かれている。今回はGPIO0とGPIO1を使う。パソコンとの接続には、秋月電子通商で売っている<a href="https://akizukidenshi.com/catalog/g/g108461/">FT234X 超小型USBシリアル変換モジュール</a>を使用した。UARTで接続するためのパソコン側のソフトウェアはminicomを使用した。僕の環境ではシリアル変換モジュールをパソコンにUSB接続すると、<code>/dev/ttyUSB0</code>として認識されるので、</p> 63 <pre><code>$ minicom -D /dev/ttyUSB0 64 </code></pre> 65 <p> 66 とすると接続できる。 67 </p> 68 69 <h2>main.s</h2> 70 <h3>初期設定</h3> 71 <p> 72 後で見るように、UARTの動作には多分水晶発振子とPLLが必要なので、まずはそれを設定する。起動後、メインのプログラムが読み込まれるまでの<code>boot2</code>は前回と同じものである。<code>main.s</code>ではまず前回と同様に初期スタックポインタとエントリーポイントを定義する: 73 </p> 74 <pre><code> .section .vectors 75 vectors: 76 .word 0x20040000 // initial SP 77 .word (reset+1) // entry point 78 </code></pre> 79 <p> 80 続いて利用するサブシステムのリセットを解除する。PLLとUARTが追加されている。今回使うUARTはUART0だけである。なお、UARTはclock_periが有効化されるまでリセット状態の解除が完了しないようなので、unreset_chkからは外してある:</p> 81 <pre><code> .section .text 82 reset: 83 // unreset gpio, pll_sys, uart0 84 ldr r0, =(1 << 22 | 1 << 12 | 1 << 5) // uart0 | pll_sys | io_bank0 85 ldr r3, resets_base 86 ldr r1, atomic_clr 87 str r0, [r3, r1] // RESETS: RESET 88 mov r1, #1 89 lsl r1, #22 90 bic r0, r1 // uart stays in reset state until clock_peri is enabled 91 unreset_chk: 92 ldr r1, [r3, #0x8] // RESETS: RESET_DONE 93 bic r0, r1 94 bne unreset_chk 95 96 /* ... */ 97 98 atomic_clr: 99 .word 0x00003000 100 resets_base: 101 .word 0x4000c000 102 </code></pre> 103 104 <h3>GPIOの設定</h3> 105 <p> 106 次にGPIOの役割を設定する。前回はLEDを点滅させるためにGPIO25をSIOに設定したが、今回はGPIO0とGPIO1をUART0にする: 107 </p> 108 <pre><code> // set gpio functions 109 ldr r3, io_bank0_base 110 mov r0, #2 // uart0 111 mov r1, #0x4 112 str r0, [r3, r1] // IO_BANK0: GPIO0_CTRL 113 mov r1, #0xc 114 str r0, [r3, r1] // IO_BANK0: GPIO1_CTRL 115 116 /* ... */ 117 118 io_bank0_base: 119 .word 0x40014000 120 </code></pre> 121 122 <h3>Clockの設定</h3> 123 <p> 124 Clockの設定をする。まずは水晶発振子を起動する。水晶発振子は起動してから周波数が安定するまで少し時間がかかるようで、その間待たないといけない。この時間は1msあれば十分だとデータシートに書いている。この待ち時間はXOSC: STARTUPレジスタに、256サイクル単位で記述する。データシートによると初期のリング発振子は最大で12MHzなので、<code>(12 * 10^6 * 1 * 10^-3) / 256 = 47</code>をこのレジスタにセットする。ところでデータシートではこの計算はリング発振子ではなく水晶発振子の周波数で書かれている。起動直後でまだ使えない水晶発振子の周波数を使うのはなんでやろ。SDKでも<code>pico-sdk/src/rp2_common/hardware_xosc/xosc.c</code>で、 125 </p> 126 <pre><code>#define STARTUP_DELAY (((((XOSC_MHZ * MHZ) / 1000) + 128) / 256) * PICO_XOSC_STARTUP_DELAY_MULTIPLIER) 127 </code></pre> 128 <p> 129 と定義されている(PICO_XOSC_STARTUP_DELAY_MULTIPLIERは1)。とりあえず47に設定しているが、試しに0や1にしても動いた。よくわからん。</p> 130 <p> 131 待ち時間を設定したら発振子を起動する。XOSC: CTRLに起動用のコマンド的なものを入力し、周波数が安定するのを待つ。</p> 132 <p> 133 以上を実装したのが以下のコード: 134 </p> 135 <pre><code> // setup xosc 136 ldr r3, xosc_base 137 mov r0, #47 // start up delay for 12MHz rosc (xosc?) 138 str r0, [r3, #0xc] // XOSC: STARTUP 139 ldr r0, =(0xfab << 12 | 0xaa0) 140 str r0, [r3, #0] // XOSC: CTRL 141 wait_xosc: 142 ldr r0, [r3, #0x4] // XOSC: STATUS 143 lsr r0, r0, #31 // STABLE bit 144 beq wait_xosc 145 146 /* ... */ 147 148 xosc_base: 149 .word 0x40024000 150 </code></pre> 151 152 <h3>PLLの設定</h3> 153 <p> 154 水晶発振子が起動できたので、次にPLLを設定する。CPUが133MHzまで対応しているので133MHzになるようにした。</p> 155 <p> 156 PLLは入力となる振動(ここでは水晶発振子の振動)を加工して周波数を上げたり下げたりする。出力の周波数は以下の式で決まる: 157 </p> 158 <pre>(FREF / REFDIV) * FBDIV / (POSTDIV1 * POSTDIV2)</pre> 159 <p> 160 FREFは入力の周波数(ここでは12MHz)で、その他の変数はプログラマが設定できる。ただしデータシートによると(FREF / REFDIV)は5MHz以上でないといけないので、REFDIVは1である。また、FBDIVは16〜320、POSTDIV1とPOSTDIV2は1〜7で、POSTDIV1とPOSTDIV2に違う値を代入する場合、POSTDIV1に大きい方を入れたほうが消費電力が少なくなるとのことなので、133MHzにするには、FBDIV=133、POSTDIV1=6、POSTDIV=2とすればいい(POSTDIV1=4、POSTDIV2=3も可能だが、pico-sdkに付属するvcocalc.pyというスクリプトのコメントには、この2つの値の差が大きい方がいいと書いている)。 161 </p> 162 <p> 163 PLL設定の手順は、FBDIVの設定、PLLとVCOの起動、VOCが安定するまで待機、POSTDIV1とPOSTDIV2の設定、Post Dividerの起動、そして最後にシステムとUARTのクロックを今設定したPLLに変更、である。以上を実装したのが以下のコード: 164 </p> 165 <pre><code> // setup pll_sys 133MHz 166 ldr r3, pll_sys_base 167 // set feedback divider 168 mov r0, #133 169 str r0, [r3, #0x8] // PLL: FBDIV_INT 170 // power on pll and vco 171 ldr r0, =(1 << 5 | 1) // VCOPD | PD 172 ldr r1, atomic_clr 173 add r1, r1, #0x4 174 str r0, [r3, r1] // PLL: PWR 175 // wait vco to lock 176 wait_vco: 177 ldr r0, [r3, #0] // PLL: CS 178 lsl r0, r0, #31 179 beq wait_vco 180 // setup post dividers 181 ldr r0, =(4 << 16 | 3 << 12) 182 str r0, [r3, #0xc] // PLL: PRIM 183 // power on post divider 184 mov r0, #8 // POSTDIVPD 185 str r0, [r3, r1] // PLL: PWR 186 187 // set system clock clksrc_pll_sys 188 ldr r3, clocks_base 189 ldr r0, =(0x0 << 5 | 0x1) 190 str r0, [r3, #0x3c] // CLOCKS: CLK_SYS_CTRL 191 // enable clk_peri 192 mov r0, #1 193 lsl r0, r0, #11 194 str r0, [r3, #0x48] // CLOCKS: CLK_PERI_CTRL 195 196 /* ... */ 197 198 atomic_clr: 199 .word 0x00003000 200 clocks_base: 201 .word 0x40008000 202 pll_sys_base: 203 .word 0x40028000 204 </code></pre> 205 206 <h3>UARTの設定</h3> 207 <p> 208 データシートによるとUART設定の手順は以下の通り: 209 </p> 210 <ul> 211 <li>リセットの解除</li> 212 <li>clock_periの設定</li> 213 <li>UARTの有効化</li> 214 <li>FIFOの有効化</li> 215 <li>転送速度の設定</li> 216 <li>フォーマットの設定</li> 217 </ul> 218 <p> 219 上の2つは既に終えている。残りの部分はこの順番どおりに設定しても動かなかった。C言語で書かれたサンプルを見ると、クロックを設定した後、転送速度の設定、UARTの有効化、FIFOの有効化の順になっている。そのとおりにすると動いた。理由はよく理解していないが、変数を設定してから起動するほうが素直ではある。</p> 220 <p> 221 転送速度はminicomのデフォルトである115200 baudに設定する。データシート「4.2.7.1. Baud Rate Calculation」の計算式において、クロック周波数を125MHzから133MHzに変えて計算して、BRDI=72、BDRF=0.157(=10/64)となる。この数値をUART: UARTIBRD、UART: UARTFBRDレジスタにそれぞれ代入する。 222 </p> 223 <p> 224 UARTの有効化はUART: UARTCRレジスタのUARTENビットをセットすることで行う。C言語のサンプルでは同じレジスタのRXE、TXEビットもセットしているが、この2つはもともと1になっているのでほっといてよさそう。</p> 225 <p> 226 FIFOの有効化はUART: UARTLCR_HレジスタのFENビットをセットすることで行う。また、同じレジスタの他のビットで、データーのフォーマットを設定できる。ここではminicomのデフォルトに合わせてWLENを8bitにする。</p> 227 <p> 228 以上をまとめると以下のようになる: 229 </p> 230 <pre><code> // setup uart0 231 ldr r3, uart0_base 232 // set baudrate 115200 233 // BDRI = 72, BDRF = 0.157 (10 / 64) 234 mov r0, #72 235 str r0, [r3, #0x24] // UART: UARTIBRD 236 mov r0, #10 237 str r0, [r3, #0x28] // UART: UARTFBRD 238 // enable uart0 239 mov r0, #1 // UARTEN 240 ldr r1, atomic_set 241 add r1, r1, #0x30 242 str r0, [r3, r1] // UART: UARTCR 243 // enable FIFO and set format 244 ldr r0, =(3 << 5 | 1 << 4) // WLEN = 8, FEN = 1 245 str r0, [r3, #0x2c] // UART: UARTLCR_H 246 247 /* ... */ 248 249 atomic_set: 250 .word 0x00002000 251 uart0_base: 252 .word 0x40034000 253 </code></pre> 254 255 <h3>UARTの入出力</h3> 256 <p> 257 設定が終わったので実際にUARTの入出力を処理するコードを書く。まずUARTからの出力は、出力したいバイトをUART: UARTDRに書き込むことで行う。その際、書き込まれたデータは一時的に出力用FIFOに保持されるので、このFIFOが満杯でないことを確認する必要がある。FIFOの状態はUART: UARTFRレジスタで確認できる。このレジスタのTXFFの値が1であればデータを書き込めないので、0になるまで待機する。関数名は<code>putbyte</code>にした。また出力したいデータは<code>r0</code>レジスタにの下位8ビットに入れられているものとした。書き込めるデーターは8ビットだけなので、<code>0xff</code>と論理積をとってから書き込んでいる: 258 </p> 259 <pre><code>putbyte: 260 ldr r3, uart0_base 261 mov r1, #1 262 lsl r1, r1, #5 // TXFF 263 txff: 264 ldr r2, [r3, #0x18] // UART: UARTFR 265 tst r1, r2 266 bne txff 267 mov r1, #0xff 268 and r0, r0, r1 269 str r0, [r3, #0] // UART: UARTDR 270 bx lr 271 272 /* ... */ 273 274 uart0_base: 275 .word 0x40034000 276 </code></pre> 277 278 <p> 279 入力はUART: UARTDRの下位8ビットを読むことで得られる。UARTからの入力は、一時的に入力用FIFOに保存される。このFIFOが空の状態でデータを読んでも意味がないので、FIFOが空でないことを確認する必要がある。これはUART: UARTFRレジスタのRXFEを読むことで確認できる。本来は入力があったときに割り込みを発生させて、それまではCPUを休ませるか別の処理をさせておくべきだが、とりあえずここではループでFIFOの状態を確認し続けている。関数名は<code>getbyte</code>にした。 280 読み込んだデータは<code>r0</code>レジスタに保存している:</p> 281 <pre><code>getbyte: 282 ldr r3, uart0_base 283 mov r1, #1 284 lsl r1, r1, #4 // RXFE 285 rxfe: 286 ldr r2, [r3, #0x18] // UART: UARTFR 287 tst r1, r2 288 bne rxfe 289 ldr r0, [r3, #0] // UART: UARTDR 290 mov r1, #0xff 291 and r0, r0, r1 292 bx lr 293 294 /* ... */ 295 296 uart0_base: 297 .word 0x40034000 298 </code></pre> 299 <p> 300 あとはこの2つの関数をループの中で交互に呼び出せば、オウム返しするだけのプログラムが完成する: 301 </p> 302 <pre><code>loop: 303 bl getbyte 304 bl putbyte 305 b loop 306 </code></pre> 307 308 <h2>リング発振回路でUARTは動くんかな?</h2> 309 <p>UARTの通信には正確なクロックが必要である。その為上では<code>clk_peri</code>として水晶発振子とPLLを用いた。ところがpico-examplesのhello_uartでは<code>main()</code>関数で水晶発振子を設定していない。そこでリング発振回路を用いてみたのだが、どうもうまく通信できない。出力されている正確な周波数も分からないのであきらめることにした。オシロスコープなんていうものは持っていない。</p> 310 311 <h3>pico-sdk</h3> 312 <p> 313 ところがどうも調べているとSDKを使った場合、デフォルトではクロック周波数は125MHzになっているらしい。どうやら水晶発振子もPLLも<code>main()</code>が呼ばれる前に設定されているようである。</p> 314 <p> 315 pico-examplesのサンプルプログラムはビルドすると自動で逆アセンブリしたファイルを出力してくれる。これを見ると、最初の256バイトは前回説明したboot2のコードで、その後ろにベクターテーブルが続く。ベクターテーブルの最初は初期スタックポインタで、<code>0x20042000</code>になっている。次はエントリーポイントで、<code>0x100001f7</code>である:</p> 316 <pre><code>10000100 <__VECTOR_TABLE>: 317 10000100: 20042000 .word 0x20042000 318 10000104: 100001f7 .word 0x100001f7 319 </code></pre> 320 <p> 321 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ではユーザープログラムの一部として組み込んでるんかな? 322 </p> 323 <pre><code>100001f6 <_reset_handler>: 324 100001f6: 481d ldr r0, [pc, #116] ; (1000026c <hold_non_core0_in_bootrom+0xe>) 325 100001f8: 6800 ldr r0, [r0, #0] 326 100001fa: 2800 cmp r0, #0 327 100001fc: d12f bne.n 1000025e <hold_non_core0_in_bootrom> 328 </code></pre> 329 <p>上のコードの最初の<code>ldr</code>は、<code>0xd0000000</code>(M0PLUS: CPUIDレジスタ)をロードしている。最後の飛び先<code>0x1000025e</code>はCPUIDが<code>1</code>のCPUを待機させる処理である:</p> 330 <pre><code>1000025e <hold_non_core0_in_bootrom>: 331 1000025e: 4809 ldr r0, [pc, #36] ; (10000284 <hold_non_core0_in_bootrom+0x26>) 332 10000260: f001 fb9c bl 1000199c <rom_func_lookup> 333 10000264: 4700 bx r0 334 10000266: 0000 .short 0x0000 335 /* ... */ 336 10000284: 00005657 .word 0x00005657 337 </code></pre> 338 <p>内蔵フラッシュに書きこまれた関数を呼びだしている。呼びだしに使うコードは<code>0x00005657</code>(<code>'W' | 'V' << 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> 339 <pre><code>$ find pico-sdk/src -type f | xargs grep -l _reset_handler 340 pico-sdk/src/rp2_common/pico_standard_link/crt0.S 341 </code></pre> 342 <p>このファイルによると: 343 </p> 344 <pre><code> // Only core 0 should run the C runtime startup code; core 1 is normally 345 // sleeping in the bootrom at this point but check to be sure 346 </code></pre> 347 <p>だそうである。やっぱり無駄やん。内蔵フラッシュのプログラムにバグがあってもこのコードのせいで見付かりにくくなってない?知らんけど。</p> 348 349 <p>続いて<code>.data</code>領域と<code>.bss</code>領域のコピー、初期化のようである。多分OSの本かなんかで習ったメモリマップの話:</p> 350 <pre><code>100001fe: a40d add r4, pc, #52 ; (adr r4, 10000234 <data_cpy_table>) 351 10000200: cc0e ldmia r4!, {r1, r2, r3} 352 10000202: 2900 cmp r1, #0 353 10000204: d002 beq.n 1000020c <_reset_handler+0x16> 354 10000206: f000 f812 bl 1000022e <data_cpy> 355 1000020a: e7f9 b.n 10000200 <_reset_handler+0xa> 356 1000020c: 4918 ldr r1, [pc, #96] ; (10000270 <hold_non_core0_in_bootrom+0x12>) 357 1000020e: 4a19 ldr r2, [pc, #100] ; (10000274 <hold_non_core0_in_bootrom+0x16>) 358 10000210: 2000 movs r0, #0 359 10000212: e000 b.n 10000216 <bss_fill_test> 360 361 10000214 <bss_fill_loop>: 362 10000214: c101 stmia r1!, {r0} 363 364 10000216 <bss_fill_test>: 365 10000216: 4291 cmp r1, r2 366 10000218: d1fc bne.n 10000214 <bss_fill_loop> 367 </code></pre> 368 369 <p>最後にいろいろ呼びだす:</p> 370 <pre><code>1000021a <platform_entry>: 371 1000021a: 4917 ldr r1, [pc, #92] ; (10000278 <hold_non_core0_in_bootrom+0x1a>) 372 1000021c: 4788 blx r1 373 1000021e: 4917 ldr r1, [pc, #92] ; (1000027c <hold_non_core0_in_bootrom+0x1e>) 374 10000220: 4788 blx r1 375 10000222: 4917 ldr r1, [pc, #92] ; (10000280 <hold_non_core0_in_bootrom+0x22>) 376 10000224: 4788 blx r1 377 10000226: be00 bkpt 0x0000 378 10000228: e7fd b.n 10000226 <platform_entry+0xc> 379 /* ... */ 380 10000278: 10001819 .word 0x10001819 381 1000027c: 100002dd .word 0x100002dd 382 10000280: 10001909 .word 0x10001909 383 </code></pre> 384 <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> 385 <pre><code>$ find pico-sdk/src -type f | xargs grep -l runtime_init 386 pico-sdk/src/rp2_common/pico_runtime/runtime.c 387 pico-sdk/src/rp2_common/pico_standard_link/crt0.S 388 pico-sdk/src/common/pico_sync/include/pico/mutex.h 389 </code></pre> 390 <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> 391 <pre><code> clock_configure(clk_peri, 392 0, 393 CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, 394 125 * MHZ, 395 125 * MHZ); 396 </code></pre> 397 <p>やっぱり水晶発振子じゃないとあかんのかな。</p> 398 399 <h2>CMake</h2> 400 <p>上ではビルドしたバイナリを逆アッセンブルして読んだ。わざわざこんなことをしなくてもMakefile読めばなにがどうなって最終生成物に辿りつくのか分かればいいのだが、そうもいかない。このSDKとpico-examplesにはビルドシステムとしてCMakeなるものが使われている。これがどうも複雑でよく分からない。勉強する気にもならん。上で見た<code>crt0.S</code>や<code>runtime.c</code>といったファイルも<code>hello_uart</code>で本当に使われているものなのかもよく分からない。こんな煩雑なものは本当に必要なのかな。無駄に複雑にしてるだけとちゃうんかな。特に僕は勉強用に使ってるので、ソースコードの依存関係をもっと分かりやすくしてくれないと、内部でなにがどうなってるのか理解しにくい。何度か頑張って読もうとしたが、面白くないのでやめた。数百行のファイルをあっちからこっちから<code>include</code>してるし、大文字ばかりの変数だらけで目が痛い。こんなものを扱えるというのはえらいええ頭してはるんやね。</p> 401 402 403 <h2>参考</h2> 404 <ul> 405 <li> 406 <a href="https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf">RP2040 Datasheet.Raspberry Pi Foundation</a> 407 </li> 408 <li> 409 <a href="https://github.com/raspberrypi/pico-sdk">pico-sdk.github</a> 410 </li> 411 <li> 412 <a href="https://developer.arm.com/documentation/ddi0419/c/">ARMv6-M Architecture Reference Manual</a> 413 </li> 414 <li> 415 <a href="https://ja.wikipedia.org/wiki/%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%BB%E3%82%AA%E3%82%B7%E3%83%AC%E3%83%BC%E3%82%BF">リング・オシレータ.Wikipedia</a> 416 </li> 417 <li> 418 <a href="https://www5.epsondevice.com/ja/information/technical_info/osc.html">水晶発振器とは? 原理と仕組み、水晶振動子との違い、選び方のポイントを解説.エプソン水晶デバイス</a> 419 </li> 420 </ul> 421 </article> 422 423 </main> 424 <footer> 425 <address>info(at)mtkn(dot)jp</address> 426 <a href="http://creativecommons.org/publicdomain/zero/1.0?ref=chooser-v1" rel="license noopener noreferrer">CC0 1.0</a> 427 </footer> 428 </body> 429 </html>