Port RP2040 RP2350 - amir1387aht/MicroCS GitHub Wiki

MicroCS for Raspberry Pi RP2040 / RP2350 (pico-sdk)

Raspberry Pi Pico, Pico W, Pico 2 (Arm or RISC-V cores) and any RP2040/RP2350 board.

Quick start

export PICO_SDK_PATH=/path/to/pico-sdk
cmake -S ports/rp2/example -B build/pico -DPICO_BOARD=pico \
      -DMICROCS_FS_DOWNLOAD=ON        # or pico2, pico_w; fetches LittleFS once (or -DMICROCS_FS=tinyfs)
cmake --build build/pico
# copy build/pico/microcs_pico.uf2 to the board (hold BOOTSEL while plugging in)

Open the USB serial port (any baud rate) and type C# at the > prompt. The whole firmware is example/main.c, ~30 lines.

Pins

mcs_rp2_cfg_t pins = MCS_RP2_CFG_DEFAULT;     // Pico defaults:
// UART0 GP0/GP1, UART1 GP4/GP5, I2C0 GP8/GP9, I2C1 GP6/GP7,
// SPI0 GP18/19/16 (SCK/MOSI/MISO), SPI1 GP10/11/12
pins.i2c[0] = (mcs_rp2_i2c_pins_t){ 4, 5 };   // change any bus
mcs_rp2_hal_init(&hal, &pins);
C# RP2
pins GPIO numbers; "GP15", "GPIO15", "LED" (on-board LED where defined; on a Pico W it is the radio's "WL_GPIO0")
GPIO.OnChange GPIO IRQ callback
UART interrupt-driven receive ring
PWM.Set(gpio, ...) every GPIO can do PWM (channel = GPIO number)
LedStrip ws2812 driver (DRIVERS.md; -DMICROCS_WS2812=OFF drops it and hardware_pio): WS2812 on any GPIO through a PIO state machine (up to 4 strips); "NEOPIXEL" = PICO_DEFAULT_WS2812_PIN (Waveshare RP2040-Zero: GP16)
ADC.Read(0..3) GP26–GP29; ADC.Read(4) = internal temperature sensor
Timer hardware alarm pool
Watchdog, RTC, Hal.UniqueId hardware watchdog, software clock on the 64-bit µs timer (set it with RTC.Set), flash unique id

Not available on this chip: DAC, CAN, QSPI for user devices; I²S needs PIO (planned).

Files on flash

The example keeps /boot.cs, /main.cs, uploaded scripts and every file a script writes in LittleFS on the top of the board's QSPI flash, so they survive resets:

static mcs_rp2_flash_t flash;
static mcs_flashfs_t fs;
if (mcs_rp2_flash_init(&flash, 0, 0) == 0 &&                        // last MCS_RP2_FS_SIZE bytes
    mcs_flashfs_mount(&fs, &flash.flash, 0, 0, MCS_FLASHFS_DEFAULT, MCS_FLASHFS_FORMAT_IF_NEEDED) == 0) {
    cfg.fs_ops = fs.ops; cfg.fs_ctx = fs.ctx;
}
  • Region: MCS_RP2_FS_SIZE bytes at the end of flash — 1 MB on 2 MB boards (Pico), all but the first 1 MB on 4 MB+ boards (Pico 2: 3 MB). Pico W / Pico 2 W builds with Wi-Fi or BLE keep the first 1.5 MB for the firmware (MCS_RP2_FW_RESERVE: 512 KB of files on a Pico W), and BLE bonds take the last 8 KB. Override with MCS_RP2_FS_SIZE (in mcs_user_config.h or -D) or pass an offset/size; the driver refuses a region that overlaps the firmware.
  • Erase/program go through flash_safe_execute, which pauses interrupts and the other core.
  • Filesystem sources are not bundled or downloaded silently: pass -DMICROCS_LITTLEFS_DIR=/path/to/littlefs (a git clone -b v2.9.3 of littlefs), keep a copy in third_party/littlefs, or add -DMICROCS_FS_DOWNLOAD=ON to fetch v2.9.3 once (FILESYSTEM.md).
  • TinyFS instead (built into MicroCS, nothing to fetch): cmake ... -DMICROCS_FS=tinyfs, optionally -DMICROCS_FS_SIZE=65536 for the region size (default as above).
  • YAFFS2 instead: cmake ... -DMICROCS_FS=yaffs2 (MICROCS_YAFFS2_DIR or -DMICROCS_FS_DOWNLOAD=ON; GPLv2 or commercial licence — linking it puts your firmware under those terms). -DMICROCS_FS= (empty) builds without flash files (RAM disk only).

Both cores (FreeRTOS SMP)

The pico-sdk has no OS of its own; Raspberry Pi's supported RTOS is FreeRTOS SMP from their FreeRTOS-Kernel fork (RP2040 and RP2350 ports, used by pico-examples). The release .uf2 files are built this way.

git clone https://github.com/raspberrypi/FreeRTOS-Kernel
cmake -S ports/rp2/example -B build -DPICO_BOARD=pico -DMICROCS_OS=freertos -DFREERTOS_KERNEL_PATH=$PWD/FreeRTOS-Kernel

The REPL runs in a FreeRTOS task on core 0 (configuration: example/freertos/FreeRTOSConfig.h). Thread.RunOn(1, "/dsp.cs", "Filter", 128), Thread.Every(10, "/control.cs", "Tick", 1) and thread core=1 jobs in jobs.cfg run on core 1, and jobs.cfg file jobs run on threads by default. Works on RP2040 and RP2350 (-DPICO_BOARD=pico2). Without MICROCS_OS, the firmware is single-threaded, as before. See docs/THREADS.md.

Wi-Fi (Pico W, Pico 2 W)

With FreeRTOS and a *_w board the example firmware gets Wi-Fi, lwIP sockets, Http, HttpServer, WebSocket, DnsServer, Ntp, Mdns and Ping (docs/NETWORK.md):

git -C $PICO_SDK_PATH submodule update --init lib/cyw43-driver lib/lwip
cmake -S ports/rp2/example -B build/pico_w -DPICO_BOARD=pico_w -DMICROCS_OS=freertos \
      -DFREERTOS_KERNEL_PATH=$PWD/FreeRTOS-Kernel -DMICROCS_FS_DOWNLOAD=ON   # or pico2_w
cmake --build build/pico_w
if (Wifi.Connect("MyNetwork", "secret-password")) Console.WriteLine(Wifi.Ip);
var led = new Pin("LED", GPIO.Output);        // the LED hangs on the radio chip

MICROCS_WIFI is on by default for these boards (-DMICROCS_WIFI=OFF to leave it out; without MICROCS_OS=freertos the radio stays off). The backend is mcs_port_rp2_net.c, lwIP settings are in wifi/lwipopts.h (-DMICROCS_LWIPOPTS_DIR= for your own). Wifi.Save keeps the network in the file /.wifi. No HTTPS, ESP-NOW, WPS or SmartConfig.

Bluetooth LE (Pico W, Pico 2 W)

Opt-in, not in the release images: -DMICROCS_BLE=ON adds C# Ble, BleService, BleConnection and BleUart on BTstack (docs/BLE.md) — with or without FreeRTOS, with or without Wi-Fi:

git -C $PICO_SDK_PATH submodule update --init lib/cyw43-driver lib/lwip lib/btstack
cmake -S ports/rp2/example -B build/pico_w_ble -DPICO_BOARD=pico_w -DMICROCS_BLE=ON -DMICROCS_FS_DOWNLOAD=ON
cmake --build build/pico_w_ble

BTstack settings are in ble/btstack_config.h (2 connections, 247-byte MTU, LE Secure Connections; -DMICROCS_BTSTACK_CONFIG_DIR= for your own). Bonds use the last 8 KB of flash. Backend: mcs_port_rp2_ble.c.

Flash layout: with Wi-Fi or BLE the firmware (radio firmware included) gets the first 1.5 MB and the filesystem the rest (MCS_RP2_FW_RESERVE; 1 MB without the radio).

Checked in CI

The example firmware is built for pico (RP2040, LittleFS) and pico2 (RP2350, LittleFS and YAFFS2), plus pico_w and pico2_w with FreeRTOS and Wi-Fi, pico_w with BLE (no OS) and pico2_w with Wi-Fi + BLE.