no_std basics
#![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;
Available modules
| Module |
Purpose |
core |
Basic language features |
alloc |
Heap allocation (requires allocator) |
compiler_builtins |
Compiler intrinsics |
embedded-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);
}
}
Common traits
| trait |
Operation |
OutputPin |
Set high/low level |
InputPin |
Read pin |
SpiBus |
SPI communication |
I2c |
I2C communication |
Serial |
Serial port |
Interrupt handling
#![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);
}
Memory management
Stack size
[profile.dev]
panic = "abort" # 减少二进制大小
[profile.release]
lto = true
opt-level = "z" # 最小化大小
Avoid dynamic allocation
// 用栈数组代替 Vec
let buffer: [u8; 256] = [0; 256];
// 或使用定长环形缓冲区
struct RingBuffer {
data: [u8; 256],
write_idx: usize,
read_idx: usize,
}
Peripheral access patterns
// 寄存器映射
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);
}
}
}
Common problems
| Problem |
Cause |
Solution |
| panic infinite loop |
No panic handler |
Implement #[panic_handler] |
| Stack overflow |
Nested interrupts or large local variables |
Increase stack, reduce local variables |
| Memory corruption |
Raw pointer operations |
Use safe abstraction |
| Program does not run |
Linker script problem |
Check startup code |
| Peripheral not responding |
Clock not enabled |
Configure RCC first |
Resource-constrained techniques
| Technique |
Effect |
opt-level = "z" |
Minimize size |
lto = true |
Link-time optimization |
panic = "abort" |
Remove unwinding |
codegen-units = 1 |
Better optimization |
| Avoid alloc |
Use stack or static arrays |
Project configuration example
[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 multithreading
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 and memory ordering
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);
}
Thread-local storage (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 embedded development
Basic setup
// 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
Interrupts and exceptions
// 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();
}
}
Memory barriers
// RISC-V 内存屏障
use riscv::asm;
/// 数据内存屏障 - 确保所有内存访问完成
fn data_memory_barrier() {
unsafe {
asm!("fence iorw, iorw");
}
}
/// 指令屏障 - 确保指令流更新可见
fn instruction_barrier() {
unsafe {
asm!("fence i, i");
}
}
Atomic operations
// 使用 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
}
}
Multicore synchronization
// 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 privilege levels
// 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 performance optimization
| Optimization point |
Method |
| Memory access |
Use unaligned access instructions (if supported) |
| Atomic operations |
Use A extension instructions |
| Multiplication and division |
Use M extension instructions |
| Vector operations |
Use V extension (RV64V) |
| Compressed instructions |
Use C extension to reduce code size |