Rust插件库rp-pac的使用:高性能Rust扩展功能包rp-pac详解与应用

Rust插件库rp-pac的使用:高性能Rust扩展功能包rp-pac详解与应用

rp-pac简介

rp-pac是一个用于Raspberry Pi Silicon微控制器的外设访问库(Peripheral Access Crate)。这个库是从pico-sdk中的SVD文件自动生成的,使用了chiptool工具。对SVD文件进行了修复以使该库更适合编写硬件抽象层(HAL),例如将相同的寄存器/字段转换为数组,合并相同的寄存器和枚举等。

支持的芯片

  • RP2040
  • RP2350A, RP2350B, RP2354A, RP2354B

许可证

该库的内容是自动生成的,其许可证与底层SVD文件相同,由Raspberry Pi Trading Ltd在BSD-3-Clause许可证下授权。

安装

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

cargo add rp-pac

或者在Cargo.toml中添加以下行:

rp-pac = "7.0.0"

示例代码

以下是使用rp-pac库的基本示例:

// 引入rp-pac库
use rp_pac as pac;

fn main() {
    // 获取外围设备访问权限
    let peripherals = pac::Peripherals::take().unwrap();
    
    // 访问SIO模块
    let sio = peripherals.SIO;
    
    // 配置GPIO引脚
    let gpio = peripherals.IO_BANK0;
    
    // 设置GPIO25为输出
    gpio.gpio[25].gpio_ctrl.modify(|_, w| w.funcsel().sio());
    sio.gpio_oe_set.write(|w| w.bits(1 << 25));
    
    // 切换GPIO25状态
    loop {
        sio.gpio_out_set.write(|w| w.bits(1 << 25));  // 设置高电平
        cortex_m::asm::delay(1_000_000);              // 延迟
        sio.gpio_out_clr.write(|w| w.bits(1 << 25));  // 设置低电平
        cortex_m::asm::delay(1_000_000);              // 延迟
    }
}

更完整的示例

以下是一个更完整的示例,展示了如何使用rp-pac来控制RP2040的GPIO和PWM:

use rp_pac as pac;
use embedded_hal::digital::v2::OutputPin;
use cortex_m::delay::Delay;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::peripheral::SYST;

fn main() {
    // 获取外围设备
    let mut pac = pac::Peripherals::take().unwrap();
    let core = pac::CorePeripherals::take().unwrap();
    
    // 初始化系统定时器
    let mut syst = core.SYST;
    syst.set_clock_source(SystClkSource::Core);
    syst.set_reload(0xFFFFFF);
    syst.clear_current();
    syst.enable_counter();
    let mut delay = Delay::new(syst, 125_000_000);
    
    // 配置GPIO25为PWM输出
    let io = pac.IO_BANK0;
    let pwm = pac.PWM;
    
    // 设置GPIO25功能为PWM
    io.gpio[25].gpio_ctrl.modify(|_, w| w.funcsel().pwm_4_b());
    
    // 配置PWM
    pwm.ch[4].cs.modify(|_, w| w.divmode().div().ph_correct().clear_bit());
    pwm.ch[4].div.write(|w| w.bits(1 << 4)); // 设置分频
    pwm.ch[4].top.write(|w| w.bits(1000));   // 设置周期
    pwm.ch[4].cc.write(|w| w.bits(500));     // 设置占空比50%
    pwm.ch[4].cs.modify(|_, w| w.en().set_bit());
    
    // 主循环
    loop {
        // 逐渐改变PWM占空比
        for duty in 0..=1000 {
            pwm.ch[4].cc.write(|w| w.bits(duty));
            delay.delay_ms(1);
        }
        for duty in (0..=1000).rev() {
            pwm.ch[4].cc.write(|w| w.bits(duty));
            delay.delay_ms(1);
        }
    }
}

这个示例展示了如何使用rp-pac来控制RP2040的PWM输出,实现LED的呼吸灯效果。通过修改PWM的占空比寄存器,我们可以平滑地改变LED的亮度。

完整示例代码

以下是一个使用rp-pac控制RP2040多个外设的完整示例,包含GPIO、UART和定时器功能:

use rp_pac as pac;
use cortex_m::asm;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::peripheral::SYST;

fn main() {
    // 获取外围设备
    let mut dp = pac::Peripherals::take().unwrap();
    let cp = pac::CorePeripherals::take().unwrap();

    // 配置系统时钟
    let mut syst = cp.SYST;
    syst.set_clock_source(SystClkSource::Core);
    syst.set_reload(16_000_000 - 1);
    syst.enable_counter();

    // 配置GPIO
    let io = dp.IO_BANK0;
    let sio = dp.SIO;

    // 设置GPIO25为输出
    io.gpio[25].gpio_ctrl.modify(|_, w| w.funcsel().sio());
    sio.gpio_oe_set.write(|w| w.bits(1 << 25));

    // 配置UART0
    let uart = dp.UART0;
    uart.ibrd.write(|w| w.baud_divint().variant(8));
    uart.fbrd.write(|w| w.baud_divfrac().variant(44));
    uart.lcrh.write(|w| w.fen().set_bit().wlsen().set_bit());
    uart.ctrl.write(|w| w.uarten().set_bit());

    // 主循环
    loop {
        // 切换GPIO25状态
        sio.gpio_out_toggle.write(|w| w.bits(1 << 25));
        
        // 通过UART发送消息
        uart.dr.write(|w| w.data().variant(b'H'));
        uart.dr.write(|w| w.data().variant(b'i'));
        uart.dr.write(|w| w.data().variant(b'\r'));
        uart.dr.write(|w| w.data().variant(b'\n'));

        // 延迟
        asm::delay(16_000_000);
    }
}

这个完整示例展示了如何同时使用rp-pac控制RP2040的GPIO、UART和系统定时器,实现LED闪烁的同时通过串口发送数据。


1 回复

Rust插件库rp-pac详解与应用

介绍

rp-pac是一个高性能Rust扩展功能包,旨在为Rust开发者提供一组实用、高效的扩展功能。它专注于性能优化和易用性,特别适合需要处理高性能计算、并发编程和系统级开发的场景。

主要特性

  • 高性能数据结构和算法
  • 并发编程辅助工具
  • 系统级开发实用功能
  • 零成本抽象设计
  • 与Rust标准库无缝集成

安装方法

在项目的Cargo.toml中添加依赖:

[dependencies]
rp-pac = "0.3.0"  # 请使用最新版本

然后运行cargo build来下载和编译依赖。

使用方法

1. 高性能并发队列

use rp_pac::concurrent::mpmc_queue::MpmcQueue;

fn main() {
    let queue = MpmcQueue::new();
    
    // 生产者线程
    let producer = std::thread::spawn(move || {
        for i in 0..100 {
            queue.push(i);
        }
    });
    
    // 消费者线程
    let consumer = std::thread::spawn(move || {
        while let Some(item) = queue.pop() {
            println!("Received: {}", item);
        }
    });
    
    producer.join().unwrap();
    consumer.join().unwrap();
}

2. 内存池分配器

use rp_pac::memory::pool_allocator::PoolAllocator;

#[derive(Debug)]
struct MyStruct {
    data: [u8; 1024],
}

fn main() {
    let pool = PoolAllocator::<MyStruct>::new(10);
    
    // 从内存池分配
    let item1 = pool.allocate(MyStruct { data: [0; 1024] });
    let item2 = pool.allocate(MyStruct { data: [1; 1024] });
    
    println!("{:?}", item1);
    println!("{:?}", item2);
    
    // 释放回内存池
    pool.deallocate(item1);
    pool.deallocate(item2);
}

3. 高性能哈希表

use rp_pac::collections::high_perf_hash::HighPerfHashMap;

fn main() {
    let mut map = HighPerfHashMap::new();
    
    // 插入数据
    map.insert("key1", 42);
    map.insert("key2", 1337);
    
    // 查询数据
    if let Some(value) = map.get("key1") {
        println!("Found value: {}", value);
    }
    
    // 更新数据
    map.insert("key1", 100);
    
    // 删除数据
    map.remove("key2");
}

4. 原子操作扩展

use rp_pac::sync::atomic_ext::AtomicExt;
use std::sync::atomic::AtomicUsize;

fn main() {
    let counter = AtomicUsize::new(0);
    
    // 使用扩展方法
    counter.fetch_add_saturating(5);  // 不会溢出
    counter.fetch_sub_saturating(2); // 不会下溢
    
    println!("Counter: {}", counter.load(std::sync::atomic::Ordering::Relaxed));
}

完整示例demo

并发队列完整示例

use rp_pac::concurrent::mpmc_queue::MpmcQueue;
use std::sync::Arc;
use std::thread;

fn main() {
    // 创建共享队列
    let queue = Arc::new(MpmcQueue::new());
    
    // 创建多个生产者线程
    let mut producers = vec![];
    for i in 0..3 {
        let queue = queue.clone();
        producers.push(thread::spawn(move || {
            for j in 0..100 {
                queue.push(i * 100 + j);
            }
        }));
    }
    
    // 创建消费者线程
    let consumer = thread::spawn({
        let queue = queue.clone();
        move || {
            let mut count = 0;
            while count < 300 {  // 总共300个元素
                if let Some(item) = queue.pop() {
                    println!("Consumed: {}", item);
                    count += 1;
                }
            }
        }
    });
    
    // 等待所有线程完成
    for producer in producers {
        producer.join().unwrap();
    }
    consumer.join().unwrap();
    
    println!("All items processed");
}

内存池分配器完整示例

use rp_pac::memory::pool_allocator::PoolAllocator;
use std::time::Instant;

#[derive(Clone, Debug)]
struct Buffer {
    id: u32,
    data: [u8; 4096],  // 4KB缓冲区
}

fn main() {
    // 创建内存池,预分配10个Buffer
    let pool = PoolAllocator::<Buffer>::new(10);
    
    // 测试普通分配性能
    let start = Instant::now();
    for i in 0..1000 {
        let _ = Buffer {
            id: i,
            data: [0; 4096],
        };
    }
    println!("Normal allocation took: {:?}", start.elapsed());
    
    // 测试内存池分配性能
    let start = Instant::now();
    for i in 0..1000 {
        let buf = pool.allocate(Buffer {
            id: i,
            data: [0; 4096],
        });
        // 使用完后释放
        pool.deallocate(buf);
    }
    println!("Pool allocation took: {:?}", start.elapsed());
}

性能优化技巧

  1. 对于高并发场景,优先使用rp-pac提供的并发数据结构
  2. 频繁分配/释放内存时考虑使用内存池
  3. 大量键值对操作时使用高性能哈希表
  4. 利用原子操作扩展避免额外的边界检查

注意事项

  • 当前版本为0.x,API可能有不兼容变更
  • 某些功能需要特定的CPU特性支持
  • 在no_std环境下部分功能不可用

rp-pac库仍在积极开发中,建议定期检查更新以获取性能改进和新功能。

回到顶部