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);
    }
}

外设访问说明

  1. 通过Peripherals::take()获取外设实例
  2. 使用IO_BANK0控制GPIO配置
  3. 使用SIO控制GPIO输出状态
  4. 每个寄存器都有类型安全的访问方法

完整示例代码

下面是一个更完整的示例,展示如何使用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) }),
        _ => {}
    }
}

注意事项

  1. rp2040-pac提供了对硬件的底层访问,使用时需确保理解RP2040的硬件特性
  2. 寄存器访问通常使用writemodify方法,它们提供了类型安全的接口
  3. 某些寄存器访问需要使用unsafe块,因为编译器无法验证硬件操作的合理性
  4. 建议结合rp-hal等更高级的硬件抽象层使用,除非你需要直接寄存器访问
回到顶部