You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Rust cortex-m-rt框架中,Systick异常处理相关实现疑问:调用特权线程模式main()及异常中#[entry]的使用

在Rust cortex-m-rt框架中,Systick异常处理相关实现疑问:调用特权线程模式main()及异常中#[entry]的使用

首先,先帮你梳理下当前的问题,再一步步给出解决方案:

一、先点评下你的SysTick初始化代码

你的systick_init逻辑大体是对的,但有个小细节需要注意:
你用固定值0x3e8(也就是1000)作为syst_calib来计算重载值,这个思路没问题(本质是把毫秒转成时钟周期数),但要确保DefaultCPUClock是你当前STM32H723核心的实际运行频率(比如HCLK如果是400MHz,那这个值要设为400_000_000)。另外,SysTick的COUNTFLAG需要在中断中手动读取来清除,否则可能会重复触发中断,这个后面会提到。

二、如何实现SysTick的#[exception]处理函数

在cortex-m-rt框架中,你只需要用#[exception]宏标记名为SysTick的函数,就能作为SysTick中断的处理入口。不过要注意:异常处理函数本身是在特权级的Handler模式下运行的,如果你的需求是切换到特权级线程模式执行main(),直接在异常里调用会让main()跑在Handler模式下,这可能不是你想要的——更合理的方式是用"中断触发标志+主循环轮询"的方式,让main()在特权线程模式下执行。

完整代码示例

下面是一个可运行的参考实现:

use cortex_m::{asm, peripheral::SYST};
use cortex_m_rt::{entry, exception};
use core::sync::atomic::{AtomicBool, Ordering};
use stm32h7xx_hal::pac; // 假设你用stm32h7xx-hal库,也可以直接用pac

// 定义核心时钟频率,根据你的实际配置修改
const DEFAULT_CPU_CLOCK: u32 = 400_000_000; // 400MHz,STM32H723的典型主频

// 原子标志:用于通知主循环SysTick中断已触发
static TICK_TRIGGERED: AtomicBool = AtomicBool::new(false);

#[entry]
fn entry() -> ! {
    // 获取外设控制权
    let dp = pac::Peripherals::take().unwrap();
    let mut syst = dp.SYST;

    // 初始化SysTick,设置50ms中断
    systick_init(&mut syst, 50);

    // 这里可以添加其他硬件初始化(比如GPIO、UART等)

    // 主循环:在特权线程模式下等待中断触发,执行main任务
    loop {
        // 进入低功耗模式,等待中断唤醒
        asm::wfi();

        // 检查中断标志,如果触发则执行main
        if TICK_TRIGGERED.swap(false, Ordering::Acquire) {
            main();
        }
    }
}

#[exception]
fn SysTick() {
    // 清除SysTick中断标志(必须读取COUNTFLAG来清除)
    let _ = SYST::get_countflag();

    // 设置触发标志,通知主循环执行任务
    TICK_TRIGGERED.store(true, Ordering::Release);
}

// 你的main函数:运行在特权线程模式下
fn main() {
    // 这里写你需要周期性执行的代码,比如LED翻转、数据处理等
    // 示例:翻转LED(假设你已经初始化了LED引脚)
    // led.toggle();
}

// 你的SysTick初始化函数
fn systick_init(syst: &mut pac::SYST, time_ms: u32) {
    // 计算重载值:(时钟频率 * 毫秒数 / 1000) - 1
    let reload_val = (DEFAULT_CPU_CLOCK * time_ms / 1000) - 1;

    // 配置SysTick
    syst.set_reload(reload_val);
    syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core);
    syst.enable_interrupt();
    syst.enable_counter();
}

三、关键注意事项

  1. 特权线程模式的保证:#[entry]标记的入口函数默认就是在特权级线程模式下运行的,所以主循环里调用的main()自然也是在这个模式下执行,完全符合你的需求。
  2. 原子变量的使用:用AtomicBool而不是普通的静态可变变量,是为了避免中断和主循环同时访问变量导致的竞态条件,保证线程安全。
  3. 中断标志的清除:SysTick的中断标志必须通过读取COUNTFLAG来清除,否则会导致中断重复触发,这个步骤一定不能忘。
  4. 异常处理函数的代码长度:尽量不要在SysTick异常处理函数里写复杂逻辑,保持它的执行时间极短,避免影响其他中断的响应——所以用标志通知主循环执行任务是更优的设计。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:24:37