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闪烁的同时通过串口发送数据。
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());
}
性能优化技巧
- 对于高并发场景,优先使用rp-pac提供的并发数据结构
- 频繁分配/释放内存时考虑使用内存池
- 大量键值对操作时使用高性能哈希表
- 利用原子操作扩展避免额外的边界检查
注意事项
- 当前版本为0.x,API可能有不兼容变更
- 某些功能需要特定的CPU特性支持
- 在no_std环境下部分功能不可用
rp-pac库仍在积极开发中,建议定期检查更新以获取性能改进和新功能。