Skip to content

RP2040 / Pico Platform Guide

Xylolabs SDK integration for the Raspberry Pi Pico (RP2040). The RP2040 is a cost-effective sensor-only target.


RP2040 Specifications

Resource Specification Notes
CPU Dual Cortex-M0+ @ 133 MHz ~266 MIPS total; no DSP, no FPU
SRAM 264 KB Static allocation, no heap
Flash External QSPI (2-16 MB typical) Firmware + log storage
UART 2 channels LTE-M1 modem AT commands
ADC 4 channels, 12-bit, 500 ksps Sensor inputs (GPIO26-29)
SPI 2 channels External sensors, SD card
I2C 2 channels Temperature, humidity, pressure sensors
PIO 8 state machines (2 blocks x 4) Flexible I/O protocols
DMA 12 channels Zero-copy data transfers
WDT Hardware watchdog Long-term unattended operation
GPIO 30 pins Sensors, modem control, status LEDs

Key Differences from RP2350

The RP2040 uses the same Pico SDK as the RP2350, but has important hardware differences:

Feature RP2040 (Pico) RP2350 (Pico 2)
Core Cortex-M0+ Cortex-M33
Clock 133 MHz 150 MHz
SRAM 264 KB 520 KB
FPU None Single-precision
DSP extensions None SIMD MAC, saturating
XAP audio Not feasible Full support (4ch @96kHz)
ADPCM audio 1-2ch optional 4ch supported
Pico SDK board pico pico2
Price ~$4 ~$5

XAP is not feasible on RP2040. The Cortex-M0+ lacks a hardware FPU, so all floating-point operations are software-emulated. XAP encoding requires ~10 MIPS/channel with FPU, but ~40+ MIPS/channel with software float -- exceeding the RP2040's budget for multi-channel audio.


Use Cases

The RP2040 is recommended for:

  • Environmental monitoring: Temperature, humidity, pressure, CO2
  • Simple vibration monitoring: Single-axis accelerometer via ADC
  • Power monitoring: Current and voltage sensors
  • Low-cost sensor networks: Where audio is not needed

For audio streaming, use the RP2350 (Pico 2) instead.


Hardware Setup

LTE Modem (UART0) -- BG770A

RP2040 GPIO              LTE Modem
------------------       ------------------
GPIO0  (UART0_TX) -----  RXD
GPIO1  (UART0_RX) -----  TXD
GPIO2  (GPIO)     -----  PWRKEY
GPIO3  (GPIO)     -----  RESET_N
VSYS (5V)         -----  VCC (via LDO)
GND               -----  GND

Sensor Inputs (ADC)

GPIO ADC Channel Typical Use
GPIO26 ADC0 Temperature sensor
GPIO27 ADC1 Humidity sensor
GPIO28 ADC2 Pressure sensor
GPIO29 ADC3 Vibration / current

I2C Sensors

Bus GPIO Typical Devices
I2C0 GPIO4 (SDA), GPIO5 (SCL) CHT832X (temp/humidity), BME280
I2C1 GPIO6 (SDA), GPIO7 (SCL) LIS3DH (accelerometer)

# Install dependencies
rustup target add thumbv6m-none-eabi
cargo install probe-rs-tools

# Build
cd sdk/examples/rp2040-sensor
cargo build --release

# Flash
cargo run --release  # Uses probe-rs via .cargo/config.toml

See sdk/examples/ for all RP2040 examples.


Legacy C Build System

cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(my_sensor_node C CXX ASM)
set(PICO_BOARD pico)  # Important: target original Pico, not Pico 2
pico_sdk_init()

add_subdirectory(sdk/rp2040)

add_executable(my_sensor_node src/main.c)
target_link_libraries(my_sensor_node
    pico_stdlib
    hardware_adc
    hardware_i2c
    hardware_watchdog
    hardware_timer
    xylolabs_sdk_rp2040
)
pico_add_extra_outputs(my_sensor_node)

Key Difference from RP2350 Build

Set PICO_BOARD=pico (not pico2). The Pico SDK automatically selects the correct startup code and linker script for the RP2040.


Memory Budget

Region Size Config Macro
XMBP packet buffer 4 KB XYLOLABS_XMBP_BUF_SIZE
HTTP buffer 4 KB XYLOLABS_HTTP_BUF_SIZE
Metadata accumulation ~4 KB 4ch x 100 samples x f32
AT command buffer ~1 KB Internal
Stack + SDK internals ~8 KB
Total SDK ~21 KB 8% of 264 KB
Available for app ~243 KB

Software Float Considerations

Since the RP2040 has no FPU, floating-point operations are emulated:

  • float multiply: ~20 cycles (vs 1 cycle on Cortex-M4F)
  • float divide: ~70 cycles
  • float trig: ~200+ cycles

For performance-critical sensor calibration, consider using fixed-point integer math with scaling factors instead of floating-point.


Power Management

The RP2040 supports dormant and sleep modes:

// Rust (Embassy) - Recommended
use embassy_time::Timer;

// Lightweight sleep between samples (async timer wakeup)
Timer::after_micros(interval_us - 500).await;

// For event-triggered wakeup, use embassy GPIO interrupt
let mut sensor_int = Input::new(p.PIN_X, Pull::Down);
sensor_int.wait_for_rising_edge().await;
Legacy C equivalent
// Lightweight sleep between samples (timer wakeup)
sleep_us(interval_us - 500);  // Wake slightly early for timing accuracy

// Deep dormant mode (GPIO wakeup only)
// Useful for event-triggered sensors
dormant_until_pin(GPIO_SENSOR_INT, true, false);  // Wake on rising edge

Rust is the recommended language for new RP2040 projects. The Embassy-based Rust examples provide async sensor polling and networking with compile-time safety.

cd sdk/examples/rp2040-sensor
cargo build --release
# Flash the resulting ELF via probe-rs
probe-rs run --chip RP2040 target/thumbv6m-none-eabi/release/rp2040-sensor

See sdk/examples/README.md for detailed build instructions.


C Examples (alternative) ### Existing Examples The `sdk/c/rp2040/examples/` directory contains: | Example | Description | |---------|-------------| | `sensor_node.c` | 4-channel ADC sensor streaming at 100Hz |

Troubleshooting

Symptom Likely Cause Fix
Watchdog reset loop xylolabs_tick() not called often enough Ensure tick runs every 4 seconds
Inaccurate sensor values Software float rounding Use integer math with scaling
High power consumption Not using sleep between samples Add sleep_us() in main loop
Build fails with RP2350 errors Wrong PICO_BOARD setting Set PICO_BOARD=pico in CMake
Modem not responding UART baud mismatch Default 115200, check modem config

Further Reading