8ピンチップ3個だけで作ったインタラクティブ速度のLinuxコンピュータ
(dmitry.gr)- 家庭で組み立て可能な最小コンピュータを目標に、Debian Linux、vi、gcc、makeが動作する8MB RAM・1 MIPS級システムを8ピン部品だけで実現
- 最終ボードは STM32G031、8MB SPI PSRAM、PL2303GL USB-シリアルブリッジの3チップで構成され、8ピンパッケージの制約のため使えるI/Oは6本しかない
- ピン不足は設計上の核心的な難題で、RAMは通常のSPI、SDカードはRAMピンを共有する 1-bit SDIO、UART送信はビットバンギングで処理
- ソフトウェアは既存のARMv6Mアセンブリベースの MIPSエミュレータ を再利用し、8KBブートローダがSDカードFATファイルシステム上のFIRMWARE.BINでファームウェアを更新
- STM32G031はVOS0設定で公称64MHzを超えてオーバークロックされ、148MHzのホストCPUで約1.65MHzのMIPS R3000相当としてDebianを約1分で起動
8ピンチップだけで作った最小Linuxコンピュータ
- 目標は、家庭で簡単に組み立てられる キット型の現代的コンピュータ を8ピンチップだけで作ること
- 現代的コンピュータの最小基準は、Debian Linux、vi、gcc、makeを実行できることとした
- 以前の実験をもとに、Linux実行に必要な最小仕様を 8MB RAM と 1 MIPS CPU に設定
- ストレージはSDカード、コンソール接続はUSB-シリアルを使用
- ボードは小型の円形で、上部にボードエッジの USB-Cコネクタ を備える
- はんだ付け経験がほとんどない人でも45Wのはんだごてで組み立てられるよう、部品数とピン数を削減
部品選定
- USB接続には PL2303GL を採用
- 外付け部品なしで動作するUSB-シリアルブリッジで、100mAの3.3Vレギュレータ出力も提供
- 主要OS向けドライバがあり、macOSではApp Storeからのインストールが必要
- 代替としてATTINYx5と V-USB を使ったUSB実装も検討
- USB low-speedは仕様上bulk endpointを使えないが、主要OSはこれを強制しないため、ACMシリアルポート実装は動作
- V-USBはCPU時間、フラッシュ、RAMを多く消費するため、このプロジェクトには負担が大きい
- RAMにはSOIC-8の SPI PSRAM を使用
- ISSI、APMEMORY、Vilsionなどが関連部品を製造しており、8MB品は一般流通で入手可能
- 16MBチップは複数社が約束したものの、実際には供給されていないと判断
- マイクロコントローラはPIC16F、RL78、PSoC1、eZ8、S08CPUv2、STM8、MSP430、AVR、PSoC4、MSPM0C、CH32V003、CH570E、STM32G0系列を比較
- 最終的な採用は STM32G031J4M6/STM32G031 系列
- Cortex-M0+コア、公称64MHz、32KBフラッシュ、8KB RAMを提供
- 8ピンパッケージで性能とメモリの面で他候補より有利だった
- STMチップのerrata文書の品質には懸念があったが、オンチップ周辺機能を最小限しか使わない設計なので採用可能だった
6本のI/Oピンに収めたハードウェア設計
-
コンソールUART
- UART RXとTXは他機能と組み合わせにくい
- RXを共有すると他の動作中に受信データを取りこぼす可能性があり、TXを共有すると短いlowパルスでもPC側では文字のように見えることがある
- このため、6本のI/Oのうち2本を UARTコンソール に割り当て
- 最終的なピン配置ではpin 8をUSART2 RXに使い、pin 7はUART TXを ビットバンギング で実装
- UART送信中は実行全体が停止するため、可能な限り高速な115,200bpsを使用
- 1文字の送信には約87マイクロ秒かかり、ボードは大半の時間で出力しないため、この方式は許容範囲
-
RAM接続
- SPI PSRAMはQSPIをサポートするが、QSPIには6本のピンが必要なため利用不可
- dual-SPIは追加ピンなしで通常のSPIより2倍高速にできる可能性があるが、STM32G031はdual-SPIをサポートしない
- CPUでdual-SPIをビットバンギングしても、ハードウェアSPIとDMAの組み合わせを上回るのは難しいと判断
- 結果としてRAMは 通常のSPI で接続され、この接続だけで残り4本のピンをすべて使用
-
SDカード接続
- SDカードをSPIモードで使うにはchip selectピンをもう1本必要とするが、残りピンがなかった
- RAM nCSをインバータで反転してSDカードのnCSに使う方法は一部カードで問題があり、追加部品も必要だった
- UART TXピンをローパスフィルタ付きでSD card nCSと共有する方法も検討したが、300bps以下のUARTが必要で、SDカードが遅い場合に脆弱だった
- 最終的な解決策は、SDカードの 1-bit SDIO プロトコルを直接実装すること
- RAM nCSはSD CLK、RAM CLKはSD CMD、RAM MOSIはSD DATと共有
- RAMアクセスはSDカード側からはidle状態の1ビットのように見え、SDアクセスはRAM側からは選択と解除を繰り返しているように見えるため、安全に動作
- ただし、SDトランザクションの途中にRAMアクセスを挟めないため、マルチブロック読み書き は使用不可
- STM32G031のピン配置上、ハードウェアデバイスでSDIOを使えないため、SDアクセスはすべてビットバンギングで実装
- アセンブリ実装は約14 CPU cycles/bitのスループットを出す
ブートローダとLinux起動フロー
-
エミュレータ
- 既存の LinuxCard プロジェクトの MIPSエミュレータ を再利用
- エミュレータはARMv6Mアセンブリで書かれており、Linuxを起動できた
- より高速な実行のためMIPS-to-ARMv6M JITも作成したが、コードサイズが46KBと大きすぎ、6KB変換キャッシュでも速度向上が十分でなかったため不採用
- STM32G031の32KBフラッシュは8KBブートローダと24KBメインコードに分割
-
ファームウェア更新用ブートローダ
- デバッグ用ピンを残せなかったため、SDカードからファームウェアを更新する ブートローダ が必要だった
- ブートローダにはSDIOドライバ、FATファイルシステムドライバ、フラッシュ書き込みコード、ロギング、ビットバンギングUART送信コードが含まれる
- 実サイズは約6.5KBだが、フラッシュブロック単位の都合で8KB領域を使用
- SDカード上で FIRMWARE.BIN を探し、基本チェックに合格し、かつバージョンが増えている場合に更新を適用
- アプリケーションイメージのoffset 16のwordをバージョン番号として使用
- ブートローダのoffset 8のbyteはブートローダバージョンで、メインアプリ起動時のテキスト表示以外には使わない
- ブートローダはFATファイルシステム上で名前がCLOCKで始まるファイルやディレクトリも探す
- 後続の数字をメインアプリケーションのクロック速度として使い、32〜200MHzの範囲外または値がない場合は132MHzを使用
-
カードパーティションとカーネル読み込み
- 起動フローはPCのブート過程に似せて構成
- SDカードの先頭セクタをRAM先頭に読み込んでジャンプ
- 第1段階コードはtype 0xBBパーティションを探して0x80001000にロードし、そこへジャンプ
- 第2段階ブートローダはactive指定されたパーティションをFAT16としてマウントし、VMLINUX ファイルをELFとしてロード
- カーネルコマンドラインはブートローダに埋め込み済み
- rootは
/dev/pvd3、initは/sbin/uMIPSinit /dev/pvd1は/bootへのマウントを試行- プロジェクトのパーティション順は、FATパーティション、ブートローダパーティション、rootfsの順
- WindowsとmacOSが先頭パーティションをマウントするため、FATパーティション経由でファイルを簡単に出し入れできる
- 起動後のLinuxでもこのパーティションは
/bootとして見える
性能とオーバークロック
- STM32G031の公称動作速度は64MHzだが、内部電圧設定を使ってより高いクロックを試行
- STM文書にはVOS2 1.0VとVOS1 1.2V設定があり、VOS1では約75MHz以上は安定しない
- 古い文書や類似チップの文書にある VOS0 1.35V 設定を使うと、オーバークロック余地が大きく広がる
- 大半のチップは136MHzで問題なく動作し、一部は180MHzまで到達
- フラッシュメモリ自体は高速化しないため、flash wait states を正しく管理する必要がある
- 148MHzのホストCPUで、エミュレートされたMIPS CPUはFPU無効時の約1.65MHz MIPS R3000に相当
- システムは約1分で起動し、vi、make、objdump、gccが動作
- 完全なDebianシステムなので、
.debパッケージを/bootに持ち込んでインストール可能
組み立てと初期起動
-
組み立て手順
- ボードを自作できるよう設計ファイルが提供されており、キット販売会社を探している
- 組み立てはSDカードソケット、コンデンサ、抵抗、STM32G031、PL2303GLの順に進める
- R101、R102、R201、R202は最初は実装しない
- まずSTM32にブートローダを書き込む必要がある
- R101とR201をブリッジしてROMブートローダ用のシリアル配線を構成
- SDカードは挿さず、RAMチップもまだはんだ付けしていない状態で進める
- ブートローダ書き込み後、R101/R201のブリッジを外し、R102/R202をブリッジ
- その後、APS6408またはVTI7064 RAMチップをU2位置にはんだ付けすればハードウェア組み立ては完了
-
ファームウェアと初回起動
- SDカードは最低1GB必要で、提供されたディスクイメージを書き込む
- イメージには第1段階MIPSブートローダ、第2段階MIPSブートローダ、Linuxカーネルとファームウェアのコピーを含むパーティション、Debian rootfsが含まれる
- FATパーティションに FIRMWARE.BIN を置くと、初回起動時にブートローダが自己フラッシュを実行
- シリアルターミナルは115,200bps、8N1に設定
- 初回実行時にはSTM32 fuseがプログラムされ、USB-Cケーブルを抜き差しする必要がある場合がある
- 約20秒後にLinuxカーネルの起動メッセージが始まり、全体の起動には約1分かかる
- RAMが8MBしかないため、最初のコマンドとして
swapon /swapfileの実行を強く推奨 - swap有効化には数十秒かかるが、その後はより多くのプログラムを実行できる
ダウンロードファイルと利用方法
- メインのダウンロードは uMIPS.8PL.zip
- アーカイブにはボード製作と実行に必要なファイルが含まれる
schematics: 回路図gerbers: 基板製造用ガーバーファイルsrcs: エミュレータとブートローダのソースbinaries/SD.img: SDカードに書き込むイメージBOOTLOADER.BIN: 組み立て中にチップへ書き込むブートローダFIRMWARE.BIN: ビルド済みファームウェアイメージ
- 起動後のデフォルトシェルは
shで、bashも実行可能 - RAM不足を避けるには、イメージに含まれるswapfileを
swapon /swapfileで有効にするのが望ましい - MCUを120MHzで動かす前提では、有効CPU速度は約1.5MHz
- 簡単なCプログラムでもgccでのコンパイルには数分かかるが、実際に動作する
- 例として、浮動小数点版と固定小数点版のMandelbrot生成器がソースとバイナリで提供される
- インストール済みツールにはvim、make、gccが含まれ、DebianパッケージはSDカードの共有FAT16パーティション経由で追加できる
1件のコメント
Hacker Newsの意見
SDIOの3本のピンとどのピンを兼用できるか検討した末に、RAMのnCSをSDカードのCLKに、RAMのCLKをSDカードのCMDに、RAMのMOSIをSDカードのDATに使うという解法にたどり着いた、という部分は本当に見事なハック
各デバイスとのあり得る相互作用を考えてみると、安全に動作するという点まで説得力があり、Hacker Newsに載るだけの価値は十分ある
USBと接続するために別チップを使う方式が基本の選択肢になるのを見ると、いつも少し残念に思う
USBはあまりに複雑なプロトコルなので、低速USB 1.1を動かす基本的なV-USBレベルを超えると、特殊なハードウェアとかなり大きなソフトウェアスタックなしではたいてい難しいように見える
一方でSPIはばかばかしいほど単純で、必要な最小限のハードウェアは十分高速なクロックを受けられるシフトレジスタ程度
昔のデスクトップやノートPCのように、外部に露出したシリアル/パラレルポートがあって、こうした低レベル通信ができた時代が懐かしい
単純な周辺機器はUART、I2C、SPIマルチドロップを短距離で、いくつかの標準クロックと単一コネクタで使い、モニターや外付けドライブのようにデータ量の多い機器はそのままIEEE 802.3 Ethernetへ移行していたなら、USBとEthernetを別々にサポートする必要はなく、Ethernetリンクだけ対応すれば済んだかもしれない
SPIは電源供給、ホットプラグ、デバイス発見、ビットエラーといったUSBが提供する多くの利便性を考慮していない
ソフトウェア開発者がSPIのイディオムやハードウェア設計者がSPIをどう使うかを理解することには価値がある
通常SPIは周辺機器のレジスタを埋めるために使われ、USBやEthernet、そしてその上の抽象化層でよく見られる高水準の非同期通信とは性格が異なる
SPIフレームに普遍的な標準はないが、慣用的なパターンはあり、無数の応用でそれで十分だった
現実にはSPIやI2Cのような単純なプロトコルでは十分ではない
速くないし、シングルエンド信号方式なのでノイズに非常に弱く、誤り訂正もない
これらのプロトコルは本来の用途、つまりPCB上でIC同士を接続する用途には非常によく合っているが、終端処理のないポートを外部に露出すると、何も保証しにくい
現代のPCでもこうしたプロトコルやその派生は多く使われているが、あくまで内部バス
USB仕様を詳しく見たわけではないが、ビットバンギングの主な問題は要求速度である可能性が高い
マイクロコントローラは、ピンをトグルしながら同時にプロトコルをデコードし、誤り訂正を管理できるほど速くないため、専用ハードウェアが必要になる
I2Cをビットバンギングしても同じ問題にぶつかり得る
20MHz CPUで得られる最大クロックは約250KHzで、一般的な最大速度400KHzの半分を少し超える程度であり、1MHz版は事実上不可能
PHYが存在する理由は、通信プロトコルをハードウェアに任せたほうが圧倒的に安いから
そうでなければ、通信を手作業で管理するためのリソースを確保しようとしてCPUをはるかに過剰にする必要があり、そのため現代のマイクロコントローラにはI2C、SPI、シリアル通信用のハードウェアが入っている
要するに、SPI、I2C、UARTのような単純なシリアルプロトコルは、外部周辺機器向けとしては非常に悪い選択
適切な速度で動作させにくく、長いケーブルやノイズにも耐えられない
RS-232はUARTではないので例外としても、こうしたプロトコルの性質と設計上、このような使い方には向いておらず、これを支えるよう仕様を変えれば結局USBを再発明することになる
案内表示や会議室用TVディスプレイも、HDMI-CECより柔軟な制御のためにRS-232を備えていることが多い
9600bpsより高いビットレートが必要ないことも多く、最も一般的なコネクタはTx、Rx、GNDの3ピンねじ端子
最近の設置ではたいていどこかにRS232-USBアダプタが1つ以上入り、大きな部屋ではRS232をEthernet上にブリッジする
最初にこの分野に入ったときは意外だったが、多くの設置が数十年前のもので、構成要素が1つずつ置き換えられてきたと考えると納得できる
このチップは0.10ドル級で、2KB RAM、16KB Flash、48MHz、1 CPIで動作する
新しいCH570もSOIC8で0.10ドル級なのに、100MHz、16KB RAM、256KB Flash、USB、2.4GHzパケット無線まで備えており、開発ボードを注文してある
自作で基板を作ろうとする人向けに、必要な基板厚も書いておくとよい
記憶が正しければ0.8mm程度で、「USB-Cエッジコネクタ」がプラグに合うにはその厚みが必要
素晴らしい記事だが、8ピンという要件を少しだけ緩く見ていたら、ずっと単純になっていたのではとも思う
ピンが数本増えるだけでもプロジェクトの複雑さは大きく減り、はんだ付け時間はほんの少ししか増えなかった気がする
USB内蔵でもっと高速なチップはいくらでもある
Allwinner V3sも手はんだ可能で、RAMを内蔵しており、Linuxをネイティブで問題なく起動する
RP2350も良い選択肢で、キャッシュ内蔵の優れたQSPI RAMインターフェースとUSB対応を備えている
ほとんど2チップ構成のプロジェクトに近い
1つは単なるUSB-シリアルICで、SDカードを数えなければ、SDカードを含めても3つになる
ピン数の合計があまりに少ないので、デッドバグ方式で作ってみたくなる
microSD-to-SDアダプタは、はんだ付け可能なmicroSDホルダとしてかなり使える
それを対象に似たようなトリックをやるのも面白いハックになりそう
技術的にはとてもすばらしいプロジェクトだが、初心者向けの新しいコンピュータキットを作るという目標とは、ややずれるほど極端なところまで行っている気がする
初心者にとっては、SOIC8をはんだ付けするのとSOIC28をはんだ付けするのとで大きな違いはない
SOIC28もSOIC8と同じくらい簡単、あるいは難しいと思う
より大きなチップを使えば、最低限のサウンドやキーボード、将来的にはVGA風の本物のモニタ出力まで追加できて、ずっと実用的なコンピュータにできる
はんだ付けの難易度はほとんど増えないのに、興味を持ったユーザーが拡張しやすい土台になる
そういう方向で作りたいなら、私のコードを使ってもよい
私は 8ピンという人為的な制約 が面白くてそうしただけ
基板すら省いて、回路彫刻として作ってみたくなる妙な衝動がある
私は芸術家でも彫刻家でもないので、あえて挑戦はしなかった
ストレージとしてSDカードの代わりに 8ピン SPI Flash を使うとかわいらしい気がする
「個人的な理由でRISC-Vにアレルギーがある」と言っていたが、その理由が気になる
炎上議論を始めたいわけではなく、ただの個人的な意見だが、かなり強い意見ではある
RISC-Vは歴史的に十分遅い時期に設計されていて、既存の知見を多く活用できたはずなのに、ほとんど活用しなかったと思う
そのため、最初からちゃんとしておくべきだったことを直すための拡張がいろいろ提案されている
追加が増えるにつれて、10年たってようやく少しずつ筋の通った形に近づいてきている
学習過程が必要だったという言い訳にも納得できない
必要な情報は最初からあったし、ミスも私たちの大半には明白だった
いくつかの拡張は、根本設計の問題に貼る絆創膏にすぎない
たとえば shadd2 は、配列アクセスのためのまともなアドレッシングモードがない問題をごまかすための絆創膏だ
これに対するよくある返答は、コア内の魔法のような命令融合を約束することだが、しばしば約束されるだけで、実際には提供されない
とくにRISC-Vのほぼ唯一のターゲットに見える低価格プロセッサではなおさらだ
ビットフィールドの抽出や挿入命令がないのもアマチュア的なミスで、それを直す拡張もある
だが、そのような機能が必要だということは最初から明らかだったはずだ
レジスタ内の特定ビットを基準に条件分岐する命令もよく使われるので、最初から考慮すべき明白な機能だ
現代ソフトウェアを少し分析すれば分かったはずだ
腹立たしいのは、情報がすでに存在していたことだ
現代ソフトウェアが何をしているか分かっていたのに、それがすべて無視され、結果として少し更新された MIPS-1 を受け取ったように思う
今では拡張が大量にぶら下がり、断片化がひどくなっている
ある程度まともな最終成果物であるRV23のようなものを対象にすることもできるが、それを実装したハードウェアは存在せず、さもなければどこでも動くがひどく非効率な最小公倍数を対象にするしかない
実際の高性能コンピューティングでRISC-Vを使おうとすると、さらに深刻な設計上の問題もあるが、それは次のrantに取っておく
同じような時期に設計された別の命令セットは、現代ソフトウェアの実態をめぐる知見を実際に活用しており、その結果は明白だ: aarch64
プロジェクト自体も非常にすばらしいが、このページは小型マイクロコントローラの情報を得る資料としても優れている
WLCSP系は抜けているが、ARM用MIPSエミュレータのページ https://dmitry.gr/?r=05.Projects&proj=33.%20LinuxCard にもつながっていて、かなり興味深そうだ