Rust嵌入式开发库rp2040-pac的使用,rp2040-pac为树莓派RP2040微控制器提供外设访问控制功能
Rust嵌入式开发库rp2040-pac的使用
rp2040-pac是为树莓派RP2040微控制器提供的外设访问控制(PAC)库,它允许开发者通过Rust语言直接访问和控制RP2040芯片的各种硬件外设。
基本信息
rp2040-pac是通过svd2rust工具自动生成的,基于pico-sdk v1.5.1中的SVD文件构建。它使用BSD-3-Clause许可证。
安装方法
在项目中使用rp2040-pac,需要在Cargo.toml中添加以下依赖:
rp2040-pac = "0.6.0"
或者运行以下Cargo命令:
cargo add rp2040-pac
完整示例代码
下面是一个使用rp2040-pac控制GPIO外设的完整示例:
// 导入必要的库
use rp2040_pac as pac;
use panic_halt as _;
// 定义主函数
#[entry]
fn main() -> ! {
// 获取外设访问实例
let mut pac = pac::Peripherals::take().unwrap();
// 初始化SIO (Single-cycle IO) 外设
let sio = pac.SIO;
// 配置GPIO25为输出
let gpio = pac.IO_BANK0;
gpio.gpio25_ctrl.write(|w| w.funcsel().sio());
sio.gpio_oe_set.write(|w| unsafe { w.bits(1 << 25) });
// 主循环
loop {
// 设置GPIO25高电平
sio.gpio_out_set.write(|w| unsafe { w.bits(1 << 25) });
cortex_m::asm::delay(1_000_000);
// 设置GPIO25低电平
sio.gpio_out_clr.write(|w| unsafe { w.bits(1 << 25) });
cortex_m::asm::delay(1_000_000);
}
}
外设访问说明
- 通过
Peripherals::take()
获取外设实例 - 使用
IO_BANK0
控制GPIO配置 - 使用
SIO
控制GPIO输出状态 - 每个寄存器都有类型安全的访问方法
完整示例代码
下面是一个更完整的示例,展示如何使用rp2040-pac初始化时钟和UART外设:
// 导入必要的库
use rp2040_pac as pac;
use panic_halt as _;
use cortex_m_rt::entry;
// 主函数
#[entry]
fn main() -> ! {
// 获取外设实例
let peripherals = pac::Peripherals::take().unwrap();
// 初始化时钟系统
let resets = &peripherals.RESETS;
resets.reset.modify(|_, w| w.io_bank0().clear_bit());
// 配置UART0
let uart0 = peripherals.UART0;
uart0.uartlcr_h.write(|w| {
w.fen().set_bit() // 启用FIFO
.wlben().clear_bit() // 8位数据
.stp2().clear_bit() // 1个停止位
.pen().clear_bit() // 无奇偶校验
});
// 设置波特率
uart0.uartibrd.write(|w| unsafe { w.bits(8) }); // 整数部分
uart0.uartfbrd.write(|w| unsafe { w.bits(44) }); // 小数部分
// 启用UART
uart0.uartcr.write(|w| {
w.uarten().set_bit() // 启用UART
.txe().set_bit() // 启用发送
.rxe().set_bit() // 启用接收
});
// 主循环
loop {
// 发送数据
uart0.uartdr.write(|w| unsafe { w.bits(0x41) }); // 发送字符'A'
cortex_m::asm::delay(1_000_000);
}
}
这个库为RP2040微控制器提供了完整的寄存器级别访问能力,适合需要精细控制硬件的嵌入式开发场景。
1 回复
Rust嵌入式开发库rp2040-pac的使用指南
概述
rp2040-pac是Rust语言中用于树莓派RP2040微控制器的外设访问控制库(Peripheral Access Crate)。它为RP2040的所有外设提供了类型安全的Rust接口,允许开发者直接与硬件寄存器交互。
主要功能
- 提供RP2040所有外设的寄存器定义
- 自动生成的安全访问方法
- 符合Rust所有权模型的硬件访问控制
- 支持中断处理
- 与cortex-m-rt等嵌入式Rust库良好集成
使用方法
添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
rp2040-pac = "0.5.0"
cortex-m = "0.7.6"
cortex-m-rt = "0.7.3"
基本使用示例
use rp2040_pac as pac;
fn main() -> ! {
// 获取设备外设的单一实例
let mut peripherals = pac::Peripherals::take().unwrap();
// 访问SIO外设
let sio = &peripherals.SIO;
// 访问GPIO外设
let gpio = &peripherals.IO_BANK0;
// 配置GPIO25为输出
gpio.gpio[25].gpio_ctrl.write(|w| w.funcsel().sio());
sio.gpio_oe_set.write(|w| unsafe { w.bits(1 << 25) });
loop {
// 切换GPIO25状态
sio.gpio_togl.write(|w| unsafe { w.bits(1 << 25) });
cortex_m::asm::delay(1_000_000);
}
}
中断处理示例
use rp2040_pac as pac;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
let mut peripherals = pac::Peripherals::take().unwrap();
// 启用TIMER中断
unsafe {
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::TIMER_IRQ_0);
}
// 配置TIMER
let timer = &peripherals.TIMER;
timer.intr.write(|w| w.alarm0().set_bit());
timer.alarm[0].write(|w| unsafe { w.bits(timer.timer.read().bits() + 1_000_000) });
loop {
cortex_m::asm::wfi();
}
}
#[cortex_m_rt::interrupt]
fn TIMER_IRQ_0() {
let peripherals = unsafe { pac::Peripherals::steal() };
let timer = &peripherals.TIMER;
// 清除中断标志
timer.intr.write(|w| w.alarm0().set_bit());
// 设置下一个定时器中断
timer.alarm[0].write(|w| unsafe { w.bits(timer.timer.read().bits() + 1_000_000) });
// 这里可以执行定时任务
}
PWM配置示例
use rp2040_pac as pac;
fn configure_pwm(peripherals: &mut pac::Peripherals, pin: u8) {
// 选择PWM功能
peripherals.IO_BANK0.gpio[pin as usize].gpio_ctrl.write(|w| w.funcsel().pwm());
// 获取PWM片(每个PWM有8个通道,分成2个片)
let pwm_slice = if pin < 8 { &peripherals.PWM.pwm[0] } else { &peripherals.PWM.pwm[1] };
let channel = pin % 8;
// 配置PWM
pwm_slice.csr.write(|w|
w.divmode().div_int(1)
.ph_correct().clear_bit()
);
pwm_slice.div.write(|w| unsafe { w.bits(1 << 4) }); // 分频器
pwm_slice.top.write(|w| unsafe { w.bits(10000) }); // 周期
// 设置占空比(50%)
match channel {
0 => pwm_slice.cc.write(|w| unsafe { w.a().bits(5000) }),
1 => pwm_slice.cc.write(|w| unsafe { w.b().bits(5000) }),
_ => {}
}
// 启用PWM
pwm_slice.csr.modify(|_, w| w.en().set_bit());
}
完整示例代码
以下是一个完整的RP2040 LED闪烁和PWM控制示例,结合了上述基本操作和PWM功能:
#![no_std]
#![no_main]
use panic_halt as _;
use rp2040_pac as pac;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
let mut peripherals = pac::Peripherals::take().unwrap();
// 初始化SIO和IO_BANK0
let sio = &peripherals.SIO;
let gpio = &peripherals.IO_BANK0;
// 配置GPIO25为输出(LED)
gpio.gpio[25].gpio_ctrl.write(|w| w.funcsel().sio());
sio.gpio_oe_set.write(|w| unsafe { w.bits(1 << 25) });
// 配置GPIO0为PWM输出
configure_pwm(&mut peripherals, 0);
let mut counter = 0;
loop {
// 切换GPIO25状态
sio.gpio_togl.write(|w| unsafe { w.bits(1 << 25) });
// 更新PWM占空比
update_pwm_duty(&mut peripherals, 0, counter % 10000);
counter += 100;
cortex_m::asm::delay(50_000);
}
}
fn configure_pwm(peripherals: &mut pac::Peripherals, pin: u8) {
// 选择PWM功能
peripherals.IO_BANK0.gpio[pin as usize].gpio_ctrl.write(|w| w.funcsel().pwm());
// 获取PWM片和通道
let pwm_slice = if pin < 8 { &peripherals.PWM.pwm[0] } else { &peripherals.PWM.pwm[1] };
let channel = pin % 8;
// 配置PWM
pwm_slice.csr.write(|w|
w.divmode().div_int(1)
.ph_correct().clear_bit()
);
pwm_slice.div.write(|w| unsafe { w.bits(1 << 4) }); // 分频器
pwm_slice.top.write(|w| unsafe { w.bits(10000) }); // 周期
// 初始占空比(0%)
match channel {
0 => pwm_slice.cc.write(|w| unsafe { w.a().bits(0) }),
1 => pwm_slice.cc.write(|w| unsafe { w.b().bits(0) }),
_ => {}
}
// 启用PWM
pwm_slice.csr.modify(|_, w| w.en().set_bit());
}
fn update_pwm_duty(peripherals: &mut pac::Peripherals, pin: u8, duty: u16) {
let pwm_slice = if pin < 8 { &peripherals.PWM.pwm[0] } else { &peripherals.PWM.pwm[1] };
let channel = pin % 8;
// 更新占空比
match channel {
0 => pwm_slice.cc.write(|w| unsafe { w.a().bits(duty) }),
1 => pwm_slice.cc.write(|w| unsafe { w.b().bits(duty) }),
_ => {}
}
}
注意事项
- rp2040-pac提供了对硬件的底层访问,使用时需确保理解RP2040的硬件特性
- 寄存器访问通常使用
write
和modify
方法,它们提供了类型安全的接口 - 某些寄存器访问需要使用
unsafe
块,因为编译器无法验证硬件操作的合理性 - 建议结合rp-hal等更高级的硬件抽象层使用,除非你需要直接寄存器访问