Getting Started with Baochip



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

baochip | bluesky: @baochip.com

「日本語版(機械翻訳)」

Introducing Baochip

  • Five open-source CPUs
    • VexRiscv RV32IMAC+MMU @ 350MHz
    • 4x PicoRV I/O Engine ("BIO") @ 700MHz
  • 4MiB on-chip ROM ("RRAM")
  • 2MiB on-chip SRAM
  • Cryptographic accelerators, TRNG
  • USB HS, camera, I2C, SPI, UART, etc.

Microcontroller comparison table: Dabao vs Raspberry Pi Pico 2, ESP32, Teensy 4.1, Adafruit Feather M4, BBC micro:bit v2

Spec Dabao Raspberry Pi Pico 2 ESP32-DevKitC Teensy 4.1 Adafruit Feather M4 BBC micro:bit v2
ManufacturerBaochipRaspberry Pi LtdEspressif SystemsPJRCAdafruitMicro:bit Educational Foundation
MCU / SoCBaochip-1x (single-core Vexriscv)RP2350 (dual-core Cortex-M33)ESP32 (dual-core Xtensa LX6)NXP iMXRT1062 (Cortex-M7)SAMD51 (Cortex-M4F)nRF52833 (Cortex-M4F)
Clock Speed350 MHz150 MHz240 MHz600 MHz120 MHz64 MHz
I/O CoprocessorBIO (4× PicoRV @ 700 MHz)2× PIO blocks (8 state machines)2× ULP cores (RISC-V / FSM)FlexIOSERCOMNone
Hardware SecuritySigned boot, TRNG, key store, one-way counters, RSA, ECC, ECDSA, X25519, SHA-256/512, SHA3, Blake2/3, AES; secure mesh, glitch sensors, ECC-protected RAMTrustZone, signed boot, OTP key store, HW SHA-256, TRNGeFuse secure boot + AES flash encryption, HW RNGHAB secure boot, AES-256 encrypted XIP (lockable)NVM read-back protection onlyRead-back protection only; no HW crypto
IRIS InspectableYesNoNoNoNoNo
Open BootloaderYesYesNoNoNoNo
Open RTLMostly openNoNoNoNoNo
Memory ProtectionMMUMPU + TrustZoneMPU-likeMPUMPUMPU
Swap MemoryYes (Xous + external PSRAM)NoNoNoNoNo
Rust-nativeYesNoNoNoNoNo
RAM2048 KB + 256 KB I/O buffers520 KB520 KB1 MB192 KB128 KB
Flash4 MB (internal RRAM)4 MB4 MB8 MB + SD slot512 KB internal + 2 MB external512 KB internal
Flash InterfaceInternal XIP (up to 1200 MB/s)QSPI (~56 MB/s XIP)QSPI (~40 MB/s)FlexSPI octal/quad (~100 MB/s XIP)Internal NVM (XIP est ~400 MB/s)Internal NVM (est. 20–40 MB/s)
GPIO Pins20263455205 large / 19 total
WirelessNoneNone (W variant adds Wi-Fi/BT)Wi-Fi + Bluetooth 4.2None (add-on available)None (Wing ecosystem)Bluetooth 5.0 + 2.4 GHz
USBUSB-C (USB 2.0 HS device)Micro-USB (native)Micro-USB (via CP2102)USB-C (native, device + host)Micro-USBMicro-USB
Price (approx.)$12$5–$7$8–$12$30–$35$20–$24$15–$18
Best ForSecurity, high-assurance & general-purposeGeneral-purpose, MicroPython/C++IoT projects, wireless connectivityAudio DSP, high-speed data, USB MIDI/HIDCircuitPython, modular add-on WingsEducation, kids, classroom coding

IRIS Inspectable

IRIS Makes it Harder to Fake Chips

BIO Gives Flexible I/O


  • BIO: Bao-I/O protocol emulator
    • Any protocol <25MHz toggle rate
    • CAN
    • LED strips
    • USB full speed
    • I2C, UART, SPI, etc...
    • That weird air conditioner IR protocol...
  • Open source and patent-free!
    • Similar to Raspberry Pi PIO but open source

C-Codable I/O: "Blink" an LED


#include <stdint.h>

#include "bio.h" // this must always be first

#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); // drives it 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); // drives the pin low
        }
    }
}
					

Debug BIO Code Online

Try the BIO

Introducing Dabao

Dabao: Baochip-1x Evaluation Board

  • "Simplest Board"
    • 2-layer PCB
    • JLCPCB-compatible
  • Not all I/O routed to pins
    • Baochip-1x CSP package is too dense
    • Subset of routable I/O available
  • Includes local voltage regulators
  • Source: https://github.com/baochip/dabao

Dabao Pinout

Introducing Xous

Xous: A Pure-Rust OS For Baochip-1x

  • Written from the ground-up in Rust
  • Source: 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
    								
  • Requires Rust toolchain
    • If already installed, run "rustup update" to ensure it is recent
  • Supports multiple targets, build for dabao with
  • 
    									cargo xtask dabao dabao-console
    								
  • Or use the Baochip vscode plugin!

VScode Plugin for Xous

Xous Overview

Xous is a Message Passing OS

  • Every process runs in an isolated, virtual memory space
  • Messages must "bounce off" the kernel to be routed to its destination
  • In this example:
    • The "console" process sends a log message to "log" via the kernel
    • The log receives the message
    • It routes the log message to the USB interface
    • (Not shown: it also routes it to the hardware serial interface)

Xous Message Semantics are the

Same as Rust Memory Semantics:

Mutable XOR Shared

Example of Rust Ownership Types: Associated Functions


						impl Example {
							/// The object is no longer accessible in the
							/// caller
							fn _move(self) { ... }

							/// Multiple threads can call this function
							fn _borrow(&self) { ... }

							/// Only one thread may call this function
							fn _mut_borrow(&mut self) { ... }
						}
					

Rule: Lending Memory Temporarily Moves It

Memory is unavailable to Process A until Process B returns it

IO is Just Memory

  • Only one process can own a peripheral
  • First-come, first-serve ownership
  • Access peripheral through message API
  • This is why we have the "HAL" server: it "owns" most of the peripherals

Xous Basic Messaging Architecture

Finding a Server

  • Shared address space
  • 128-bit Server Name
  • Either:
    • Well-known 128-bit value
    • Random 128-bit value

Creating a Server

    
    							let srv = create_server(b"0123456789abcdef");
    						
    
    							while let Some(mut msg) = receive_message(srv) {
    								// Handle message
    							}
    						

Sending a Message


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

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

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

Xous Message Types

Rust
Ownership
Xous
Memory
Xous
Scalar
move Send Scalar
&borrow Lend BlockingScalar
&mut borrow LendMut BlockingScalar

Xous Implementation

Ticktimer

  • Takes ownership of hardware timer
  • Handles uptime count
  • Provides scheduler
    • ReturnToParent
      syscall
  • Provides
    msleep

Ticktimer


						pub fn sleep(dur: Duration) {
							let conn = connect(b"ticktimer-server");
							blocking_scalar(conn,
								1,   // Opcode for SleepMs
								dur.as_millis(),
								0,
								0,
								0,
							);
						}
					

Log Server


						#[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,   // Opcode for StandardOutput
							&lend_buffer.0,
							0,
							14,  // Length of "Hello, world!\n"
						);
					

libstd
Integration: Pre-built Library

Results

  • Upstream Tier-3 Rust Target
  • Only using Stable features
  • No C compiler or linker needed
  • Rust semantics enforced by hardware MMU

Let's Try: Blink an LED

  • Add a "blink" command to the shell
  • Connect to the IO service on the HAL
  • Set up a pin
  • Loop while changing the pin value

Shell Overview

  • Shell is located in "dabao-console"
  • Shell has a REPL (Read-Eval-Print-Loop) which takes commands and dispatches them to "command modules"
  • This is an example of the "ver" command module

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 command: Add the Sub-Command

  • Add a "blink" command to the "test.rs" module
  • Insert the blink code in apps-dabao/dabao-console/src/cmds/test.rs around Line 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");
                }

						

Test the Command Extension

Using the vscode extension:

  • Click "Build-flash-monitor"
  • If doing this the first time, follow the instructions to find the Dabao disk and serial port locations
    • Set baochip location
    • Set bootloader mode serial port
    • Press build-flash-monitor
    • Set run mode serial port
    • You may have to select "monitor" again
  • Type "test blink" on the "[console]" prompt

[console]

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

Blink command: Add the Blink

  • Create the "IoxHal" object
  • Configure the port and direction
    • PB4 allows us to put a simple LED between PB4 and the adjacent ground pin
  • Create a loop:
    • Set the pin to high
    • Wait 1 second
    • Set the pin to low
    • Wait 1 second
  • 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));
                    }
                }
						

Built-in Dabao Commands

WS2812 Demo

  • ws2812 [rainbow [<duration>]] drives a rainbow pattern on PB5 by default
  • ws2812 pin [number] to set the BIO pin
  • ws2812 length [pixels] to set strip length (default 6 LEDs)
  • ws2812 hexcolor [#rrggbb] sets the strip to a solid hex color
  • ws2812 touch demonstrates captouch + WS2812 using PB1 for touch and PB5 for LED
  • ws2812 captouch-pin [pin] changes which pin is used for captouch input

Captouch Demo

  • touch [pin] sets the pin for captouch input (default PB1)
  • touch monitor shows the raw captouch values
  • touch wait-touch waits until sensor is touched, prints a message, and quits

I2C Detect

  • i2cdetect scan scans for any I2C devices on PB11(SCL) and PB12(SDA)
  • Works best with external pull-ups on PB11 and PB12
  • Assumes 3.3V I/O for I2C devices

BIO Code Loading