← 講義ポータルへ戻る 第7回・第8回講義:外部メモリを調達する

第4章:外部メモリ ― SPI Flash/RAM で「非力さ」を脱する

第3章までで、自作の周辺(GPIO・タイマ・PWM)をWishboneに足しました。本章からは、いよいよ外部の他人のIP(既製IP)を調達して組み込む段に入ります。最初の題材は外部メモリ。序章の先輩比較表で見たとおり、CH32V003はRAM 2KB/Flash 16KBと、メモリが大きな弱点でした。本章では、外部のSPI FlashとRAMを実装し、この「非力さ」を正面から脱します。そしてこれは、後のMicroPython移植(第11章)の土台にもなります。

4.1 なぜ外部メモリが要るのか

マイコンの「窮屈さ」は、たいていメモリの少なさから来ます。プログラムが大きくなればFlash(不揮発の置き場)が足りなくなり、扱うデータが増えればRAM(作業場)が足りなくなります。FPGA内蔵のメモリ(BRAM)だけでは、すぐ頭打ちです。そこで、チップの外に大きなメモリを置いて、バス越しに使うのが定石です。

外部SPI Flash(プログラムの置き場)

不揮発(電源を切っても消えない)で、安価にMB級の容量。プログラム本体を置きます。CH32V003の16KBに対し、外部Flashなら桁違いの大きさを確保できます。

外部RAM(広い作業場)

揮発するが高速で、大きなデータ・ヒープを扱えます。MicroPythonのような「実行時にメモリを多く使う」ソフトを載せるには、ここが効いてきます。

★鍵となる仕組み「XIP(その場実行)」: 外部Flashの嬉しい使い方が XIP(eXecute In Place)です。これは、Flashの中身をCPUのメモリ空間に直接マップし、Flashから命令を読みながらそのまま実行する仕組み。いちいちRAMへコピーしなくても、大きなプログラムを外部Flashに置いたまま動かせます。先輩マイコンが「大きなプログラムを動かせる」のは、この仕組みのおかげです。本章で調達するIPは、まさにこれを実現します。

4.2 【IP調達・実演】SPI Flashコントローラを調達する

では、序章の7ステップで外部SPI Flashコントローラを調達します。今回は「他人が書いた既製IP」を相手にする初めての回。現物確認(ステップ4)の重みが、ぐっと増します。

   IP調達ワークフロー:SPI Flashコントローラ
 ───────────────────────────────────────────────────────────────
   1. 要求を言語化   ・外部SPI FlashからXIP(その場実行)できる
                     ・PicoRV32エコシステムと相性が良い
                     ・実績がある(枯れている)/組み込み可能なライセンス
                     ・できればQSPI(高速)にも対応
   2. 探索先         PicoRV32公式に付属する PicoSoC(公式の参照SoC), GitHub
   3. 候補を絞る     PicoSoC同梱の spimemio を第一候補(公式・同作者・実績)
   4. 現物を確認     公式リポジトリの picosoc/spimemio.v を開いて確認(次項4.3で詳述)
   5. 採否を判断     採用。ただし「接続の方言」に統合上の課題あり(後述)
   6. 統合           我々のWishboneに載せる工夫が要る(4.4)
   7. 検証           付属の spiflash.v(シミュ用Flashモデル)でTB → FPGAで実機確認

4.3 【現物確認】spimemio を開いて分かったこと

ステップ4で現物を確認したところ、採用に値する長所と、見過ごせない統合上の注意点の両方が見えました。正直に両方記します。

長所(採用の理由)

PicoRV32と同じ作者(Claire Xenia Wolf)・同じISCライセンス。公式の参照SoCに組み込まれた実績あるコントローラで、外部FlashからのXIPに対応し、高速なQSPIモードも持ちます。Flashをメモリ空間にマップして直接実行できます。

注意点(統合の課題)

spimemio は、PicoSoCの中でPicoRV32の「素のメモリI/F」に直結する前提で書かれています。Wishboneのスレーブとしては書かれていません。我々はWishbone主バスを選んだので、ここに「方言の違い」が生じます。

※これこそ「現物を開く」価値です(実験ログ): 「PicoRV32用のSPI Flashコントローラがある」という情報だけなら、AIや記事からも得られます。しかし実際にファイルを開かなければ、「それが素のI/F前提で、Wishboneではない」という肝心の事実は分かりません。もし現物を見ずに「Wishboneに挿すだけ」と思い込んで設計を進めたら、後で大きな手戻りになっていたはずです。釣った魚は、料理の前に必ず捌いて中を確かめる――7ステップのステップ4が要である理由が、ここにはっきり表れています。

※同じことが simpleuart にも言えます(先回りのメモ): 現物を見るついでに、PicoSoCのUART(simpleuart)も確認しました。こちらも同様に素のI/F前提でした。つまり「PicoSoCの周辺を我々のWishbone SoCに迎えるときは、方言の橋渡しが要る」という共通のパターンが見えてきます。これは第5章(UART調達)でも効いてくる、重要な気づきです。

4.4 統合の設計判断 ― 方言の橋をどう架けるか

採用は決めました。残るは「素のI/F方言で書かれた spimemio を、Wishbone主バスのSoCにどう載せるか」という設計判断です。ここは勝手に決めず、選択肢を並べて、考え方を示します。

案A:Wishboneスレーブで包む

spimemio を、第3章で作ったWishboneスレーブの型でラップし、バスに1つの部品として挿す。SoC全体がWishboneで統一され、見通しが良い。橋(ラッパ)を1枚書く手間がかかる。

案B:メモリ経路だけ素I/Fにする

命令フェッチの経路(Flash+RAM)はPicoSoC流に素のI/Fで組み、その他の周辺だけWishboneにするハイブリッド。XIPの性能は出しやすいが、SoCに2つの作法が混在し、複雑になる。

※本章の推奨と、確認のお願い(設計判断): 本講座は「Wishboneで統一して見通しよく学ぶ」ことを重んじてきました。その方針に沿うなら案A(Wishboneスレーブで包む)が素直です。XIPの最高速を狙う本格用途では案Bも有力ですが、まずは学びやすさ優先で案Aを推します。ただしこれは性能にも関わる設計判断なので、案A/案Bのどちらで進めるかは、著者の確認をいただいてから確定します(勝手に決めません)。決まり次第、ラッパの完全コードは検証込みの専用工程で用意します。

4.5 メモリマップを更新する

外部メモリが加わるので、第2章で作ったメモリマップを更新します。プログラムは外部Flashに置き、作業用の小さなRAM(FPGA内蔵BRAM)を速い領域として用意する――これはPicoSoCでも使われている、理にかなった構成です。

   メモリマップ(外部Flash統合後・上位ニブル adr[31:28] で住み分け)
 ───────────────────────────────────────────────────────────────
   0x0000_0000 〜   RAM(BRAM・小さな高速作業場:スタック/データ専用)
   0x1000_0000 〜   LED(第3章)
   0x2000_0000 〜   GPIO(第3章。+0 出力 / +4 入力)
   0x3000_0000 〜   タイマ(第3章。+0 リロード / +4 ステータス)
   0x4000_0000 〜   PWM(第3章。+0 デューティ)
   0x5000_0000 〜   外部SPI Flash(XIP・本章で調達)★リセットベクタ PROGADDR_RESET=0x5000_0000
   0x6000_0000 〜   UART(第5章で調達)   ← 以降は後章で席を予約
   0x7000_0000 〜   SPI (第5章で調達)
   0x8000_0000 〜   UART2(第6章・無線モジュール用)
   ───────────────────────────────────────────────────────────────
   ※ 上記は専用ビルド工程でシミュ検証済みの割り当て。実機での最終確認は[改訂マーカー]。

※リセットベクタの設計(シミュ検証済/実機確認は改訂マーカー): PicoSoCでは、リセット直後にCPUが最初に実行する番地(リセットベクタ)をFlash内のある位置に置いていました。第1章で見たパラメータ PROGADDR_RESET を、この位置に合わせます。専用ビルド工程では、外部Flash領域の先頭 0x5000_0000 をリセットベクタとして XIP 起動することをシミュレーションで確認済みです(実機での最終確認は[改訂マーカー])。

4.6 外部RAM ― 広い作業場をどう持つか

大きなデータや、将来のMicroPythonのために、外部RAMも視野に入れます。ただしここは正直に線を引きます。Basys 3 には、すぐ使える大容量の外部RAMは載っていません(あるのはFPGA内蔵のBRAMです)。大きな外部RAMが欲しい場合は、Pmod経由でPSRAM等を増設するか、最終的な基板化(第14章)で実装する、という段取りになります。

※外部RAMコントローラのIPは、必要になった段で7ステップで(誇張を避ける): 外部RAM(PSRAM/HyperRAM等)を制御するIPにも、オープンソースの選択肢があります。ただし具体的にどれを使うかは、現物確認(実在・対応バス・ライセンス・成熟度)を経て決めるべきで、いま固有名を断定はしません。本講座では、まず内蔵BRAMの小さなRAM+外部Flashのプログラムで土台を作り、より大きな外部RAMはMicroPythonを本格的に載せる段(第11章)や基板化(第14章)で、改めて7ステップで調達します。「RAMが要る」と「このIPを使う」の間には、必ず現物確認を挟みます。

4.7 【確認】外部Flashから、プログラムを直接実行する

本章のゴールは、「外部SPI Flashに置いたプログラムが、XIPでそのまま動く」ことの確認です。検証は、序章の段階どおりに進めます。幸い、調達した spimemio にはシミュレーション用のFlashモデル(spiflash.v)が付属しているので、実物のFlashが手元になくても波形で確かめられます。

  1. 統合: 4.4で確定した方式(案A/案B)で、spimemio をSoCに組み込む。
  2. シミュレーション: 付属の spiflash.v をFlashの代役に使い、CPUが外部Flashから命令を読み出して実行する様子を波形で確認(第12章で本格化)。
  3. FPGA(Basys 3): Pmod経由で実物のSPI Flashをつなぎ、プログラムを書き込んで、XIPで動くことを実機確認。
  4. 記録: 「先輩の16KBを、外部Flashで桁違いに超えた」――その到達を実験ログに残す。

4.8 この章のまとめ

外部メモリで「窮屈さ」を脱する道筋ができました。次の第5章では、いよいよ通信に踏み込みます。本章で見えた「PicoSoCの周辺は素I/F方言」という気づきを携えて、UART・SPI・I2C、そしてEthernetを調達し、Wishboneへ橋渡しします。Webhook/MQTTといった、ネット越しのAI連携につながる入口も見渡します。