Rust嵌入式开发必备:panic-rtt-target插件库的使用,实现高效RTT(实时传输)目标设备错误处理

panic-rtt-target

crates.io documentation

通过RTT记录panic消息。这是rtt-target的配套库。

文档

RTT必须通过使用其中一个rtt_init宏进行初始化。否则在编译时会出现链接错误。

panic消息总是记录到打印通道。当panic发生时,通道模式会自动设置为BlockIfFull,以确保完整的消息总能被记录。如果代码在RTT初始化之前就panic了(这种情况不太可能发生),或者打印通道不存在,则不会记录任何内容。

panic处理器运行在一个不返回的critical_section中,其实现应由用户提供。

使用方法

Cargo.toml:

[dependencies]
rtt-target = "x.y.z"
panic-rtt-target = "x.y.z"

main.rs:

#![no_std]

use panic_rtt_target as _;
use rtt_target::rtt_init_default;

fn main() -> ! {
    // 你可以使用`rtt_init_print`或者在初始化后调用`set_print_channel`
    rtt_init_default!();

    panic!("Something has gone terribly wrong");
}

Defmt支持

你可以启用defmt特性,这样panic消息会打印到defmt通道。如果你这样做并且同时配置了打印通道和defmt通道,panic消息会同时打印到两个通道。defmt特性不会自动启用rtt-target/defmt。这允许你在需要时使用不同的defmt后端。

完整示例代码

#![no_std]
#![no_main]

use panic_rtt_target as _; // 启用panic处理并通过RTT输出
use rtt_target::{rtt_init_print, rprintln};

#[cortex_m_rt::entry]
fn main() -> ! {
    // 初始化RTT打印通道
    rtt_init_print!();
    
    // 正常日志输出
    rprintln!("System started");
    
    // 模拟panic情况
    panic!("This is a simulated panic message");
    
    // 注意:panic!是一个发散函数,不会返回
    #[allow(unreachable_code)]
    loop {}
}

这个示例展示了:

  1. 如何初始化RTT打印系统
  2. 正常日志输出使用rprintln!宏
  3. 模拟panic情况的处理
  4. panic消息将通过RTT通道输出

要使用这个示例,你需要在Cargo.toml中添加以下依赖:

[dependencies]
cortex-m-rt = "0.7.3"
panic-rtt-target = "0.2.0"
rtt-target = "0.3.1"

1 回复

Rust嵌入式开发必备:panic-rtt-target插件库的使用

完整示例代码

以下是基于内容中提供的示例代码扩展的完整demo,展示了在实际嵌入式项目中使用panic-rtt-target的完整流程:

#![no_std]  // 不使用标准库
#![no_main] // 不使用标准main入口

// 引入必要的库
use panic_rtt_target as _; // panic处理器
use cortex_m_rt::entry;    // Cortex-M运行时入口
use rtt_target::{rtt_init_print, rprintln}; // RTT打印功能

// 应用主入口
#[entry]
fn main() -> ! {
    // 初始化RTT打印系统
    rtt_init_print!(
        NoBlockSkip, // 非阻塞模式,缓冲区满时跳过新消息
        128,         // 上行缓冲区大小(设备到主机)
        64           // 下行缓冲区大小(主机到设备)
    );
    
    rprintln!("系统初始化完成...");
    
    // 模拟传感器初始化
    match init_sensors() {
        Ok(_) => rprintln!("传感器初始化成功"),
        Err(e) => panic!("传感器初始化失败: {:?}", e),
    };
    
    // 主应用循环
    loop {
        match read_sensor_data() {
            Ok(data) => {
                rprintln!("温度: {}.{}°C", data.temp / 10, data.temp % 10);
                rprintln!("湿度: {}%", data.humidity);
            }
            Err(e) => {
                // 使用自定义错误处理
                handle_sensor_error(e);
            }
        }
        
        // 模拟延迟
        cortex_m::asm::delay(8_000_000); // ~1秒延迟(假设8MHz时钟)
    }
}

// 传感器数据结构
#[derive(Debug)]
struct SensorData {
    temp: u16,    // 温度(0.1°C精度)
    humidity: u8, // 湿度百分比
    light: u16,   // 光照强度
}

// 自定义错误类型
#[derive(Debug)]
enum SensorError {
    I2CFault,
    CRCError,
    Timeout,
    NotCalibrated,
}

// 初始化传感器
fn init_sensors() -> Result<(), SensorError> {
    // 模拟初始化过程
    if some_hw_check() {
        Ok(())
    } else {
        Err(SensorError::I2CFault)
    }
}

// 读取传感器数据
fn read_sensor_data() -> Result<SensorData, SensorError> {
    // 模拟读取过程
    if some_condition() {
        Ok(SensorData {
            temp: 235,    // 23.5°C
            humidity: 45, // 45%
            light: 1023,  // 最大光照
        })
    } else {
        Err(SensorError::CRCError)
    }
}

// 自定义错误处理函数
fn handle_sensor_error(e: SensorError) -> ! {
    // 根据不同错误类型采取不同措施
    match e {
        SensorError::Timeout => {
            rprintln!("警告: 传感器超时,尝试复位...");
            // 尝试恢复逻辑...
            panic!("传感器无法恢复: 超时");
        }
        _ => panic!("传感器错误: {:?}", e),
    }
}

// 模拟硬件检查
fn some_hw_check() -> bool {
    false // 模拟硬件故障
}

// 模拟读取条件
fn some_condition() -> bool {
    true // 修改为false可触发错误
}

代码说明

  1. 初始化配置

    • 使用rtt_init_print!宏初始化RTT系统,配置了128字节的上行缓冲区和64字节的下行缓冲区
    • 设置了非阻塞模式(NoBlockSkip),当缓冲区满时跳过新消息而不是阻塞
  2. 错误处理

    • 展示了两种错误处理方式:直接panic和使用自定义处理函数
    • 自定义handle_sensor_error函数可以根据错误类型采取不同措施
  3. 传感器模拟

    • 定义了SensorData结构体来组织传感器数据
    • 使用SensorError枚举定义各种可能的传感器错误
  4. 实际应用

    • 包含完整的初始化、主循环和错误处理流程
    • 展示了如何在真实应用场景中使用RTT输出调试信息

使用方法

  1. 将上述代码保存为main.rs
  2. Cargo.toml中添加依赖:
[dependencies]
cortex-m-rt = "0.7"
panic-rtt-target = "0.3"
rtt-target = "0.3"
  1. 使用cargo build --release编译
  2. 通过J-Link调试器和RTT Viewer工具查看输出

输出示例

当应用运行时,你将在RTT Viewer中看到类似输出:

系统初始化完成...
传感器初始化失败: I2CFault

当修改some_condition()返回false时,会触发:

温度: 23.5°C
湿度: 45%
传感器错误: CRCError
回到顶部