付録: 実機がなくても試せる#

Arduino UNO R4 WiFi が手元に無くても、実機と同じファームウェアを PC の中で 動かして本書を読み進められます。LED マトリクスと内蔵 LED はブラウザ上の 基板写真に重ねて表示され、第5章で作るシェルもそのまま使えます。

pio run -e sim   →   firmware.elf   →   QEMU (RA4M1)   →   ブラウザ
  (いつもの        (実機に書くものと     (実機と同じ        (基板の上で
    ビルド)          同じ ELF)           Cortex-M4)         LED が光る)

図の QEMU は CPU とボードをソフトウェアで再現するエミュレータ、 ELF はビルドでできる実行ファイルの形式です。

サンプルコードは 1 行も変えません。実機向けのビルドとの違いは、Arduino コア 公式のフラグ -D NO_USB を足すことだけです(理由は後述)。

注釈

ブラウザ版はインストール不要です。 後半の「必要なもの」から先の、PC で動かす手順は、 PlatformIO で動かす(本書の標準環境) と OS 別のページ(Windows での開発・Linux での開発・macOS での開発)で環境を整えてあることが前提です。 そちらを済ませてから戻ってきてください。

Tip

インストールなしで、まずブラウザで試せます。 各章のファームウェアを ブラウザの中の QEMU(WebAssembly 版)で動かすページを用意しました。 PC に何も入れずに、LED の点滅やシェルを触れます。自分で書き換えてビルドした firmware.elf も動かせます(自分でビルドした ELF を動かす)。

ブラウザで動かす

ブラウザ版の QEMU は命令をインタプリタで実行するため、タイマや点滅は実時間 どおりですが、重い計算は実機より遅くなります。本文の出力と細かく比べるときは、 以下の手順で PC に入れたものか実機を使ってください。

注釈

本書のカーネルが使うのは SysTick・PendSV・NVIC・MPU といった Cortex-M の 標準機能です(いずれも本文で順に出てきます)。エミュレータ上でもこれらは実機と同じように動き、第6章の フォールト(ゼロ除算・不正アドレス)も本文どおりに起きます。

ブラウザで動かす#

ブラウザで動かす

ページを開くと、各章のファームウェア(pio run -e sim でビルドしたもの)が ブラウザの中の QEMU で動き出します。章は上の一覧で切り替えます。シェルのある章は、 画面下の入力欄にコマンドを打てばそのまま動きます。

自分でビルドした ELF を動かす#

サンプルを書き換えたら、ビルドしてできた firmware.elf をブラウザ版に渡すだけで、 書き込まずに動きを確かめられます。ここでは 00_intro のメッセージを書き換えてみます。

  1. 00_intro/src/main.cpp の Environment OK! を、好きな文に書き換えます (下の GIF では sed で Hello from my build! に置き換えています)。

  2. ビルドします。書き込み(-t upload)は要りません。

    pio run -d 00_intro
    

    できた ELF は 00_intro/.pio/build/uno_r4_wifi/firmware.elf にあります。

    ../_images/sim_upload_build.gif

    メッセージを書き換えてビルドし、firmware.elf ができたところ#

  3. ブラウザ版を開き、章の一覧の最後の 「自分でビルドした ELF を動かす…」 を選びます。

  4. 出てきた欄に firmware.elf をドロップします(欄をクリックしてファイルを選んでも同じです)。

  5. Serial monitor に書き換えたメッセージが出て、LED マトリクスに「OS」が出れば成功です。

    ../_images/sim_upload_run.gif

    ビルドした firmware.elf をドロップすると、書き換えたメッセージが出る#

注釈

  • UNO R4 WiFi 向けのふつうのビルドがそのまま動きます。 Arduino の boards.txt は UNO R4 WiFi に -DNO_USB を付けていて、Serial は元から UART です(pio run と pio run -e sim の ELF はまったく同じものになります)。

  • ファイルはブラウザの中だけで使われ、どこにも送られません。

  • 選べるのは .elf だけです(.bin や .hex は使えません)。UNO R4 Minima 向け のように Serial を USB で出すビルドは、エミュレータに USB が無いのでシリアルが 出ません(ページに注意が出ます)。

  • 章を切り替えるとページが読み込み直されます。動かし直すときは、もう一度 「自分でビルドした ELF を動かす…」を選んでください。

ブラウザ版の制限#

  • 速さは実機の約 1/10 です。 タイマや点滅は実時間どおりに進みますが、重い計算は 遅くなります。第4章の Heavy タスクはほとんど進まず、第9章の ps の CPU% は 合計が 100% を少し超えることがあります(ページにも注意が出ます)。

  • 起動が終わる前に打った文字は失われます。 プロンプト(> など)が出てから 打ってください。

本文の出力と細かく比べるときは、以下の手順で PC に入れたものか実機を使ってください。

必要なもの#

入手先

QEMU(UNO R4 対応版)

iory/qemu-arduino-uno-r4

Python 3.10 以降

標準ライブラリのみ使用(pip install は不要)

PlatformIO

PlatformIO で動かす(本書の標準環境) と同じもの

本家の QEMU には UNO R4 のマイコン(Renesas RA4M1)が入っていないので、 それを足したものを本書用に配布しています。Homebrew や apt で入る qemu-system-arm では動きません。

QEMU のインストール#

リリースページから OS に合ったファイルを取ってきて、ホームの qemu-unor4 フォルダに展開するだけです。この場所に置けば、仮想ボードが自動で見つけます。

Apple Silicon(macOS 14 以降)と Intel Mac(macOS 15 以降)に対応しています。

mkdir -p ~/qemu-unor4 && cd ~/qemu-unor4
arch=$(uname -m)   # arm64 か x86_64
curl -fLO "https://github.com/iory/qemu-arduino-uno-r4/releases/download/v11.1.1-unor4.5/qemu-arduino-uno-r4-v11.1.1-unor4.5-macos-$arch.tar.gz"
tar xzf qemu-arduino-uno-r4-*-macos-*.tar.gz --strip-components=1
~/qemu-unor4/bin/qemu-system-arm --version

必要なライブラリは同梱しているので、Homebrew は要りません。

ブラウザでダウンロードした場合は、macOS が「開発元を検証できない」として 起動を止めます。展開したフォルダで一度だけ次を実行してください。

xattr -dr com.apple.quarantine ~/qemu-unor4

macOS 15 に上げられない古い Intel Mac では、後述の Renode を使ってください。

x64 版と ARM64 版(Snapdragon X など)があります。Windows on ARM では 必ず ARM64 版を使ってください。 x64 版はエミュレーション経由では動きません。

PowerShell で:

$arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'arm64' } else { 'x86_64' }
$name = "qemu-arduino-uno-r4-v11.1.1-unor4.5-windows-$arch"
Invoke-WebRequest "https://github.com/iory/qemu-arduino-uno-r4/releases/download/v11.1.1-unor4.5/$name.zip" -OutFile "$name.zip"
Expand-Archive "$name.zip" -DestinationPath "$HOME\qemu-unor4"
& "$HOME\qemu-unor4\$name\bin\qemu-system-arm.exe" --version

必要な DLL は bin に同梱しています。

x86_64 版と arm64 版があります(glibc 2.35 以降、Ubuntu 22.04 相当以降)。 ただし本書のビルドに使う PlatformIO のコンパイラが Linux arm64 向けには 配布されていないため、章をビルドできるのは x86_64 だけです (Raspberry Pi の 64 ビット OS なども同じです)。

mkdir -p ~/qemu-unor4 && cd ~/qemu-unor4
arch=$(uname -m); [ "$arch" = aarch64 ] && arch=arm64
curl -fLO "https://github.com/iory/qemu-arduino-uno-r4/releases/download/v11.1.1-unor4.5/qemu-arduino-uno-r4-v11.1.1-unor4.5-linux-$arch.tar.gz"
tar xzf qemu-arduino-uno-r4-*-linux-*.tar.gz --strip-components=1
~/qemu-unor4/bin/qemu-system-arm --version

使うライブラリは glib だけで、ほとんどのディストリビューションに最初から 入っています。無い場合は sudo apt install libglib2.0-0 です。画面は使わない ので、DISPLAY の無い環境(SSH 越しなど)でもそのまま動きます。

動かす#

cd code/04_scheduler
uv run pio run -e sim                # シミュレータ用にビルド
uv run python ../sim/board.py --chapter .  # 仮想ボードを起動

ブラウザで http://127.0.0.1:8080 を開くと基板が表示されます。終了は Ctrl-C です。 (localhost でも開けますが、Windows では IPv6 を先に試すぶん表示が数秒遅れます)

../_images/sim_browser.jpg

第7章の改良版 07_led_matrix_v2 を動かし、シリアルモニタに ps と打ったところ。 上が基板、下がシリアルモニタです。マトリクスの横棒と ps の CPU% は同じ値を表しています。#

Windows では python3 ではなく python と打ってください。

QEMU を qemu-unor4 以外の場所に置いた場合は、--qemu でその qemu-system-arm(Windows は qemu-system-arm.exe)を指定するか、 環境変数 QEMU に場所を入れておいてください。

画面の見かた#

  • 12×8 LED マトリクス — Arduino_LED_Matrix が実機で走査しているフレーム バッファ(12 バイト)をそのまま読んで光らせています

  • L (D13) — ポートレジスタ PCNTR1 の出力ビットを読んでいます

  • シリアルモニタ — 双方向です。入力欄にコマンドを打てば、第5章以降の シェルや第11章の TinyPython がそのまま使えます

第1章は実機と同じく起動時に S の入力を待ちます。入力欄に S と打って ください。

../_images/sim_d13.gif

第2章のサンプルで、内蔵 LED「L」(D13)が点滅する様子(D13 のまわりを拡大)。#

../_images/sim_matrix_kill.gif

第7章の改良版 07_led_matrix_v2。マトリクスの横棒は CPU の使用率で、12 個で 100% です。 いちばん上の 2 行が CPU 全体、1 行あけて下の 5 行がタスクごと(上から LED・Light・Heavy・Shell・Display)です。 kill 3 で重い計算のタスク(Heavy)を止めると、Heavy の行が消えて全体の棒が縮み、 exec 3 で元に戻ります。#

章ごとの対応#

章

シミュレータ

第0章〜第11章、応用編 1〜3

✅ 動きます

第12章(ハードウェア)

❌ センサ・アクチュエータの実物が必要です

第13章(四脚ロボット)

❌ サーボとロボット本体が必要です

応用編 4(ファイルシステム)

❌ Renesas FSP のフラッシュドライバが必要です

実機との違い#

ここだけは実機と違います。本文の説明と食い違う場面があるので、 気づいたときはこの節を思い出してください。

  • Serial が USB ではなく UART になります エミュレータには USB が実装されていないため、-D NO_USB で Serial を ハードウェア UART(SCI9)に切り替えています。UNO R4 WiFi の Serial が USB CDC(USB をシリアルポートとして見せる標準の方式)であること自体は本書で扱う話題なので、そこは実機で確かめてください。

  • ESP32 / Wi-Fi はありません UNO R4 WiFi のもう 1 つのチップは載っていません。

  • 時間の進み方は近似です 命令 1 つを 16 ns(≒ 48 MHz)として時間を進めています。タスク切り替えの 周期や CPU 使用率の傾向は追えますが、命令ごとのサイクル数や割り込みの ジッタは本物ではありません。リアルタイム性の最終確認は実機で行ってください。

  • 本書で使わない周辺回路はありません タイマ(AGT)・シリアル(SCI)・GPIO・割り込みコントローラ以外 (ADC、I²C、SPI、PWM 用のタイマなど)は入っていません。

注釈

動作確認は macOS 26 (Apple Silicon)・Windows 11 (ARM64)・ Ubuntu 24.04 (x86_64) で行っています。加えて GitHub Actions で、macOS (Apple Silicon / Intel)・Windows(x64 / ARM64)・Ubuntu(x86_64)の 5 環境で、この付録の手順どおりに全章を毎週確かめています。うまくいかない場合は Issues で教えてください。

うまくいかないとき#

「ファームウェアが見つかりません」と出る

pio run -e sim を実行しましたか。実機向けの pio run だけでは、 エミュレータ用のビルド(.pio/build/sim/firmware.elf)ができません。

「arduino-uno-r4 マシン入りの qemu-system-arm が見つかりません」と出る

探した場所と、それぞれがダメだった理由が一緒に表示されます。QEMU を ホームの qemu-unor4 に展開したか、--qemu が展開した qemu-system-arm を 指しているか確認してください。Homebrew や apt で入れた本家の QEMU では 動きません。 macOS で「開発元を検証できない」と出た場合は、上の xattr を実行してください。

シリアルに何も出てこない

章によっては入力待ちで止まっています(第1章は S、第5章以降はシェルの プロンプト)。

ポートが使用中

--http-port / --monitor-port / --uart-port で番号を変えられます。

PC が重い・ファンが回り続ける

board.py を kill -9 などで強制終了すると、QEMU だけが残って動き続ける ことがあります(Ctrl-C や端末を閉じた場合は自動で止まります)。 macOS / Linux は pkill -f qemu-system-arm、Windows はタスクマネージャーで qemu-system-arm.exe を終了してください。

章の確認を自動で走らせる#

本書の検証スクリプトは、実機の代わりにエミュレータでも走ります。 期待値は本文の「期待される出力」から起こしたものと同じです。

cd code
uv run python scripts/verify_chapters.py --sim
uv run python scripts/verify_chapters.py --sim --only 05_shell

code/sim/record.py を使うと、基板の光り方をそのまま GIF に録れます。

Renode を使う場合#

QEMU の代わりに、オープンソースのエミュレータ Renode (1.17 以降)でも同じ画面が動きます。macOS 15 に上げられない Intel Mac では こちらを使ってください。 Renode は RA4M1 を最初から持っているので、公式のリリースをそのまま使えます。

  • macOS: brew trust renode/tap && brew install renode/tap/renode (brew trust を先に実行しないと untrusted tap で止まります)

  • Windows: renode-*.setup.exe(Windows on ARM でも x64 エミュレーションで動きます)

  • Linux: renode-*.linux-portable.tar.gz を展開(.NET 同梱)

いずれも renode/renode から入手できます。 起動するときは --emulator renode を付けます。

uv run python ../sim/board.py --chapter . --emulator renode
uv run python ../sim/board.py --chapter . --emulator renode --renode /path/to/renode  # PATH に無いとき

検証スクリプトも --emulator renode で Renode を使います。

QEMU との違いは、第6章のフォールトが起きないことです。 Renode は CCR.DIV_0_TRP を実装していないためゼロ除算で UsageFault に ならず、未マップ領域への書き込みでも BusFault を上げません。「壊れたタスク だけが死んで他は動き続ける」ことは観察できますが、FAULT DETECTED の表示と 原因の特定は見られません(検証スクリプトでは SKIP になります)。

Renode が残って動き続けたときは pkill -f Renode(Windows は Renode.exe を終了) で止めてください。

仕組みを知りたい#

code/sim/README.md に、どのアドレスから何を読んでいるか、ブラウザへ どう流しているかを書いています。仮想ボード本体(board.py と board.html)は 600 行ほどです。QEMU 側の実装(RA4M1 の割り込み コントローラ・SCI・AGT・GPIO)は iory/qemu-arduino-uno-r4 にあります。