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_SIZEbytes 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 withMCS_RP2_FS_SIZE(inmcs_user_config.hor-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(agit clone -b v2.9.3of littlefs), keep a copy inthird_party/littlefs, or add-DMICROCS_FS_DOWNLOAD=ONto fetch v2.9.3 once (FILESYSTEM.md). - TinyFS instead (built into MicroCS, nothing to fetch):
cmake ... -DMICROCS_FS=tinyfs, optionally-DMICROCS_FS_SIZE=65536for the region size (default as above). - YAFFS2 instead:
cmake ... -DMICROCS_FS=yaffs2(MICROCS_YAFFS2_DIRor-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.