第6章 外部接続 ― microSDカードと無線モジュール(ESP)
前章で、私たちのSoCは世界と言葉を交わす「神経」(UART・SPI・I2C)を得ました。本章では、その神経の先に二つの実用機能をつなぎます。記憶(microSDカード)と、ネットへの声(技適済み無線モジュール)です。フィジカルAIの身体に、覚える力と、外に呼びかける力を与える章だと思ってください。
そして本章には、うれしい特徴があります。新しく調達するIPはゼロだということです。microSDは「SPIで話せる記憶装置」、無線モジュールは「UARTで話せるネットの出口」――どちらも前章で現物確認を済ませた simple_spi と simpleuart の再利用で届きます。本章で新しく学ぶのは「IPの調達」ではなく、既存の部品をどう組み合わせ、どんなソフトで動かすかです。
┌──────────── 我々のSoC(FPGA / Basys 3)=「身体」────────────┐
│ PicoRV32 ── Wishbone ──┬── spi_wb (simple_spi 再利用) ──SPI──→ microSD(記憶)
│ │ CS=GPIO
│ └── uart_wb(simpleuart 再利用) ─UART─→ 技適済みESPモジュール
└──────────────────────────────────────────────────────────┘ │
(2.4GHz)→ AP → Internet(声)
6.1 この章の地図 ― 記憶と声を、既存の神経でつなぐ
設計判断の軸はシンプルです。「その機能に、いちばん簡単で確実な既存の道はどれか」。記憶については、USB大容量ストレージ(=USBホストが要る)とmicroSD(=SPIで足りる)を比べれば、後者が圧倒的に簡単で確実。声については、自前で無線を作る(=物理と電波法の壁)とモジュール外付け(=UARTで足りる)を比べれば、後者。どちらも「既に持っている神経の再利用」に落ちます。
6.2 microSDは、実はSPIである
理由から。microSDカードには「SPIモード」という簡易接続が用意されていて、私たちから見ればただのSPIデバイスになります。USB経由のストレージがUSBホストという難所を要求するのに対し、SDのSPIモードは第5章で作ったSPIマスタにそのまま乗ります。これが「簡単で確実」の中身です。
USBストレージなら
FPGA側にUSBホスト(USB1.1・要自前ドライバ・外部PHY)。難所そのもの。今回は採らない。
microSD(SPIモード)なら
SPIマスタ+CS+ソフト。SPIマスタは第5章で調達済み。新規RTLゼロ。3.3VでPmodと電圧も合う。
6.3 simple_spi の再利用+CS(GPIO)でSDをつなぐ
具体です。必要なのは三つだけ。(1) SPIマスタ=simple_spi(第5章の spi_wb ラッパごと再利用)、(2) チップセレクト=第3章のGPIOの1ビット(simple_spi はSS線を持たないため、これは第5章で確認済みの定石)、(3) 物理結線=SD側の CLK / CMD / DAT0 を SPIの SCK / MOSI / MISO に対応づけ、Pmod経由で3.3V接続。
SoC側(再利用) microSD(SPIモード) ───────────────────────────────────────────── spi_wb.sck_o ─────────→ CLK spi_wb.mosi_o ─────────→ CMD (DI) spi_wb.miso_i ←───────── DAT0 (DO) gpio_out[0] ──(CS)───→ DAT3 (CS) ※CSはGPIOで叩く 3.3V / GND ─────────→ VDD / VSS ※Pmod経由
// soc_top.v ― 第6章で増える外部接続の“組み合わせ図”(骨格・未検証)
// 新規IPはゼロ。第5章で裏取り済みの spi_wb / uart_wb を再利用して足すだけ
module soc_top ( /* clk, rst, 各ピン … 省略 */ );
// (既存)CPU(picorv32_wb)・RAM・GPIO・タイマ・PWM・spimemio … 第2〜4章
// --- microSD:simple_spi(spi_wb) の再利用。CS は GPIO の1ビットで駆動 ---
spi_wb sd_spi (
.wb_clk_i (clk), .wb_rst_i (rst),
.wb_adr_i (adr), .wb_dat_i (wdat), .wb_dat_o (sd_rdat),
.wb_we_i (we), .wb_stb_i (sd_sel), .wb_cyc_i (cyc), .wb_ack_o (sd_ack),
.sck_o (sd_sck), .mosi_o (sd_mosi), .miso_i (sd_miso)
);
assign sd_cs_n = gpio_out[0]; // CS は GPIO(第3章)で駆動
// --- 無線モジュール:simpleuart(uart_wb) の再利用。TX/RX はクロス結線 ---
uart_wb esp_uart (
.wb_clk_i (clk), .wb_rst_i (rst),
.wb_adr_i (adr), .wb_dat_i (wdat), .wb_dat_o (esp_rdat),
.wb_we_i (we), .wb_sel_i (sel), .wb_stb_i (esp_sel),
.wb_cyc_i (cyc), .wb_ack_o (esp_ack),
.ser_tx (esp_tx), .ser_rx (esp_rx) // SoC.TX → ESP.RX / ESP.TX → SoC.RX
);
endmodule
6.4 SDを動かすソフトの考え方(RISC-V側の仕事)
ここからはRTLでなくソフトの役割分担です。SDカードは「SPIでコマンドを送ると応答する」装置なので、PicoRV32上のソフトがコマンド列と、その上のファイルシステムを担います。考え方の地図だけ示します(具体のコマンド表・タイミングは使うカードで現物確認)。
- 初期化。 カードを起こし、SPIモードに入れ、種別(SDHC等)を判定する一連のコマンド(
CMD0でアイドル化 →CMD8で電圧確認 → 初期化完了待ち → 必要に応じブロック長設定)。 - 読み書き。 1ブロック読み(
CMD17)/書き(CMD24)を基本に、セクタ単位でやり取りする。 - ファイルシステム。 その上に FATファイルシステムを載せれば、PCと同じ感覚でファイルとして読み書きできる。組込みでは FatFs のような定番の実装を移植して使うのが普通(ライセンスは採用時に現物確認)。
6.5 技適済み無線モジュールは、UARTである
声の側です。第5章5.7で「有線でネット越しAI(API)と連携」の考え方を置きました。それを実装に落とすのが、技適済みの無線モジュール(ESP系など、UARTで話せるもの)の外付けです。私たちのSoCが「このサーバにこれをPOSTして」とテキストで頼み、モジュールが無線とTCP/IPを代行する――旗印「ボード=身体、頭脳=ネット越し」そのものです。
6.6 simpleuart の再利用でモジュールをつなぐ
結線は単純で、SoCのTXをモジュールのRXへ、モジュールのTXをSoCのRXへ(クロス)、あとはGND共通と3.3V系の電圧確認だけです。SoC側は uart_wb(simpleuart)をもう一つインスタンス化するだけ――新規RTLはありません(上の soc_top.v 骨格を参照)。
SoC側(再利用) 無線モジュール その先 ─────────────────────────────────────────────────────────── uart_wb.ser_tx ───────────→ RX uart_wb.ser_rx ←─────────── TX 3.3V / GND ───────────→ VDD / GND (2.4GHz)→ AP → Internet
ソフトの考え方は、モジュールへテキストのコマンドを送り、応答を読むという対話です(いわゆるATコマンド方式が手軽)。「アクセスポイントに接続」「接続先を開く」「このデータを送る」を順に頼めば、Webhook(HTTP POST)やMQTT(pub/sub)に届きます。これは第5章5.7で示した上位プロトコルの考え方の、実体側の足です。
設計ノート:なぜ「2つ目のUART」を足すだけで済むのか/なぜ1つ目を残すのか
第5章で simpleuart を Wishbone スレーブ(uart_wb)として一度仕上げました。無線モジュールをつなぐ本章で必要なのは、その uart_wb を「もう一つ」置くことだけです。中身は1ビットも変えません。番地(0x8)だけを変えて二度目の実体化をする――これがハードウェアにおける部品の再利用の最小かつ典型の姿です。ソフトで同じ関数を引数違いで二度呼ぶのと同じ感覚を、RTL でも持てる、ということです。
1つ目のUART(コンソール)を、なぜ残したままにするのか。 本章のデモは無線用の2つ目(0x8)しか使いません。ならば1つ目(0x6)を外して構成を小さくしてもよさそうですが、あえて残します。理由は二つ。第一に再利用の物語の一貫性――1つ目を残したまま2つ目を足すと、第5章のSoCと本章のSoCの違いが「UARTが一つ増えただけ」になり、図がそのまま「もう一本生やす」像と重なります。逆に1つ目を消すと「1つ目はどこへ消えた?」となり、再利用の物語が崩れます。第二に番地の一貫性――コンソールUART(0x6)は第5章からの住人で、番地表に空席を作らず据え置くのが混乱を生まない素直なやり方です。学ぶ人が設計図を素直に読めること、を部品点数の最小化より優先しました。
番地表は動かさない、という約束。 メモリマップは上位4ビットで住み分ける約束で M1 から一貫しています(0x0RAM/0x1LED/0x2GPIO/0x3TIMER/0x4PWM/0x5Flash/0x6UART/0x7SPI/0x8UART2)。新機能を足すときも既存番地は動かしません。動かせば本文・図・C言語の #define・テストベンチの照合値まで一斉にズレて学ぶ人を惑わせます。本章で無線を足すのも0x8 を1枠だけ増やす操作で、0x0〜0x7 は不変です。
6.7 旗印コラム ― いつかRF以外を自前で:Ethernet MAC内蔵という現実的な夢
「無線モジュールごと、自分のRISC-V SoCで作れないのか」――尖った夢です。正直に分解すると、ESP相当は三つの層からできています。どこまでが自前で届き、どこからが壁かを、誇張せず色分けします。
① MCU層(RISC-Vコア)
作れる・もう作っている。 ESPのCPUに当たる部分は、まさにPicoRV32でやっていること。ここは夢でなく現在地。
② プロトコル層(TCP/IP)
射程内。 軽量TCP/IPスタック(LwIP等)をRISC-V上で動かすのはあり得る。相応の外部RAMが前提(MicroPython移植と同じ条件)。
③ 無線層(RF/PHY)
ここが本当の壁。 2.4GHzのアナログRF・変調復調・PA・アンテナ整合はFPGAのデジタル論理では作れない。さらに電波を出す=技適が正面に立つ。
6.8 【確認】この章の最小確認
再利用した二つの神経を、シミュ→FPGA実機の順で確認します。このうちシミュ(専用ビルド工程 M5)は完了しています(実測ログは下記)。FPGA実機は[改訂マーカー]として残します。
- microSD(FPGA)。 spi_wb+GPIOのCSでカードを初期化し、1ブロック書いて読み戻し、一致を確認。さらにFAT経由で小さなファイルを1つ読み書き。
- 無線モジュール(FPGA)。 uart_wb経由でモジュールへコマンドを送り、応答を受け、アクセスポイントへ接続。
- 結合(FPGA)。 SDから読んだ1行を、モジュール経由でサーバへ POST(Webhook) する。記憶(SD)→声(無線)→ネットの一気通貫を達成。
0xA5→0x5Aで送受双方向を最小実証)、無線ダミーは1バイト受けると合図に 'O'(0x4F)を返す相手。本物のSD初期化(CMD0…)やATコマンド対話・技適は、規格やカード・モジュールの版で揺れるため、ここでは扱わず実機と一次情報で詰めます(断定回避)。ダミーは「配線と道筋が正しいこと」を保証し、本物固有の作法は実機に委ねる――この線引きが、誇張せず実用に着地させる本講座の流儀です。
検査1 結合往復 gpio_out=0x5a4f -> OK ← 上位0x5A=microSD応答 / 下位0x4F=無線応答('O')
検査2 signature LED=0x5a -> OK
==== RESULT: PASS ==== (cycle=6026)
上位バイトが microSD からの応答(0xA5→0x5A の反転)、下位バイトが無線からの応答('O'=0x4F)。二つを別々に照合し、両方そろって初めて PASS とすることで「たまたま一致」を避けています。記憶(microSD)と声(無線)の両方が、既存の神経の再利用だけで届いたことの確認です。Icarus Verilog による検証で、CPUは外部Flashから起動(XIP)し、SPIとUART2の往復が成立しています。
これで身体は、覚える力(microSD)と外へ呼びかける力(無線モジュール)を得ました。第5〜6章で作った「神経」は、いずれも有線か、有線扱いの外付けで固めてあります。次章はその外付けを支える法の話――技適(電波法)の扱いを、断定を避け、一次情報へ誘導しながら正直に見ていきます。