rust-embedded
1
总安装量
1
周安装量
#49918
全站排名
安装命令
npx skills add https://github.com/huiali/rust-skills --skill rust-embedded
Agent 安装分布
trae
1
qoder
1
trae-cn
1
claude-code
1
antigravity
1
Skill 文档
åµå ¥å¼ä¸ no_std å¼å
æ ¸å¿é®é¢
å¦ä½å¨èµæºåéç¯å¢ææ²¡ææ ååºçæ åµä¸ç¼ç¨ï¼
no_std 䏿¯ Rust çåéï¼èæ¯ä¸ç§ä¸åçç¼ç¨æ¨¡å¼ã
no_std åºç¡
#![no_std]
// ä¸è½ä½¿ç¨ std, alloc, test
use core::panic::PanicMessage;
// å¿
é¡»å®ç° panic handler
#[panic_handler]
fn panic(info: &PanicMessage) -> ! {
loop {}
}
// å¯éï¼å®ä¹å
¨å±åé
å¨
#[global_allocator]
static ALLOC: some_allocator::Allocator = some_allocator::Allocator;
å¯ç¨æ¨¡å
| 模å | ç¨é |
|---|---|
core |
åºæ¬è¯è¨ç¹æ§ |
alloc |
å åé ï¼é allocatorï¼ |
compiler_builtins |
ç¼è¯å¨å ç½®å½æ° |
åµå ¥å¼-hal
use embedded_hal as hal;
use hal::digital::v2::OutputPin;
// æ½è±¡ç¡¬ä»¶è®¿é®
fn blink_led<L: OutputPin>(mut led: L) -> ! {
loop {
led.set_high().unwrap();
delay_ms(1000);
led.set_low().unwrap();
delay_ms(1000);
}
}
å¸¸ç¨ trait
| trait | æä½ |
|---|---|
OutputPin |
设置é«ä½çµå¹³ |
InputPin |
读åå¼è |
SpiBus |
SPI éä¿¡ |
I2c |
I2C éä¿¡ |
Serial |
ä¸²å£ |
䏿å¤ç
#![no_std]
#![feature(abi_vectorcall)]
use cortex_m::interrupt::{free, Mutex};
use cortex_m::peripheral::NVIC;
// å
±äº«ç¶æ
static MY_DEVICE: Mutex<Cell<Option<MyDevice>>> = Mutex::new(None);
#[interrupt]
fn TIM2() {
free(|cs| {
let device = MY_DEVICE.borrow(cs).take();
if let Some(dev) = device {
// å¤ç䏿
dev.handle();
MY_DEVICE.borrow(cs).set(Some(dev));
}
});
}
// å¯ç¨ä¸æ
fn enable_interrupt(nvic: &mut NVIC, irq: interrupt::TIM2) {
nvic.enable(irq);
}
å å管ç
æ 大å°
[profile.dev]
panic = "abort" # åå°äºè¿å¶å¤§å°
[profile.release]
lto = true
opt-level = "z" # æå°å大å°
é¿å 卿åé
// ç¨æ æ°ç»ä»£æ¿ Vec
let buffer: [u8; 256] = [0; 256];
// æä½¿ç¨å®é¿ç¯å½¢ç¼å²åº
struct RingBuffer {
data: [u8; 256],
write_idx: usize,
read_idx: usize,
}
å¤è®¾è®¿é®æ¨¡å¼
// å¯å卿 å°
const GPIOA_BASE: *const u32 = 0x4002_0000 as *const u32;
const GPIOA_ODR: *const u32 = (GPIOA_BASE + 0x14) as *const u32;
// å®å
¨æ½è±¡
mod gpioa {
use super::*;
pub fn set_high() {
unsafe {
GPIOA_ODR.write_volatile(1 << 5);
}
}
}
常è§é®é¢
| é®é¢ | åå | è§£å³ |
|---|---|---|
| panic æ»å¾ªç¯ | 没æ panic handler | å®ç° #[panic_handler] |
| æ æº¢åº | 䏿åµå¥æå¤§å±é¨åé | å¢å æ ãåå°å±é¨åé |
| å åæå | 裸æéæä½ | ç¨ safe abstraction |
| ç¨åºä¸è¿è¡ | 龿¥èæ¬é®é¢ | æ£æ¥ startup code |
| å¤è®¾ä¸ååº | æ¶éæªä½¿è½ | å é ç½® RCC |
èµæºåéæå·§
| æå·§ | ææ |
|---|---|
opt-level = "z" |
æå°åå¤§å° |
lto = true |
龿¥æ¶ä¼å |
panic = "abort" |
廿 unwinding |
codegen-units = 1 |
æ´å¥½çä¼å |
| é¿å alloc | ç¨æ æéææ°ç» |
项ç®é 置示ä¾
[package]
name = "my-firmware"
version = "0.1.0"
edition = "2024"
[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = "1.0"
nb = "1.0"
[profile.dev]
panic = "abort"
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
WebAssembly å¤çº¿ç¨
SharedArrayBuffer
// éè¦å¨æå¡å¨ç«¯é
ç½® Cross-Origin-Opener-Policy
// æµè§å¨æè½ä½¿ç¨ SharedArrayBuffer
// wasm-bindgen é
ç½®
[dependencies]
wasm-bindgen = { version = "0.2", features = ["enable-threads"] }
// ä½¿ç¨ atomic å
ååº
use std::sync::atomic::{AtomicUsize, Ordering};
static COUNTER: AtomicUsize = AtomicUsize::new(0);
#[wasm_bindgen]
pub fn increment_counter() -> usize {
COUNTER.fetch_add(1, Ordering::SeqCst)
}
#[wasm_bindgen]
pub fn get_counter() -> usize {
COUNTER.load(Ordering::SeqCst)
}
Atomics ä¸å ååº
use std::sync::atomic::{AtomicI32, Ordering};
// ä¸åå
ååºçæ§è½åå¯è§æ§æè¡¡
#[wasm_bindgen]
pub fn atomic_demo() {
let atom = AtomicI32::new(0);
// æå¼ºä¿è¯ï¼ææ
¢
atom.store(1, Ordering::SeqCst);
// éæ¾è¯ä¹ï¼ç产è
ï¼
atom.store(2, Ordering::Release);
// è·åè¯ä¹ï¼æ¶è´¹è
ï¼
let val = atom.load(Ordering::Acquire);
// æ¾æ£è¯ä¹ï¼æå¿«ï¼ä½å¯è½ reordered
atom.store(3, Ordering::Relaxed);
let val = atom.load(Ordering::Relaxed);
}
线ç¨å±é¨åå¨ (TLS)
// WASM 线ç¨å±é¨åå¨
use std::cell::RefCell;
thread_local! {
static THREAD_ID: RefCell<u32> = RefCell::new(0);
}
#[wasm_bindgen]
pub fn set_thread_id(id: u32) {
THREAD_ID.with(|tid| {
*tid.borrow_mut() = id;
});
}
#[wasm_bindgen]
pub fn get_thread_id() -> u32 {
THREAD_ID.with(|tid| *tid.borrow())
}
RISC-V åµå ¥å¼å¼å
åºç¡è®¾ç½®
// Cargo.toml
[package]
name = "riscv-firmware"
version = "0.1.0"
edition = "2024"
[dependencies]
riscv = "0.10"
embedded-hal = "1.0"
[profile.release]
opt-level = "z"
lto = true
䏿ä¸å¼å¸¸
// RISC-V 䏿å¤ç
#![no_std]
use riscv::register::{
mie::MIE,
mstatus::MSTATUS,
mip::MIP,
};
/// å¯ç¨æºå¨ä¸æ
pub fn enable_interrupt() {
// å¯ç¨å¤é¨ä¸æã计æ¶å¨ä¸æãè½¯ä»¶ä¸æ
unsafe {
MIE::set_mext();
MIE::set_mtimer();
MIE::set_msip();
// å
¨å±ä¸æä½¿è½
MSTATUS::set_mie();
}
}
/// ç¦ç¨ææä¸æ
pub fn disable_interrupt() {
unsafe {
MSTATUS::clear_mie();
}
}
å åå±é
// RISC-V å
åå±é
use riscv::asm;
/// æ°æ®å
åå±é - ç¡®ä¿ææå
å访é®å®æ
fn data_memory_barrier() {
unsafe {
asm!("fence iorw, iorw");
}
}
/// æä»¤å±é - ç¡®ä¿æä»¤æµæ´æ°å¯è§
fn instruction_barrier() {
unsafe {
asm!("fence i, i");
}
}
ååæä½
// ä½¿ç¨ riscv::atomic 模å
use riscv::asm::atomic;
fn atomic_add(dst: &mut usize, val: usize) {
unsafe {
// ä½¿ç¨ amoadd.w æä»¤
atomic::amoadd(dst as *mut usize, val);
}
}
fn compare_and_swap(ptr: &mut usize, old: usize, new: usize) -> bool {
unsafe {
// ä½¿ç¨ amoswap.w æä»¤
let current = atomic::amoswap(ptr as *mut usize, new);
current == old
}
}
夿 ¸åæ¥
// RISC-V æºå¨é´ä¸æ (IPI)
const M_SOFT_INT: *mut u32 = 0x3FF0_FFF0 as *mut u32;
fn send_soft_interrupt(core_id: u32) {
unsafe {
// è®¾ç½®è½¯ä»¶ä¸æä½
M_SOFT_INT.write_volatile(1 << core_id);
}
}
fn clear_soft_interrupt(core_id: u32) {
unsafe {
M_SOFT_INT.write_volatile(0);
}
}
RISC-V ç¹æçº§
// RISC-V ç¹æçº§æ£æ¥
use riscv::register::{mstatus, misa};
fn check_privilege_level() -> u8 {
// 读åå½åç¹æçº§
// 0 = User, 1 = Supervisor, 2 = Hypervisor, 3 = Machine
(mstatus::read().bits() >> 11) & 0b11
}
fn is_machine_mode() -> bool {
check_privilege_level() == 3
}
/// è·åå¯ç¨ç ISA æ©å±
fn get_isa_extensions() -> String {
let misa = misa::read();
format!("{:?}", misa)
}
RISC-V æ§è½ä¼å
| ä¼åç¹ | æ¹æ³ |
|---|---|
| å åè®¿é® | 使ç¨é对é½è®¿é®æä»¤ï¼å¦ææ¯æï¼ |
| ååæä½ | ä½¿ç¨ A æ©å±æä»¤ |
| ä¹é¤æ³ | ä½¿ç¨ M æ©å±æä»¤ |
| åéæä½ | ä½¿ç¨ V æ©å±ï¼RV64Vï¼ |
| å缩æä»¤ | ä½¿ç¨ C æ©å±åå°ä»£ç å¤§å° |