一、中断处理的基本概念

在嵌入式系统中,中断就像是你在专心写代码时突然有人拍你肩膀——系统必须停下当前任务,去处理更紧急的事情。Rust作为一门系统级语言,天生适合嵌入式开发,其中断处理机制既安全又高效。

中断的核心是中断向量表中断服务函数(ISR)。中断向量表是一张“地图”,告诉CPU发生中断时该跳转到哪里执行;ISR则是具体处理中断的代码。优先级配置则决定哪个中断更重要,可以插队。

二、Rust中的中断向量表实现

在Rust嵌入式开发中(以cortex-m系列为例),中断向量表通常通过#[interrupt]属性和链接脚本定义。下面是一个完整示例:

// 技术栈:cortex-m-rt(Rust嵌入式运行时)
use cortex_m_rt::entry;
use cortex_m_rt::exception;

// 定义中断向量表(部分示例)
#[link_section = ".vector_table.interrupts"]
#[no_mangle]
pub static __INTERRUPTS: [Option<unsafe extern "C" fn()>; 240] = [
    Some(exti0),    // 外部中断0
    Some(usart1),   // 串口1中断
    // ...其他中断
    None; 234       // 预留空位
];

// 中断服务函数
#[interrupt]
fn exti0() {
    // 处理外部中断0的逻辑
    unsafe { (*GPIOA::ptr()).odr.modify(|_, w| w.odr0().set_bit()); }
}

#[entry]
fn main() -> ! {
    loop {}
}

注释说明

  • #[link_section]将向量表放在特定内存段(需配合链接脚本)。
  • unsafe extern "C"确保函数符合C ABI,能被硬件调用。

三、中断服务函数的编写要点

Rust的ISR需要关注共享数据安全延迟处理。下面是一个带优先级和资源共享的示例:

// 技术栈:cortex-m + bare-metal(无OS)
use cortex_m::interrupt::{self, Mutex};
use core::cell::RefCell;

// 全局共享数据(如传感器读数)
static SENSOR_DATA: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));

#[interrupt]
fn usart1() {
    interrupt::free(|cs| {
        // 安全访问共享数据
        let data = SENSOR_DATA.borrow(cs).borrow_mut();
        *data += 1;
    });

    // 高优先级任务立即处理
    if *data > 100 {
        emergency_shutdown();
    }
}

关键点

  1. MutexRefCell解决多中断竞争问题。
  2. interrupt::free保证原子操作。

四、优先级配置实战

在Cortex-M中,优先级通过NVIC(嵌套向量中断控制器)设置。Rust的cortex-m库提供了简洁的API:

use cortex_m::peripheral::NVIC;

fn configure_priority() {
    unsafe {
        // 设置串口中断优先级为2(数字越小优先级越高)
        NVIC::unmask(interrupt::USART1);
        NVIC::set_priority(interrupt::USART1, 2);
    }
}

注意事项

  • 优先级位数因芯片而异(如STM32F4支持4位优先级)。
  • 某些中断(如NMI)优先级不可配置。

五、应用场景与技术对比

典型场景

  • 实时控制系统(如无人机电机控制)
  • 低功耗设备(中断唤醒+快速处理)

Rust优势

  • 所有权机制避免数据竞争
  • 零成本抽象不影响性能

缺点

  • 学习曲线较陡(需理解unsafe和内存模型)
  • 部分芯片支持库不完善

六、总结与最佳实践

  1. 安全第一:ISR中尽量少用unsafe,共享数据必须加锁。
  2. 性能优化:长任务拆分为“紧急处理+后台队列”。
  3. 测试要点:用硬件模拟器验证中断嵌套行为。

最后附一个综合示例:

// 技术栈:stm32f4xx-hal(STM32硬件抽象层)
use stm32f4xx_hal::{
    interrupt,
    pac,
    prelude::*,
};

#[interrupt]
fn TIM2() {
    let dp = unsafe { pac::Peripherals::steal() };
    dp.TIM2.sr.modify(|_, w| w.uif().clear_bit());
    
    // 实际业务逻辑
    blink_led();
}

fn main() {
    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();

    // 初始化时钟、GPIO等...
    configure_interrupts(&dp.NVIC);
}