Rust实时中断和任务调度库rtic-core的使用,RTIC框架核心组件助力嵌入式系统开发

Rust实时中断和任务调度库rtic-core的使用,RTIC框架核心组件助力嵌入式系统开发

rtic-core是Real-Time Interrupt-driven Concurrency(实时中断驱动并发)的核心抽象库。

许可证

采用以下任一许可证:

  • Apache License, Version 2.0
  • MIT license

贡献

除非您明确声明,否则任何有意提交的贡献都将按照上述双重许可证授权,无需任何附加条款或条件。

示例代码

以下是一个使用rtic-core的完整示例demo:

// 导入必要的库
use rtic_core::app;
use cortex_m::peripheral::{syst::SystClkSource, SYST};
use cortex_m_rt::entry;

// 定义RTIC应用程序
#[app(device = stm32f4xx_hal::stm32)]
mod app {
    use super::*;
    use stm32f4xx_hal::{
        gpio::gpioa::PA5,
        gpio::{Output, PushPull},
        prelude::*,
    };
    
    // 共享资源
    #[shared]
    struct Shared {
        led: PA5<Output<PushPull>>,
    }
    
    // 本地资源
    #[local]
    struct Local {}
    
    // 初始化函数
    #[init]
    fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
        // 获取设备外围设备访问权限
        let dp = cx.device;
        
        // 配置GPIO引脚
        let gpioa = dp.GPIOA.split();
        let led = gpioa.pa5.into_push_pull_output();
        
        // 配置系统定时器
        let mut syst = cx.core.SYST;
        syst.set_clock_source(SystClkSource::Core);
        syst.set_reload(8_000_000); // 1秒间隔
        syst.enable_counter();
        syst.enable_interrupt();
        
        (Shared { led }, Local {}, init::Monotonics())
    }
    
    // 系统定时器中断处理
    #[task(binds = SysTick, shared = [led])]
    fn systick(cx: systick::Context) {
        // 切换LED状态
        cx.shared.led.lock(|led| led.toggle().unwrap());
    }
}

// 主入口点
#[entry]
fn main() -> ! {
    // 启动RTIC应用程序
    app::init();
    
    loop {
        cortex_m::asm::wfi();
    }
}

安装

在项目目录中运行以下Cargo命令:

cargo add rtic-core

或者在Cargo.toml中添加:

rtic-core = "1.0.0"

分类

  • 并发(Concurrency)
  • 嵌入式开发(Embedded development)
  • 无标准库(No standard library)

1 回复

Rust实时中断和任务调度库rtic-core的使用

简介

rtic-core是Rust实时中断和并发(RTIC)框架的核心组件,专为嵌入式系统开发设计。它提供了一种简洁高效的方式来管理硬件中断和任务调度,特别适合实时性要求高的嵌入式应用。

RTIC框架基于优先级的中断和任务调度模型,允许开发者以声明式的方式定义系统资源,自动处理资源共享和并发访问问题。

主要特性

  • 基于优先级的任务调度
  • 高效的资源管理
  • 零成本抽象
  • 最小运行时开销
  • 与Cortex-M等嵌入式架构紧密集成

完整示例代码

下面是一个完整的RTIC应用示例,结合了中断处理、资源共享和定时任务:

#![no_std]
#![no_main]

use cortex_m_rt::entry;
use rtic::app;
use stm32f4xx_hal::{
    gpio::{gpioa::PA5, Edge, Input, Output, PushPull},
    prelude::*,
    stm32,
    timer::Timer,
};

#[app(device = stm32f4xx_hal::stm32)]
mod app {
    use super::*;
    use core::fmt::Write;
    use cortex_m::interrupt::Mutex;
    use core::cell::RefCell;
    use stm32f4xx_hal::serial::{Serial, Config};
    
    // 共享资源
    #[shared]
    struct Shared {
        counter: u32,
        serial: Mutex<RefCell<Option<Serial<stm32::USART2>>>>,
    }
    
    // 局部资源
    #[local]
    struct Local {
        led: PA5<Output<PushPull>>,
        button: PA0<Input>,
        timer: Timer<stm32::TIM2>,
    }
    
    #[init]
    fn init(cx: init::Context) -> (Shared, Local) {
        // 获取设备外设
        let dp = cx.device;
        
        // 配置时钟
        let rcc = dp.RCC.constrain();
        let clocks = rcc.cfgr.sysclk(48.mhz()).freeze();
        
        // 初始化GPIO
        let gpioa = dp.GPIOA.split();
        let led = gpioa.pa5.into_push_pull_output();
        let button = gpioa.pa0.into_pull_up_input();
        
        // 配置串口
        let tx = gpioa.pa2.into_alternate_af7();
        let rx = gpioa.pa3.into_alternate_af7();
        let serial = Serial::usart2(
            dp.USART2,
            (tx, rx),
            Config::default().baudrate(115200.bps()),
            clocks,
        ).unwrap();
        
        // 配置定时器
        let mut timer = Timer::tim2(dp.TIM2, 1.hz(), clocks);
        timer.listen(stm32f4xx_hal::timer::Event::TimeOut);
        
        // 配置外部中断
        let mut syscfg = dp.SYSCFG.constrain();
        let mut exti = dp.EXTI;
        button.make_interrupt_source(&mut syscfg);
        button.trigger_on_edge(&mut exti, Edge::Falling);
        button.enable_interrupt(&mut exti);
        
        // 初始调度
        periodic_task::schedule_after(500.millis()).unwrap();
        
        (
            Shared {
                counter: 0,
                serial: Mutex::new(RefCell::new(Some(serial))),
            },
            Local {
                led,
                button,
                timer,
            },
        )
    }
    
    #[idle]
    fn idle(_cx: idle::Context) -> ! {
        loop {
            // 进入低功耗模式
            cortex_m::asm::wfi();
        }
    }
    
    // 按钮中断处理
    #[task(binds = EXTI0, priority = 1, shared = [counter, serial])]
    fn button_press(cx: button_press::Context) {
        *cx.shared.counter += 1;
        
        cx.shared.serial.lock(|serial| {
            if let Some(serial) = &mut *serial.borrow_mut() {
                let _ = writeln!(serial, "Button pressed! Count: {}", *cx.shared.counter);
            }
        });
    }
    
    // 定时器中断处理
    #[task(binds = TIM2, priority = 2, local = [led, timer])]
    fn timer_tick(cx: timer_tick::Context) {
        // 翻转LED状态
        cx.local.led.toggle();
        
        // 清除中断标志
        cx.local.timer.clear_interrupt(stm32f4xx_hal::timer::Event::TimeOut);
    }
    
    // 周期性软件任务
    #[task(priority = 1, shared = [serial])]
    fn periodic_task(cx: periodic_task::Context) {
        cx.shared.serial.lock(|serial| {
            if let Some(serial) = &mut *serial.borrow_mut() {
                let _ = writeln!(serial, "Periodic task executed");
            }
        });
        
        // 每500毫秒重新调度自己
        periodic_task::schedule_after(500.millis()).unwrap();
    }
}

代码说明

  1. 初始化(init): 配置硬件外设,包括GPIO、串口、定时器和外部中断。

  2. 空闲任务(idle): 系统空闲时进入低功耗模式。

  3. 按钮中断(button_press):

    • 优先级1的中断处理函数
    • 每次按钮按下时增加计数器
    • 通过串口输出当前计数
  4. 定时器中断(timer_tick):

    • 优先级2的中断处理函数
    • 定期翻转LED状态
    • 清除定时器中断标志
  5. 周期性任务(periodic_task):

    • 优先级1的软件任务
    • 每500毫秒通过串口输出信息
    • 自动重新调度自身

项目配置

Cargo.toml需要包含以下依赖:

[dependencies]
rtic = "1.0"
cortex-m = "0.7"
cortex-m-rt = "0.7"
stm32f4xx-hal = { version = "0.13", features = ["rt"] }
panic-halt = "0.2"

注意事项

  1. 确保使用正确的目标设备配置,示例中使用的是STM32F4系列

  2. 根据实际硬件调整GPIO引脚配置

  3. 优先级设置要合理,避免优先级反转问题

  4. 共享资源的访问要通过RTIC提供的锁机制

  5. 定时器周期需要根据实际需求调整

回到顶部