PicoCamera

September 9, 2026 · View on GitHub

PicoCamera logo

English · 中文

📖 Documentation: English · 中文

A camera library for RP2040 with an API aligned with esp32-camera (esp_ prefix becomes pico_), based on PIO + DMA capture.

  • All pins (including VSYNC/HREF/PCLK/data) are configured at runtime in camera_config_t — no PIO source editing required
  • No pioasm build step; works out of the box in Arduino IDE and PlatformIO
  • Automatic sensor model detection (reads PID over SCCB)

Supported sensors

Sensor list aligned with esp32-camera (datasheet output-format wording normalized, e.g. YCbCr422 → YUV422, compression → JPEG); the last column shows PicoCamera's current support status:

modelmax resolutioncolor typeoutput formatPicoCamera support
OV26401600 x 1200colorYUV422/420
RGB565/555
JPEG
RAW RGB (8/10-bit)
RGB565
YUV422
JPEG
OV36602048 x 1536colorRAW RGB
RGB565/555/444
CCIR656
YUV422
JPEG
RGB565
YUV422
JPEG
OV56402592 x 1944colorRAW RGB
RGB565/555/444
CCIR656
YUV422/420
JPEG
RGB565
YUV422
JPEG
OV7670640 x 480colorRAW Bayer
Processed Bayer
YUV422
GRB422
RGB565/555
RGB565
YUV422
OV7725640 x 480colorRAW RGB
GRB422
RGB565/555/444
YUV422
RGB565 (untested)
NT991411280 x 720colorYUV422
RGB565/555/444
RAW
CCIR656
JPEG
❌ Not supported yet
GC032A640 x 480colorYUV422
RAW Bayer
RGB565
RGB565 (untested)
GC0308640 x 480colorYUV422
RAW Bayer
RGB565
Grayscale
RGB565
YUV422
Grayscale
GC21451600 x 1200colorYUV422
RAW Bayer
RGB565
RGB565
YUV422
BF3005640 x 480colorYUV422
RAW Bayer
RGB565
❌ Not supported yet
BF20A6640 x 480colorYUV422
RAW Bayer
Y-only
❌ Not supported yet
SC101IOT1280 x 720colorYUV422
RAW RGB
❌ Not supported yet
SC030IOT640 x 480colorYUV422
RAW Bayer
❌ Not supported yet
SC031GS640 x 480monochromeRAW MONO
Grayscale
❌ Not supported yet
HM0360656 x 496monochromeRAW MONO
Grayscale
❌ Not supported yet
HM10551280 x 720colorRAW (8/10-bit)
YUV422
RGB565/555/444
❌ Not supported yet

All supported sensors also expose set_reg/get_reg-style raw register access; more sensor controls are ported on demand.

Requesting JPEG on a sensor without a JPEG encoder (e.g. OV7670, GC2145, GC0308, GC032A) makes pico_camera_init() fail with PICO_CAMERA_ERR_NOT_SUPPORTED — same behavior as esp32-camera. A frame_size beyond the sensor's maximum is clamped to the maximum with a warning instead of failing.

Installation

Arduino IDE

PicoCamera is published in the Arduino Library Manager: open Sketch → Include Library → Manage Libraries..., search for PicoCamera and click Install.

PicoCamera in the Arduino Library Manager

Manual install also works: put this repository into Arduino/libraries/, or zip it and use "Add .ZIP Library".

PlatformIO

PicoCamera is published in the PlatformIO Registry:

lib_deps =
    umeiko/PicoCamera@^0.4.1

A git URL (lib_deps = https://github.com/umeiko/PicoCamera.git) or a local file:// path works too.

Pico SDK (bare-metal CMake)

The library is pure Pico SDK code (no Arduino dependency), so bare CMake projects can consume it directly (SDK ≥ 1.5.0):

add_subdirectory(path/to/PicoCamera)
target_link_libraries(my_app pico_stdlib pico_camera)

See examples/pico_sdk_capture for a complete project, and the user guide for details.

Both Arduino/PlatformIO require the earlephilhower arduino-pico core.

If your core bundles PicoCamera

Newer arduino-pico releases may bundle a copy of PicoCamera. A copy you install yourself (Library Manager, PlatformIO lib_deps, git) always takes priority over the bundled one, so you can track the latest release without waiting for a core release. To check which version your sketch compiled against, use the macros from pico_camera.h:

Serial.println(PICO_CAMERA_VERSION_STRING);        // e.g. "0.3.0"
#if PICO_CAMERA_VERSION_HEX >= 0x00030000          // feature guards
...
#endif

Quick start

RP2040 board with camera module
An RP2040 board with an OV2640/OV3660 camera module over FPC

#include <PicoCamera.h>

camera_config_t config = {
    .pin_pwdn = -1, .pin_reset = -1, .pin_xclk = 5,
    .pin_sccb_sda = 12, .pin_sccb_scl = 13,
    .pin_d0 = 14, .pin_d1 = 15, .pin_d2 = 16, .pin_d3 = 17,
    .pin_d4 = 18, .pin_d5 = 19, .pin_d6 = 20, .pin_d7 = 21,
    .pin_vsync = 2, .pin_href = 3, .pin_pclk = 4,
    .xclk_freq_hz = 10000000,
    .sccb_i2c_port = 0,
    .pixel_format = PIXFORMAT_RGB565,   // or PIXFORMAT_JPEG
    .frame_size = FRAMESIZE_QVGA,
    .jpeg_quality = 10,
    .fb_count = 1,
    .fb_location = PICO_CAMERA_FB_AUTO,
};

void setup() {
    pico_camera_init(&config);
}

void loop() {
    camera_fb_t *fb = pico_camera_fb_get();
    if (fb) {
        // fb->buf / fb->len / fb->width / fb->height
        // In JPEG mode, buf is a complete JPEG file (FFD8...FFD9)
        pico_camera_fb_return(fb);
    }
}

Sensor control, esp32-camera style:

sensor_t *s = pico_camera_sensor_get();
if (s) {
    if (s->set_vflip)   s->set_vflip(s, 1);
    if (s->set_quality) s->set_quality(s, 10);
}

Differences from esp32-camera

  • Data pins pin_d0..pin_d7 must be 8 consecutive GPIOs (a hardware limitation of the PIO in pins instruction); validated at init
  • SCCB pins are hard-muxed (real I2C, not bit-banged like ESP32): SDA on even GPIOs, SCL on odd GPIOs, and the pair must route to sccb_i2c_port — SDA GP0/4/8...28 and SCL GP1/5/9...29 for I2C0, SDA GP2/6/10...26 and SCL GP3/7/11...27 for I2C1 (extended to GP47 on RP2350). Validated at init
  • On RP2350 boards with PSRAM (enabled via the core's PSRAM menu), frame buffers can live in PSRAM — set fb_location = PICO_CAMERA_FB_IN_PSRAM to open up larger frame sizes. The default PICO_CAMERA_FB_AUTO uses PSRAM when available and falls back to SRAM otherwise (unlike esp32-camera, which fails init). RP2040 always uses SRAM (264KB): for RGB565 stay at or below QVGA in practice; the JPEG buffer is estimated as width*height/4 + 8KB
  • SCCB can share an already initialized I2C bus: set pin_sccb_sda = -1 and pick the bus with sccb_i2c_port (e.g. 1 to reuse Wire1, esp32-camera parity). You must Wire1.begin() (or i2c_init()) first; the library never touches or deinitializes a shared bus
  • grab_mode is not supported: pico_camera_fb_get() captures one frame blocking (equivalent to CAMERA_GRAB_WHEN_EMPTY)

Examples

push_image_to_python host viewer
push_image_to_python: a live OV2640 JPEG stream rendered by the Python viewer

Documentation

License

MIT