Token导航 LogoToken导航TokenDH.com
开发执行命令github未标认证来源可访问许可证需确认审计异常

mcu-embedded-reviewMCU 嵌入式审查

Agent Skill

mcu-embedded-review 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

245

周安装

10

GitHub Stars

31

下载量

78
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:mcu-embedded-review(MCU 嵌入式审查)
来源仓库:https://github.com/ecto/muni
仓库路径:skills/mcu-embedded-review
安装命令:
npx skills add https://github.com/ecto/muni --skill mcu-embedded-review
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/ecto/muni --skill mcu-embedded-review

简介

用于处理 GitHub 仓库、Issue 和 Pull Request 协作信息。

  • 适合围绕代码变更或仓库状态进行整理分析。mcu-embedded-review 属于开发类 Skill,可作为该场景下的辅助能力补充。
  • 通过 GitHub 安装,建议核验权限范围和命令执行风险。
  • 使用前应确认维护状态及是否会触发网络请求。
  • 可结合原始 README 了解具体操作流程。

SKILL.md

MCU Embedded Firmware Code Review Skill

This skill provides comprehensive code review for embedded Rust firmware targeting RP2350 and ESP32-S3 microcontrollers used in the BVR rover system.

Overview

The BVR uses two MCU platforms for peripheral control:

  1. RP2350 (Pico 2 W): LED controllers, USB peripherals
  2. ESP32-S3 (Heltec): Tool attachments, LoRa communication, OLED display

Both run Rust in no_std environments with hardware-specific runtimes and memory constraints.

Architecture:

mcu/
├── bins/
│   ├── rp2350/         # Pico 2 W binaries (LED controller, etc.)
│   │   └── src/main.rs
│   └── esp32s3/        # Heltec binaries (attachments, SLCAN)
│       └── src/main.rs
├── crates/
│   ├── mcu-core/       # Shared protocol and types
│   ├── mcu-leds/       # LED controller library
│   └── ...

Key Differences:

FeatureRP2350 (Pico 2 W)ESP32-S3 (Heltec)
RuntimeEmbassy async (#[embassy_executor::main])Polling loop (#[main])
Memory520 KB SRAM, static allocation512 KB SRAM, heap allocation
EditionRust 2021Rust 2024
LED ControlPIO state machine (WS2812)RMT peripheral (WS2811/WS2812)
USBUSB CDC serial (device mode)USB serial (via UART bridge)
DisplayNoneOLED SSD1306 (I2C)
WirelessWiFi (Pico W chip)WiFi, BLE, LoRa
CANExternal MCP2515 (SPI)Built-in TWAI (CAN 2.0)

RP2350 (Pico 2 W) Patterns

Embassy Async Runtime

Location: mcu/bins/rp2350/src/main.rs

Key Points to Review:

  • #[embassy_executor::main] on main function
  • Async main signature: async fn main(spawner: Spawner)
  • Tasks spawned with spawner.spawn(task_name()).unwrap()
  • All peripherals initialized before spawning tasks
  • Interrupt bindings with bind_interrupts! macro

Example Pattern:

// Good: Embassy async main
#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // 1. Initialize peripherals
    let p = embassy_rp::init(Default::default());

    // 2. Bind interrupts
    bind_interrupts!(struct Irqs {
        USBCTRL_IRQ => InterruptHandler<USB>;
    });

    // 3. Create drivers
    let driver = Driver::new(p.USB, Irqs);

    // 4. Spawn tasks
    spawner.spawn(usb_task(driver)).unwrap();
    spawner.spawn(led_controller_task(p.PIO0)).unwrap();

    // 5. Main loop (or empty if all work in tasks)
    loop {
        Timer::after_millis(1000).await;
    }
}

Red Flags:

  • Blocking calls in async context (std::thread::sleep)
  • Missing .await on async operations
  • Unwrapping spawner (should handle spawn errors)
  • Peripherals not moved into tasks (ownership violation)

Embassy Tasks

Key Points to Review:

  • Task functions marked with #[embassy_executor::task]
  • Async signature
  • Infinite loop or explicit return
  • Error handling (log errors, don't panic)

Example Pattern:

// Good: Embassy task
#[embassy_executor::task]
async fn led_controller_task(mut pio: PIO0) {
    loop {
        // Wait for command
        let cmd = LED_COMMAND_CHANNEL.receive().await;

        // Update LEDs
        match update_leds(&mut pio, cmd) {
            Ok(_) => {}
            Err(e) => error!("LED update failed: {:?}", e),
        }
    }
}

Static Memory Allocation

Purpose: No heap allocator in RP2350, all memory must be static.

Key Points to Review:

  • StaticCell used for static mut data
  • Global statics wrapped in static with StaticCell
  • No Box, Vec, String (heap types)
  • Arrays with fixed sizes

Example Pattern:

use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::{Channel, Sender, Receiver};
use static_cell::StaticCell;

// Good: Static channel for inter-task communication
static LED_CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, LedCommand, 8>> = StaticCell::new();

fn init_channel() -> &'static Channel<CriticalSectionRawMutex, LedCommand, 8> {
    LED_CHANNEL.init(Channel::new())
}

// Good: Static USB buffers
static EP_MEMORY: StaticCell<[u8; 1024]> = StaticCell::new();
static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();

// Bad: Heap allocation (won't compile in no_std without alloc)
// let vec = vec![1, 2, 3];  // ❌ No Vec
// let string = String::from("hello");  // ❌ No String

Red Flags:

  • Heap types (Vec, String, Box)
  • Missing StaticCell wrapper for static mut
  • Unbounded buffers (use fixed-size arrays)

See: rp2350-patterns.md for detailed patterns.

PIO for WS2812 LEDs

Purpose: Programmable I/O state machine generates precise timing for WS2812 protocol.

Key Points to Review:

  • PIO program loaded with pio.load_program()
  • State machine configured with correct frequency
  • DMA used for efficient data transfer
  • Color data in GRB format (not RGB)

WS2812 Protocol:

  • Bit 0: 400ns high, 850ns low
  • Bit 1: 800ns high, 450ns low
  • Reset: >50µs low

Example Pattern:

// Good: PIO-based WS2812 driver
use embassy_rp::pio::{Pio, Common, StateMachine};

async fn init_ws2812(pio: PIO0, pin: PIN_25) -> Ws2812<'static> {
    let Pio { mut common, sm0, .. } = Pio::new(pio);

    // Load PIO program (bit-bangs WS2812 protocol)
    let prg = pio_proc::pio_asm!(
        ".side_set 1 opt",
        ".wrap_target",
        "bitloop:",
        "  out x, 1       side 0 [1]",  // Shift out 1 bit
        "  jmp !x do_zero side 1 [2]",  // High if bit 1
        "do_one:",
        "  jmp bitloop    side 1 [4]",  // Stay high (800ns)
        "do_zero:",
        "  nop            side 0 [4]",  // Go low (400ns)
        ".wrap"
    );

    let program = common.load_program(&prg.program);

    // Configure state machine
    let mut cfg = Config::default();
    cfg.set_out_pins(&[&pin]);
    cfg.set_clock_divider(125);  // 800kHz for WS2812 timing

    let ws2812 = Ws2812::new(sm0, pin, program, cfg);
    ws2812
}

// Send color data (GRB format!)
async fn set_led_color(ws2812: &mut Ws2812<'_>, index: usize, r: u8, g: u8, b: u8) {
    let color = ((g as u32) << 16) | ((r as u32) << 8) | (b as u32);  // GRB
    ws2812.write(&[color]).await;
}

Red Flags:

  • RGB byte order (should be GRB for WS2812)
  • Incorrect clock divider (breaks timing)
  • Blocking write (should use DMA + await)
  • Missing reset delay (>50µs)

USB CDC Serial

Purpose: USB serial for debugging and SLCAN bridge.

Key Points to Review:

  • USB driver created with Driver::new()
  • CDC-ACM class instantiated
  • Read/write methods awaited
  • Line coding handled (baud rate, etc.)

Example Pattern:

use embassy_usb::class::cdc_acm::{CdcAcmClass, State};

#[embassy_executor::task]
async fn usb_task(driver: Driver<'static, USB>) {
    let mut config = embassy_usb::Config::new(0x1234, 0x5678);
    config.manufacturer = Some("Muni Robotics");
    config.product = Some("BVR LED Controller");

    let mut builder = Builder::new(driver, config, /* ... */);

    // Create CDC-ACM class
    let mut state = State::new();
    let mut cdc = CdcAcmClass::new(&mut builder, &mut state, 64);

    let usb = builder.build();

    loop {
        // Read from USB
        let mut buf = [0u8; 64];
        let n = cdc.read_packet(&mut buf).await.unwrap();

        // Echo back (for testing)
        cdc.write_packet(&buf[..n]).await.unwrap();
    }
}

ESP32-S3 (Heltec) Patterns

Polling Loop (No Async)

Location: mcu/bins/esp32s3/src/main.rs

Key Points to Review:

  • #[main] entry point (not #[embassy_executor::main])
  • Infinite loop with non-blocking checks
  • delay.delay_millis() for timing
  • UART read_ready() for non-blocking reads

Example Pattern:

// Good: Polling loop
#[main]
fn main() -> ! {
    // 1. Initialize peripherals
    let peripherals = Peripherals::take();
    let mut delay = Delay::new();

    // 2. Initialize UART
    let mut uart = Uart::new(peripherals.UART0, /* ... */);

    // 3. Main loop
    loop {
        // Non-blocking UART read
        if uart.read_ready() {
            let mut buf = [0u8; 64];
            if let Ok(n) = uart.read(&mut buf) {
                process_command(&buf[..n]);
            }
        }

        // Update LEDs
        update_leds();

        // Small delay (don't busy-wait)
        delay.delay_millis(1);
    }
}

Red Flags:

  • Blocking reads (uart.read() without read_ready())
  • Busy-wait loop (no delay)
  • Async/await syntax (ESP32 uses blocking)

See: esp32s3-patterns.md for detailed patterns.

Heap Allocation (esp-alloc)

Purpose: ESP32-S3 has a heap allocator, allows Vec, String, etc.

Key Points to Review:

  • esp_alloc::heap_allocator!() called in main
  • Heap types used sparingly (still embedded)
  • Fixed-size buffers preferred for critical paths
  • No unbounded growth (memory leaks)

Example Pattern:

use esp_alloc as _;

#[main]
fn main() -> ! {
    // Initialize heap allocator
    esp_alloc::heap_allocator!();

    // Now can use heap types (use sparingly!)
    let mut buffer = Vec::with_capacity(256);  // Pre-allocate

    loop {
        // Heap allocation okay for non-critical paths
        let message = String::from("Status: OK");
        send_message(&message);

        buffer.clear();  // Reuse buffer (don't re-allocate)
    }
}

Best Practice: Use heap for initialization and infrequent operations, not in hot loops.

RMT for WS2811/WS2812 LEDs

Purpose: Remote Control Transceiver generates precise pulse sequences.

Key Points to Review:

  • RMT channel configured with correct clock
  • Pulse sequences match WS2812 timing
  • Blocking transmit or interrupt-driven
  • Memory limits (8 RMT channels, 64 items each)

Example Pattern:

use esp_hal::rmt::{Rmt, TxChannel};

fn init_rmt_leds(rmt: RMT, pin: GPIO48) -> TxChannel<'static, 0> {
    let rmt = Rmt::new(rmt, 80u32.MHz()).unwrap();  // 80MHz clock

    let tx_config = TxChannelConfig {
        clk_divider: 1,
        idle_output_level: false,
        carrier_modulation: false,
        idle_output: true,
    };

    let mut channel = rmt.channel0.configure(pin, tx_config).unwrap();

    // WS2812 pulse timings (in RMT ticks)
    // Bit 0: 400ns high, 850ns low
    // Bit 1: 800ns high, 450ns low
    // Each tick = 12.5ns at 80MHz

    channel
}

fn send_pixel(channel: &mut TxChannel, r: u8, g: u8, b: u8) {
    let grb = ((g as u32) << 16) | ((r as u32) << 8) | (b as u32);  // GRB order

    for bit in (0..24).rev() {
        let is_one = (grb >> bit) & 1 == 1;
        let (high, low) = if is_one {
            (64, 32)  // 800ns, 400ns at 80MHz
        } else {
            (32, 64)  // 400ns, 800ns
        };

        channel.transmit(&[(high, true, low, false)]).unwrap();
    }
}

Red Flags:

  • RGB byte order (should be GRB)
  • Incorrect timing calculations
  • RMT buffer overflow (>64 items)

OLED Display (SSD1306)

Purpose: Status display for standalone operation.

Key Points to Review:

  • I2C initialized with correct frequency
  • SSD1306 driver initialized
  • Display cleared on startup
  • Updates not too frequent (I2C is slow)

Example Pattern:

use ssd1306::{Ssd1306, mode::BufferedGraphicsMode, prelude::*, I2CDisplayInterface};

fn init_display(i2c: I2C0, sda: GPIO17, scl: GPIO18) -> Ssd1306<I2CInterface<I2C0>, ...> {
    let i2c = I2c::new(i2c, sda, scl, 400u32.kHz()).unwrap();
    let interface = I2CDisplayInterface::new(i2c);

    let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
        .into_buffered_graphics_mode();

    display.init().unwrap();
    display.clear();
    display.flush().unwrap();

    display
}

fn update_status(display: &mut Ssd1306<...>, status: &str) {
    display.clear();
    Text::new(status, Point::new(0, 0), MonoTextStyle::new(&FONT_6X10, BinaryColor::On))
        .draw(display)
        .unwrap();
    display.flush().unwrap();
}

LED Controller Library

Location: mcu/crates/mcu-leds/src/lib.rs

LED Mode State Machine

Purpose: Manage LED patterns for rover state indication.

Key Points to Review:

  • LedMode enum with all patterns (Off, Solid, Pulse, Chase, Flash)
  • State machine updates mode based on CAN messages
  • Smooth transitions with wipe animation
  • Convenience methods for rover states (idle(), teleop(), etc.)

LED Modes:

  • Off: All LEDs off
  • Solid(r, g, b, brightness): Fixed color
  • Pulse(r, g, b, period_ms): Breathing effect (sine wave)
  • Flash(r, g, b, period_ms): On/off strobe
  • Chase(r, g, b, speed): Moving pattern

Rover State Convenience Methods:

impl LedMode {
    pub fn idle() -> Self {
        Self::Solid(0, 0, 255, 200)  // Blue solid
    }

    pub fn teleop() -> Self {
        Self::Pulse(0, 255, 0, 2000)  // Green pulse, 2s period
    }

    pub fn autonomous() -> Self {
        Self::Pulse(0, 255, 255, 1500)  // Cyan pulse, 1.5s period
    }

    pub fn estop() -> Self {
        Self::Flash(255, 0, 0, 200)  // Red flash, 200ms (urgent!)
    }

    pub fn fault() -> Self {
        Self::Flash(255, 165, 0, 500)  // Orange flash, 500ms
    }
}

Key Points to Review:

  • E-stop flash is fast (200ms) for maximum visibility
  • Pulse periods reasonable (1-3 seconds)
  • Brightness clamped to [0, 255]
  • Color values clamped to [0, 255]

Animation System

Purpose: Smooth transitions and effects.

Key Points to Review:

  • Wipe transition with soft edge (gradient blend)
  • Pulse uses sine wave (smooth breathing)
  • Chase wraps around LED strip
  • Frame rate consistent (30-60 Hz)

Pulse Animation:

// Good: Sine wave pulse
fn pulse_brightness(base: u8, time_ms: u32, period_ms: u32) -> u8 {
    let phase = (time_ms % period_ms) as f32 / period_ms as f32;
    let sine = ((phase * 2.0 * PI).sin() + 1.0) / 2.0;  // 0.0 to 1.0
    let min_brightness = base / 2;
    let max_brightness = base;

    (min_brightness as f32 + (max_brightness - min_brightness) as f32 * sine) as u8
}

CAN Attachment Protocol

Location: mcu/crates/mcu-core/src/protocol.rs

ID Scheme

CAN ID Range: 0x200-0x2FF (16 attachment slots, 0x10 offset each)

Per-Attachment Messages (8 message types per attachment):

  • +0x00: Heartbeat (A → H, periodic beacon)
  • +0x01: Identify request (H → A, query identity)
  • +0x02: Identity response (A → H, device info)
  • +0x03: Command (H → A, control attachment)
  • +0x04: Acknowledgment (A → H, command ACK)
  • +0x05: Sensor data (A → H, periodic readings)
  • +0x06: Configuration (H → A, set parameters)
  • +0x07: Error report (A → H, fault indication)

Example: Attachment 0 (base 0x200)

  • Heartbeat: 0x200
  • Command: 0x203
  • Sensor: 0x205

Key Points to Review:

  • CAN IDs calculated as BASE + SLOT * 0x10 + OFFSET
  • Extended CAN IDs used (29-bit)
  • Heartbeat sent at 1 Hz
  • Commands acknowledged within 100ms

See: Firmware skill can-protocol.md for full protocol.

SLCAN Protocol

Purpose: Serial Line CAN bridge for debugging via USB.

Location: mcu/bins/esp32s3/src/slcan.rs

Frame Format

Standard Frame:

t<ID><LEN><DATA>\r

Extended Frame:

T<ID><LEN><DATA>\r

Example:

T00000B0010A\r       # Extended ID 0x0B00, length 1, data 0x0A
t10348AABBCCDD\r     # Standard ID 0x103, length 4, data 0xAABBCCDD

Commands

CommandDescriptionResponse
O\rOpen CAN bus\r (OK)
C\rClose CAN bus\r
S4\rSet bitrate to 500kbps\r
V\rGet versionV1234\r
N\rGet serial numberNABCD\r

Key Points to Review:

  • Frame parsing validates ID length (3 or 8 hex digits)
  • Data length checked (0-8 bytes)
  • Invalid commands return error (e.g., \x07)
  • Carriage return (\r) terminates every message

Example Pattern:

// Good: SLCAN command parsing
fn parse_slcan(cmd: &[u8]) -> Result<SlcanCommand, SlcanError> {
    if cmd.is_empty() || cmd[cmd.len() - 1] != b'\r' {
        return Err(SlcanError::MissingCR);
    }

    match cmd[0] {
        b'O' => Ok(SlcanCommand::Open),
        b'C' => Ok(SlcanCommand::Close),
        b'S' => {
            // Parse bitrate (S0-S8)
            let rate = cmd[1] - b'0';
            if rate > 8 {
                return Err(SlcanError::InvalidBitrate);
            }
            Ok(SlcanCommand::SetBitrate(rate))
        }
        b't' => parse_standard_frame(&cmd[1..]),
        b'T' => parse_extended_frame(&cmd[1..]),
        _ => Err(SlcanError::UnknownCommand),
    }
}

See: esp32s3-patterns.md for full SLCAN implementation.

Memory Constraints

RP2350 (Pico 2 W)

SRAM: 520 KB total

  • Stack: ~16 KB
  • Static data: ~50 KB (USB buffers, channels, etc.)
  • Available: ~450 KB

Flash: 4 MB

  • Program: ~100 KB
  • Data: Plenty of space

Key Points to Review:

  • Stack size reasonable (<16 KB)
  • No large arrays on stack (use static)
  • StaticCell used for static mut data
  • No unbounded recursion

ESP32-S3 (Heltec)

SRAM: 512 KB total

  • Heap: ~400 KB (configurable)
  • Stack: ~8 KB per task
  • DMA: ~50 KB

Flash: 8 MB

  • Program: ~500 KB
  • SPIFFS/LittleFS: ~7 MB

Key Points to Review:

  • Heap allocations tracked (no leaks)
  • Large buffers allocated once (not per loop)
  • Stack size per task reasonable

Testing Embedded Code

Unit Tests (no_std)

Key Points to Review:

  • #[cfg(test)] module for unit tests
  • Tests use #[test] attribute
  • Mock hardware with traits
  • No std imports in tests

Example Pattern:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_led_mode_pulse() {
        let mode = LedMode::Pulse(255, 0, 0, 1000);
        match mode {
            LedMode::Pulse(r, g, b, period) => {
                assert_eq!(r, 255);
                assert_eq!(period, 1000);
            }
            _ => panic!("Wrong mode"),
        }
    }
}

Integration Tests (on-device)

Pattern: Use defmt logging and probe-rs for debugging.

# Flash and run with logging
cargo run --release
# or
probe-rs run --chip RP2350

Common Mistakes

❌ Async on ESP32-S3

// WRONG: ESP32 doesn't use Embassy
#[embassy_executor::main]
async fn main(spawner: Spawner) {  // ❌ Won't compile
    // ...
}

✅ Correct ESP32-S3 Entry

// CORRECT: Blocking main
#[main]
fn main() -> ! {
    loop {
        // ...
    }
}

❌ Heap Types on RP2350

// WRONG: No heap allocator
let vec = vec![1, 2, 3];  // ❌ Won't compile (no alloc)

✅ Correct RP2350 Storage

// CORRECT: Static array
static DATA: StaticCell<[u8; 16]> = StaticCell::new();

❌ RGB Instead of GRB

// WRONG: WS2812 expects GRB
let color = (r as u32) << 16 | (g as u32) << 8 | b as u32;  // ❌ RGB

✅ Correct GRB Order

// CORRECT: GRB for WS2812
let color = (g as u32) << 16 | (r as u32) << 8 | b as u32;  // ✅ GRB

References and Additional Resources

For more detailed information, see:

Quick Review Commands

# Build RP2350
cd mcu
cargo build --release -p rover-leds

# Build ESP32-S3
cd mcu/bins/esp32s3
cargo build --release

# Flash RP2350 (requires picotool)
picotool load target/thumbv8m.main-none-eabihf/release/rover-leds -t elf -f

# Flash ESP32-S3 (requires espflash)
espflash flash --monitor target/xtensa-esp32s3-none-elf/release/heltec-attachment

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.64%
按下载量换算29

Claude

26.64%
按下载量换算21

Cursor

17.65%
按下载量换算14

Gemini CLI

8.29%
按下载量换算6

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

通过

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/ecto/muni --skill mcu-embedded-review 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills