본문으로 건너뛰기
cccskills
무료GitHub에 공개

embedded-rust

Use when writing no_std Cortex-M or RISC-V firmware in Rust with cortex-m-rt, probe-rs, defmt, RTIC, or a panic handler. Not for no_std library constraints: use rust-no-std.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(3)

  • SKILL.md8.4 KB
  • agents/openai.yaml187 B
  • references/embedded-rust-targets.md2.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Embedded Rust

Contract

FieldBound contract
TriggerA Rust firmware project needs to be set up or fixed: #![no_std] #![no_main] layout, cortex-m-rt startup, probe-rs flashing and log streaming, defmt logging, an RTIC application, or the choice of panic handler.
AuthorityReversible local: writes only the project files under the directory the user names (Cargo.toml, .cargo/config.toml, memory.x, src/); rollback is deleting that directory or reverting it in version control. No remote mutation.
Side effectNew or edited project files in the named directory. Flashing a board writes the board's flash, which the next cargo run overwrites.
Donecargo build --release produces an ELF for the target triple, cargo run --release flashes it and streams defmt output to the terminal, and exactly one panic handler is linked.

Inputs

  • MCU part and its probe-rs chip name (probe-rs chip list prints the names).
  • Core: which Cortex-M or RISC-V core, and whether it has an FPU. This picks the target triple.
  • Flash and RAM origin and size from the datasheet (for memory.x).
  • Concurrency model: plain #[entry] loop, RTIC, or Embassy.
  • Debug probe on hand, or none (this picks the panic handler and the defmt transport).

Procedure

  1. Pick the target triple from the core and install it. Done when: rustup target add <triple> succeeds and the triple appears in rustc --print target-list. The full table is in references/embedded-rust-targets.md.

    CoreTarget triple
    Cortex-M0, M0+thumbv6m-none-eabi
    Cortex-M3thumbv7m-none-eabi
    Cortex-M4, M7 without FPUthumbv7em-none-eabi
    Cortex-M4F, M7Fthumbv7em-none-eabihf
    Cortex-M33 with FPUthumbv8m.main-none-eabihf
    RISC-V RV32IMACriscv32imac-unknown-none-elf
  2. Write Cargo.toml and .cargo/config.toml. Use edition 2024. The versions below are the current crates.io releases on 2026-09-05; run cargo add <crate> to take the current one rather than copying a number. debug = true in the release profile keeps DWARF for defmt and probe-rs; it does not change the flashed code size because debug info is not loaded to flash. Done when: cargo build --release links.

    # Cargo.toml
    [package]
    name = "my-firmware"
    version = "0.1.0"
    edition = "2024"
    
    [dependencies]
    cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
    cortex-m-rt = "0.7"
    defmt = "1"
    defmt-rtt = "1"
    panic-probe = { version = "1", features = ["print-defmt"] }
    
    [profile.release]
    opt-level = "s"
    lto = true
    codegen-units = 1
    debug = true
    
    # .cargo/config.toml
    [build]
    target = "thumbv7em-none-eabihf"
    
    [target.thumbv7em-none-eabihf]
    runner = "probe-rs run --chip STM32F411CEUx"
    rustflags = ["-C", "link-arg=-Tlink.x"]
    

    link.x is the linker script cortex-m-rt generates; it includes your memory.x:

    MEMORY
    {
      FLASH : ORIGIN = 0x08000000, LENGTH = 512K
      RAM   : ORIGIN = 0x20000000, LENGTH = 128K
    }
    
  3. Write the minimal program. #![no_std] drops the standard library, #![no_main] hands the entry point to cortex-m-rt, and the two as _ imports link the RTT transport and the panic handler without naming them. Done when: the program builds and cortex_m::Peripherals::take() is called at most once.

    #![no_std]
    #![no_main]
    
    use cortex_m_rt::entry;
    use defmt::info;
    use defmt_rtt as _;
    use panic_probe as _;
    
    #[entry]
    fn main() -> ! {
        info!("boot");
        let _core = cortex_m::Peripherals::take().unwrap();
        loop {
            info!("tick");
            cortex_m::asm::delay(8_000_000);
        }
    }
    
  4. Flash and stream logs with probe-rs. probe-rs run flashes, resets, and prints RTT and defmt output; probe-rs attach connects without reset or flash and keeps the running state. Done when: cargo run --release prints the info! lines.

    curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
    probe-rs list                      # connected probes
    probe-rs chip list | grep -i stm32 # chip names for --chip
    cargo run --release                # build, flash, stream defmt
    probe-rs attach --chip STM32F411CEUx target/thumbv7em-none-eabihf/release/my-firmware
    

    If probe-rs run fails to find a probe or chip, read probe-rs run --help and probe-rs list before changing the config.

  5. Log with defmt. defmt sends an interned string index plus raw arguments; the host decodes them from the ELF, so the ELF that is running must be the one the host reads. Done when: a #[derive(Format)] type prints through info!("{:?}", value).

    use defmt::{Format, error, info, warn};
    
    #[derive(Format)]
    struct Packet { id: u8, len: u16 }
    
    info!("temperature {} C", temp);
    warn!("stack {}/{}", used, total);
    error!("i2c {:?}", err);
    defmt::assert_eq!(result, expected);
    

    Transport: defmt-rtt needs a probe attached and is the default. defmt-semihosting works through a GDB or OpenOCD semihosting channel and is slower; use it when RTT is unavailable.

  6. For interrupt-driven concurrency, use RTIC 2. Tasks with binds are hardware interrupt handlers; software tasks run on the dispatcher interrupts you list. Shared resources are locked, so RTIC proves no data race at compile time. Done when: the RTIC app compiles and the bound ISR fires on the hardware event.

    #[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
    mod app {
        use defmt::info;
    
        #[shared]
        struct Shared { counter: u32 }
    
        #[local]
        struct Local {}
    
        #[init]
        fn init(_cx: init::Context) -> (Shared, Local) {
            periodic::spawn().unwrap();
            (Shared { counter: 0 }, Local {})
        }
    
        #[task(shared = [counter])]
        async fn periodic(mut cx: periodic::Context) {
            loop {
                let n = cx.shared.counter.lock(|c| { *c += 1; *c });
                info!("count {}", n);
                rtic_monotonics::systick::Systick::delay(500.millis()).await;
            }
        }
    
        #[task(binds = EXTI0, priority = 2)]
        fn button(_cx: button::Context) {
            info!("button");
        }
    }
    

    Cargo dependencies for this: rtic with the thumbv7-backend feature and rtic-monotonics with the cortex-m-systick feature. Embassy (embassy-executor) is the async alternative; pick one executor per binary.

  7. Pick exactly one panic handler. Two handlers produce a duplicate #[panic_handler] link error. Done when: Cargo.toml lists one of the crates below and the build links.

    CrateBehaviorUse when
    panic-haltInfinite loopProduction without a probe
    panic-probePrints the message through defmt, then a breakpointDevelopment with probe-rs
    panic-semihostingPrints through semihostingDevelopment under GDB or OpenOCD
    panic-resetResets the coreRecovery where a watchdog would reset anyway

Failure and recovery

SymptomCauseFix
can't find crate for coreTarget not installedrustup target add <triple>.
Link error naming memory.x or _stack_startmemory.x missing or not on the linker search pathPut memory.x next to Cargo.toml, or emit its directory from build.rs with cargo:rustc-link-search.
Duplicate #[panic_handler]Two panic crates linkedKeep one.
No defmt outputHost reads a different ELF than the one flashed, or RTT is not linkedRebuild and flash in one cargo run; keep use defmt_rtt as _;.
probe-rs reports no probeUSB permissions or no udev ruleRun probe-rs list; install the udev rules from the probe-rs docs.
HardFault at bootWrong MEMORY origins or FPU triple on a core without FPUCheck memory.x against the datasheet and the triple against the core.

Output

A project directory that builds for the target triple, flashes with cargo run --release, streams defmt logs, and links one panic handler, plus a note naming the target triple and the probe-rs chip name that were used.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

Use when configuring ADC sampling time, DMA-driven ADC, calibration, or DAC channel setup on bare-metal MCUs. Not for the DMA stream itself: use dma-baremetal.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

af-xdp

무료

Use when creating AF_XDP sockets, configuring UMEM and XSK rings, writing an XDP redirect program, or choosing copy versus zero-copy mode. Not for full kernel bypass: use dpdk.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

Use when a redacted, trimmed agent transcript must be appended to a GitHub PR or issue body, with human approval and preview. Not for automated or model-initiated insertion.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

agents-md

무료

Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential, publish, deploy, or irreversible changes.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

OutlineDriven의 스킬 모두 보기

이 스킬의 문제 신고