Baochip をはじめよう



bunnie | masto: @bunnie@treehouse.systems | bluesky: @bunnie.org

baochip | bluesky: @baochip.com

この資料の日本語は Claude (AI) に翻訳してもらいました 🤖(おかしな日本語はご容赦を)

English version

Baochip のご紹介

  • オープンソースの CPU を5つ搭載
    • VexRiscv RV32IMAC+MMU @ 350MHz
    • PicoRV I/O エンジン(「BIO」)×4 @ 700MHz
  • オンチップ ROM 4MiB(「RRAM」)
  • オンチップ SRAM 2MiB
  • 暗号アクセラレータ、TRNG
  • USB HS、カメラ、I2C、SPI、UART など

マイコン比較表:Dabao vs Raspberry Pi Pico 2、ESP32、Teensy 4.1、Adafruit Feather M4、BBC micro:bit v2

項目 Dabao Raspberry Pi Pico 2 ESP32-DevKitC Teensy 4.1 Adafruit Feather M4 BBC micro:bit v2
メーカーBaochipRaspberry Pi LtdEspressif SystemsPJRCAdafruitMicro:bit Educational Foundation
MCU / SoCBaochip-1x(シングルコア Vexriscv)RP2350(デュアルコア Cortex-M33)ESP32(デュアルコア Xtensa LX6)NXP iMXRT1062(Cortex-M7)SAMD51(Cortex-M4F)nRF52833(Cortex-M4F)
クロック周波数350 MHz150 MHz240 MHz600 MHz120 MHz64 MHz
I/O コプロセッサBIO(PicoRV ×4 @ 700 MHz)PIO ブロック ×2(ステートマシン 8基)ULP コア ×2(RISC-V / FSM)FlexIOSERCOMなし
ハードウェアセキュリティ署名付きブート、TRNG、鍵ストア、ワンウェイカウンタ、RSA、ECC、ECDSA、X25519、SHA-256/512、SHA3、Blake2/3、AES;セキュアメッシュ、グリッチセンサ、ECC 保護 RAMTrustZone、署名付きブート、OTP 鍵ストア、HW SHA-256、TRNGeFuse セキュアブート + AES フラッシュ暗号化、HW RNGHAB セキュアブート、AES-256 暗号化 XIP(ロック可能)NVM の読み出し保護のみ読み出し保護のみ;HW 暗号なし
IRIS で検査可能対応非対応非対応非対応非対応非対応
ブートローダがオープンオープンオープン非公開非公開非公開非公開
RTL がオープンほぼオープン非公開非公開非公開非公開非公開
メモリ保護MMUMPU + TrustZoneMPU 相当MPUMPUMPU
スワップメモリ対応(Xous + 外部 PSRAM)非対応非対応非対応非対応非対応
Rust ネイティブ対応非対応非対応非対応非対応非対応
RAM2048 KB + I/O バッファ 256 KB520 KB520 KB1 MB192 KB128 KB
Flash4 MB(内蔵 RRAM)4 MB4 MB8 MB + SD スロット内蔵 512 KB + 外付け 2 MB内蔵 512 KB
Flash インターフェース内蔵 XIP(最大 1200 MB/s)QSPI(XIP 約 56 MB/s)QSPI(約 40 MB/s)FlexSPI octal/quad(XIP 約 100 MB/s)内蔵 NVM(XIP 推定約 400 MB/s)内蔵 NVM(推定 20–40 MB/s)
GPIO ピン2026345520大ピン5 / 全19
無線なしなし(W 版は Wi-Fi/BT 搭載)Wi-Fi + Bluetooth 4.2なし(アドオンあり)なし(Wing エコシステム)Bluetooth 5.0 + 2.4 GHz
USBUSB-C(USB 2.0 HS デバイス)Micro-USB(ネイティブ)Micro-USB(CP2102 経由)USB-C(ネイティブ、デバイス + ホスト)Micro-USBMicro-USB
価格(目安)$12$5–$7$8–$12$30–$35$20–$24$15–$18
向いている用途セキュリティ、高信頼性、汎用汎用、MicroPython/C++IoT、無線接続オーディオ DSP、高速データ、USB MIDI/HIDCircuitPython、モジュール式 Wing 拡張教育、子ども向け、授業でのコーディング

IRIS で検査できる

IRIS でチップの偽造が難しくなる

BIO で柔軟な I/O を実現


  • BIO:Bao-I/O プロトコルエミュレータ
    • トグルレート 25MHz 未満ならどんなプロトコルでも
    • CAN
    • LED テープ
    • USB フルスピード
    • I2C、UART、SPI など…
    • あの謎なエアコンの赤外線プロトコルも…
  • オープンソースで特許フリー!
    • Raspberry Pi の PIO に似てるけど、こっちはオープンソース

C で書ける I/O:LED を「Blink(点滅)」させる


#include <stdint.h>

#include "bio.h" // これは必ず一番最初に書くこと

#define GPIO_PIN 21

void main(void) {
    uint32_t output_mask = 1 << GPIO_PIN;

    set_gpio_mask(output_mask);
    set_output_pins(output_mask);

    clear_gpio_pins_n(!output_mask); // Low に駆動
    while (1) {
        for(int i = 0; i < 10; i++) {
            set_gpio_pins(output_mask);
        }
        for(int i = 0; i < 10; i++) {
            clear_gpio_pins_n(!output_mask); // ピンを Low に駆動
        }
    }
}
					

BIO コードをブラウザでデバッグ

BIO を試してみよう

Dabao のご紹介

Dabao:Baochip-1x 評価ボード

  • 「いちばんシンプルなボード」
    • 2層基板
    • JLCPCB で製造可能
  • 全 I/O がピンに出ているわけではない
    • Baochip-1x の CSP パッケージが高密度すぎる
    • 配線できる I/O の一部だけ利用可能
  • オンボードの電圧レギュレータ内蔵
  • ソース:https://github.com/baochip/dabao

Dabao のピンアウト

Xous のご紹介

Xous:Baochip-1x 向けの純 Rust 製 OS

  • 一から Rust で書かれている
  • ソース:https://github.com/betrusted-io/xous-core/
    
    									git clone --depth 1 https://github.com/betrusted-io/xous-core/
    									cd xous-core
    									git fetch --depth 1 origin tag v0.10.1
    								
  • Rust ツールチェーンが必要
    • すでに入っている場合は「rustup update」で最新化してください
  • 複数ターゲットに対応。dabao 向けは以下でビルド
  • 
    									cargo xtask dabao dabao-console
    								
  • もしくは Baochip の vscode プラグインを使ってもOK!

Xous 用 VSCode プラグイン

Xous の概要

Xous はメッセージパッシング型 OS

  • 各プロセスは独立した仮想メモリ空間で動作する
  • メッセージは一度カーネルを「経由」して宛先へルーティングされる
  • この例では:
    • 「console」プロセスがカーネル経由で「log」にログメッセージを送る
    • log がそのメッセージを受け取る
    • log はそれを USB インターフェースへ流す
    • (図にはないけど、ハードウェアシリアルにも流している)

Xous のメッセージのセマンティクスは

Rust のメモリセマンティクスと同じ:

可変 XOR 共有 (Mutable XOR Shared)

Rust の所有権の例:関連関数


						impl Example {
							/// 呼び出し側からはもうアクセスできない
							fn _move(self) { ... }

							/// 複数のスレッドから呼び出せる
							fn _borrow(&self) { ... }

							/// 呼び出せるスレッドは1つだけ
							fn _mut_borrow(&mut self) { ... }
						}
					

ルール:メモリを貸すと、一時的に「移動」する

プロセス B が返すまで、メモリはプロセス A から使えない

I/O も結局はメモリ

  • 1つのペリフェラルを所有できるのは1プロセスだけ
  • 所有権は早い者勝ち
  • ペリフェラルへはメッセージ API 経由でアクセス
  • だから「HAL」サーバがある:ほとんどのペリフェラルを「所有」している

Xous の基本的なメッセージングアーキテクチャ

サーバを見つける

  • 共有アドレス空間
  • 128 ビットのサーバ名
  • 次のどちらか:
    • よく知られた(well-known)128 ビット値
    • ランダムな 128 ビット値

サーバを作る

    
    							let srv = create_server(b"0123456789abcdef");
    						
    
    							while let Some(mut msg) = receive_message(srv) {
    								// メッセージを処理
    							}
    						

メッセージを送る


						let connection = connect(b"0123456789abcdef");
					

						scalar_message(connection, 1, 2, 3, 4, 5);
					

						lend_message(connection, 1, &slice, 4, 5);
					

Xous のメッセージ種別

Rust の
所有権
Xous
メモリ
Xous
スカラ
move Send Scalar
&borrow Lend BlockingScalar
&mut borrow LendMut BlockingScalar

Xous の実装

Ticktimer

  • ハードウェアタイマーを所有する
  • 稼働時間(uptime)のカウントを担当
  • スケジューラを提供
    • ReturnToParent
      システムコール
  • msleep
    を提供

Ticktimer


						pub fn sleep(dur: Duration) {
							let conn = connect(b"ticktimer-server");
							blocking_scalar(conn,
								1,   // SleepMs のオペコード
								dur.as_millis(),
								0,
								0,
								0,
							);
						}
					

ログサーバ


						#[repr(C, align(4096))]
						struct LendBuffer([u8; 4096]);
					

						let mut message = LendBuffer([0u8; 4096]);
						writeln!(&mut message, "Hello, world!");
						let conn = connect(b"xous-log-server ");
						lend(conn,
							1,   // StandardOutput のオペコード
							&lend_buffer.0,
							0,
							14,  // "Hello, world!\n" の長さ
						);
					

libstd
連携:ビルド済みライブラリ

結果

  • Rust 本家の Tier-3 ターゲット
  • Stable の機能だけを使用
  • (C)コンパイラもリンカも不要
  • Rust のセマンティクスをハードウェア MMU が強制する

やってみよう:LED を点滅させる

  • シェルに「blink」コマンドを追加
  • HAL の IO サービスに接続
  • ピンを設定
  • ピンの値を切り替えながらループ

シェルの概要

  • シェルは「dabao-console」にある
  • シェルには REPL(Read-Eval-Print-Loop)があり、コマンドを受け取って「コマンドモジュール」に振り分ける
  • これは「ver」コマンドモジュールの例

impl<'a> ShellCmdApi<'a> for Ver {
    cmd_api!(ver);

    fn process(&mut self, args: String, env: &mut CommonEnv) ->
		Result<Option<String>, xous::Error> {
        use core::fmt::Write;
        let mut ret = String::new();
        let helpstring = "ver [xous]";

        let mut tokens = args.split(' ');

        if let Some(sub_cmd) = tokens.next() {
            match sub_cmd {
                "xous" => {
                    write!(ret, "Xous version: {}", env.ticktimer.get_version()).unwrap();
                    log::info!("VER.XOUS,{}", env.ticktimer.get_version());
                }
                _ => {
                    write!(ret, "{}", helpstring).unwrap();
                }
            }
        } else {
            write!(ret, "{}", helpstring).unwrap();
        }
        Ok(Some(ret))
    }
}
						

blink コマンド:サブコマンドを追加

  • 「test.rs」モジュールに「blink」コマンドを追加
  • blink のコードを apps-dabao/dabao-console/src/cmds/test.rs の 24 行目あたりに挿入

    fn process(&mut self, args: String, _env: &mut CommonEnv) -> Result<Option<String>, xous::Error> {
        use core::fmt::Write;
        let mut ret = String::new();

        #[allow(unused_variables)]
        let helpstring = "test [proc] [freemem] [interrupts] [panic] [env]";

        let mut tokens = args.split(' ');

        if let Some(sub_cmd) = tokens.next() {
            match sub_cmd {
                "blink" => {
                    log::info!("Add blinky code here");
                }

						

コマンド拡張をテスト

vscode 拡張を使って:

  • 「Build-flash-monitor」をクリック
  • 初回は、指示に従って Dabao のディスクとシリアルポートの場所を指定
    • baochip の場所を設定
    • ブートローダモードのシリアルポートを設定
    • build-flash-monitor を押す
    • 実行モードのシリアルポートを設定
    • もう一度「monitor」を選ぶ必要があるかも
  • 「[console]」プロンプトで「test blink」と入力

[console]

[console] test blink
INFO:dabao_console::cmds::test: Add blinky code here (apps-dabao\dabao-console\src\cmds\test.rs:25)
						

blink コマンド:点滅処理を追加

  • 「IoxHal」オブジェクトを作る
  • ポートと方向を設定
    • PB4 なら、PB4 と隣のグランドピンの間に LED を1個挿せる
  • ループを作る:
    • ピンを High に
    • 1秒待つ
    • ピンを Low に
    • 1秒待つ
  • Build-flash-monitor

                "blink" => {
                    use std::time::Duration;

                    use bao1x_api::{IoGpio, IoxDir, IoxHal, IoxPort, IoxValue};
                    let iox = IoxHal::new();
                    iox.set_gpio_pin_dir(IoxPort::PB, 4, IoxDir::Output);
                    loop {
                        iox.set_gpio_pin_value(IoxPort::PB, 4, IoxValue::High);
                        std::thread::sleep(Duration::from_secs(1));
                        iox.set_gpio_pin_value(IoxPort::PB, 4, IoxValue::Low);
                        std::thread::sleep(Duration::from_secs(1));
                    }
                }
						

Dabao の組み込みコマンド

WS2812 デモ

  • ws2812 [rainbow [<duration>]] はデフォルトで PB5 にレインボーパターンを表示
  • ws2812 pin [number] で BIO ピンを設定
  • ws2812 length [pixels] でストリップの長さを設定(デフォルト 6 LED)
  • ws2812 hexcolor [#rrggbb] でストリップを指定した16進カラー一色にする
  • ws2812 touch は静電容量タッチ + WS2812 のデモ(タッチに PB1、LED に PB5 を使用)
  • ws2812 captouch-pin [pin] で静電容量タッチ入力に使うピンを変更

静電容量タッチ(Captouch)デモ

  • touch [pin] で静電容量タッチ入力のピンを設定(デフォルト PB1)
  • touch monitor で生のタッチ値を表示
  • touch wait-touch はセンサーが触れられるまで待ち、メッセージを表示して終了

I2C 検出(I2C Detect)

  • i2cdetect scan は PB11(SCL) と PB12(SDA) 上の I2C デバイスをスキャン
  • PB11 と PB12 に外付けプルアップがあると安定する
  • I2C デバイスは 3.3V I/O 前提

BIO コードの読み込み

  • bio-loader を使って BIO の「.bin」ファイルをアップロード
  • 「.bin」ファイルは bio-sim で生成
  • コードのシミュレーションは BIO-surfer 波形ビューアで確認