Tables ▾

M5Stack Cardputer ADV · Volume 3

RF Object Detection (WiFi CSI) on the Cardputer ADV — Volume 3: Hardware Reference, EXT-Bus Display Wiring, and IDF Firmware Architecture

The Cardputer ADV subsystems that matter for CSI sensing builds, the 2.8\" ILI9341 EXT-bus wiring reference, Sasquach's dual-screen UI split as the display model, the PlatformIO build target details, and the IDF CSI callback path with sprite-draw RAM discipline

3.1 About this volume

Volume 3 is the hardware and firmware architecture reference for CSI builds on the Cardputer ADV. Vol 1 introduced the constraints; Vol 2 reviewed the upstream firmware and the multi-link CSI direction. This volume covers: the platform hardware in detail, the 2.8″ ILI9341 EXT-bus wiring, the dual-screen UI model that the upstream firmware establishes, the PlatformIO build target, and the IDF CSI callback + sprite-draw firmware architecture that any fork needs to follow.

3.2 The Cardputer ADV — subsystems that matter for CSI

The full hardware reference is in the Cardputer ADV reference deep dive. This table focuses on what matters specifically for CSI sensing firmware:

Table 1 — The full hardware reference is in the [Cardputer ADV reference deep dive](/m5stack-cardputer-adv/vol-2/). This table focuses on what matters specifically for CSI sensing firmware

SubsystemPartWhy it matters for CSI builds
SoCESP32-S3FN8 — dual LX7 @ 240 MHz, 512 KB SRAM, no PSRAM, 8 MB flashCSI-capable chip. RAM ceiling is the dominant constraint (Vol 1 §4).
RadioWi-Fi 4 (2.4 GHz only) + BLE 5.0, shared single front-endCSI capture lives here. BLE scanning on the same radio competes — prioritize Wi-Fi for sensing.
Display (built-in)ST7789V2 1.14″ 240×135, SPIThe control deck. Small — keyboard-driven menus only while the external screen carries live data.
ExpansionGrove HY2.0-4P (I²C + switchable 5 V) + 14-pin EXT bus (UART/I²C/SPI, EXT-SPI CS = GPIO5)Path for the 2.8″ external display (CS = GPIO5, SCK = GPIO40, MOSI = GPIO14).
AudioES8311 codec + MEMS mic + 1 W speakerOn-board mic available for acoustic sensing at zero added BOM cost.
IMUBosch BMI270 6-axis (I²C 0x68)On-board motion sensor available for device-shake compensation and gesture-driven UI.
StoragemicroSD over SPI (CS = GPIO12), shared busSession logging — shares SPI with both displays; must be batched (Vol 1 §4 constraint 2).
Power1750 mAh LiPo, 3.3 V buck + 5 V Grove boost, ~120 mA idleBacklight-dominated. A second screen cuts runtime — factor this into any build with the 2.8″.
ToolchainArduino/PlatformIO, M5Unified/M5Cardputer, board m5stack-cardputer-advFlash custom builds to ota_0; M5Launcher stays on the factory slot as the recovery lifeline.

Two free channels. The on-board ES8311 mic and BMI270 IMU are already wired to the ESP32-S3. They are available for additional sensing applications — acoustic event detection and device-motion compensation respectively — at zero added BOM cost.

3.3 How Sasquach’s dual-screen build works

The Cardputer-CSI-Human-Detector firmware uses a 2.8″ ILI9341 SPI touchscreen mounted in a 3D-printed clamshell alongside the Cardputer ADV — the same physical platform as the dual-screen mod described in the Dual-Screen Clamshell Mod sub-project. The firmware establishes the UI model this sub-project inherits:

Table 2 — The Cardputer-CSI-Human-Detector firmware uses a 2.8″ ILI9341 SPI touchscreen mounted in a 3D-printed clamshell alongside the Cardputer ADV — the same physical platform as the dual-screen mod described in the [Dual-Screen Clamshell Mod](/m5stack-cardputer-adv/dual-screen-mod/) sub-project. The firmware establishes the UI model this sub-project inherits

RoleScreenWhat it shows
Data canvasExternal 2.8″ ILI9341 (320×240)Live CSI visualization — PPI sweep, vaporwave 3D render, motion graph; future: per-MAC motion traces
Control deckBuilt-in 1.14″ ST7789V2 (240×135)Presence banner, motion scalar bar, keyboard-driven menus, settings

The key architectural idea: the small screen is the control surface, the big screen is the data canvas. The keyboard drives the UI while the external panel renders live signal data without interruption. Both screens stay active simultaneously — the external panel does not freeze when the user navigates a menu.

The 2.8″ ILI9341 panel is a standard SPI touchscreen module. The critical engineering issue: it shares the SPI bus already used by the internal display and microSD card. This is solvable (distinct CS lines, bus_shared = true) but is the second dominant constraint of the platform — see Vol 1 §4.

3.4 EXT-bus wiring for the 2.8″ ILI9341

The external panel connects through the Cardputer ADV’s 14-pin EXT header. The wiring used by the upstream firmware:

Table 3 — The external panel connects through the Cardputer ADV's 14-pin EXT header. The wiring used by the upstream firmware

ILI9341 pinCardputer ADV / EXTNote
VCC3V3The ILI9341 module accepts 3.3 V logic + LED
GNDGNDCommon ground for the harness
CSEXT-SPI CS — GPIO5Its own chip-select — distinct from SD (GPIO12) and the internal display
DC / RSGPIO6Data/command select
RSTGPIO3Reset line (or tie to 3V3 + software reset)
SCKGPIO40Shared SPI clock
MOSIGPIO14Shared SPI data out
MISO— (unwired)ILI9341 display is write-only; MISO not needed
LED (backlight)3V3 (or PWM GPIO)PWM for power saving
T_* (touch)Optional — own SPI CS, or omitSasquach trimmed a touchscreen module; touch is a UI bonus

Bus configuration: SPI2 / FSPI, bus_shared = true, 27 MHz write clock. The three SPI devices (internal display, SD card, external panel) coexist on the same bus via distinct CS lines. The firmware manages bus arbitration explicitly — no simultaneous CS assertions.

Pin conflict note: GPIO3, 5, and 6 are also used by the Cap LoRa-1262 / GNSS module on the EXT bus. The external 2.8″ display and the Cap LoRa-1262 cannot be used simultaneously — they contend for the same pins. This is the same conflict documented in the Dual-Screen Clamshell Mod sub-project (Vol 1 §5, Constraint 2). A device with the ILI9341 wired to the EXT bus cannot also run the Cap LoRa.

3.5 Firmware architecture — IDF CSI callback and sprite-draw discipline

The upstream firmware is an Arduino/PlatformIO application that uses the ESP-IDF CSI API directly alongside M5Unified. Arduino cannot expose raw CSI — the low-level esp_wifi_set_csi_rx_cb callback path requires dropping into the IDF. PlatformIO makes this seamless: M5Unified and M5GFX handle display management at the Arduino layer while the CSI callback is registered directly via the IDF Wi-Fi driver API.

3.5.1 IDF CSI callback registration

// ESP-IDF CSI setup (call after WiFi.begin() connects)
wifi_csi_config_t csi_cfg = {
    .lltf_en = true,        // legacy long training field
    .htltf_en = true,
    .stbc_htltf2_en = true,
    .ltf_merge_en = true,
    .channel_filter_en = false,
    .manu_scale = false,
};
esp_wifi_set_csi_config(&csi_cfg);
esp_wifi_set_csi_rx_cb(csiCallback, nullptr);
esp_wifi_set_csi(true);
esp_wifi_set_promiscuous(true);
esp_wifi_set_promiscuous_rx_cb(sniffCallback);

The callback receives a wifi_csi_info_t pointer on every CSI-bearing frame. The upstream callback is marked IRAM_ATTR (runs in IRAM for lower latency); as noted in Vol 2, the computationally heavy variance math should be offloaded to a FreeRTOS task via queue rather than running inline in the callback.

3.5.2 Sprite-draw discipline — no full framebuffer

The standing RAM rule for any display firmware on this platform:

// CORRECT — two M5GFX sprites, drawn small and pushed scaled
M5Canvas spr_left(&M5.Lcd);           // or &external_display
spr_left.createSprite(WIDTH/2, HEIGHT);
spr_left.fillSprite(BLACK);
// ... draw into spr_left ...
spr_left.pushRotateZoom(&external_display, cx, cy, 0, scale, scale);
spr_left.deleteSprite();

// WRONG — this alone consumes 154 KB of heap (320×240×2)
M5Canvas full_canvas(&external_display);
full_canvas.createSprite(320, 240);    // 153,600 bytes — leaves no room for Wi-Fi + CSI

The upstream firmware’s earlier 32 KB composite buffer was dropped for exactly this reason. Any fork that reintroduces a full-panel back-buffer will hit heap exhaustion when Wi-Fi connects and CSI buffers are allocated.

3.5.3 Conceptual firmware loop

A CSI sensing firmware on this platform follows this structure:

void loop() {
  M5.update();                     // keyboard, buttons, touch
  csi_pump();                      // drain the CSI ring buffer (queue → task result)
  uint8_t mode = check_imu();      // BMI270: is the device being held still?

  if (mode == STABLE) {
    draw_csi_sensorgram(BIG);      // subcarrier waterfall / per-MAC traces on 2.8"
  } else {
    draw_motion_scalar(BIG);       // blended motion bar on 2.8"
  }
  draw_status(SMALL);              // built-in 1.14": keyboard-driven control deck
  sd_log_batch();                  // RAM buffer → periodic SD flush (never per-frame)
}

Design rules embedded in this structure:

  • No full back-buffer for the 2.8″ — all rendering uses sprite/region draws.
  • CSI pump is non-blocking — the callback pushes to a queue; the main loop drains results from a task. The loop never blocks on CSI arrival.
  • SD logging is batched — accumulate in a RAM buffer and flush on a timer or size threshold, never on every CSI frame.
  • Both screens always active — the external panel renders live data continuously; the built-in screen handles menu navigation.

3.6 Build for the Cardputer ADV — PlatformIO target

The upstream platformio.ini targets m5stack-stamps3 (the original Cardputer / generic StampS3 target). For any ADV build, change this to m5stack-cardputer-adv. The ADV has different GPIO assignments, a different partition layout, and different SPI bus configuration — a binary built for m5stack-stamps3 will not run correctly on the ADV.

; platformio.ini fragment — ADV-correct target
[env:cardputer-csi-adv]
platform = espressif32
board = m5stack-cardputer-adv
framework = arduino
build_flags =
    -D RADAR_CSI=1
lib_deps =
    m5stack/M5Unified
    m5stack/M5GFX

Flash to ota_0 (hold Esc at power-on to return to M5Launcher if a build crash-loops):

pio run -e cardputer-csi-adv -t upload
pio device monitor -b 115200

3.7 Resources

  • Upstream firmware: code/firmware/upstream/src/main.cpp (full IDF CSI callback implementation), ext_panel.h (external display driver), radar_link.h (ring-buffer parser).
  • Cardputer ADV reference: hardware deep dive, pinout + EXT bus, flashing + recovery.
  • Dual-Screen Clamshell Mod sub-project: /m5stack-cardputer-adv/dual-screen-mod/ — the physical platform this firmware runs on.
  • M5GFX canvas/sprite API: https://github.com/m5stack/M5GFX
  • ESP-IDF Wi-Fi CSI API: esp_wifi_set_csi_rx_cb in the ESP-IDF Programming Guide.