Rust嵌入式USB设备驱动库embassy-usb-synopsys-otg的使用,支持Synopsys OTG控制器的高性能USB协议栈开发

Rust嵌入式USB设备驱动库embassy-usb-synopsys-otg的使用

简介

embassy-usb-synopsys-otg是一个专为Synopsys USB OTG核心设备设计的Embassy USB驱动库。它实现了embassy-usb-driver的通用功能,适用于所有使用Synopsys OTG IP的芯片。

该库包含驱动程序的"核心"部分,这些是所有使用Synopsys OTG IP的芯片共通的代码,但不包含芯片特定的初始化代码(如时钟设置和GPIO复用)。通常情况下,开发者不会直接使用这个库,而是通过硬件抽象层(HAL)来使用它。

支持的HAL列表

  • embassy-stm32:支持STMicroelectronics STM32系列芯片
  • esp-hal:支持Espressif ESP32系列芯片

如需将此库集成到您设备的HAL中,需要添加设备特定的初始化代码。可以参考上述HAL库的实现方式。

安装方法

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

cargo add embassy-usb-synopsys-otg

或在Cargo.toml中添加:

embassy-usb-synopsys-otg = "0.3.0"

完整示例

以下是基于STM32 HAL的完整示例代码:

use embassy_stm32::{
    peripherals::USB_OTG_FS,
    usb_otg::{Driver, Config},
    time::Hertz,
    Config as StmConfig,
};
use embassy_usb::{
    driver::EndpointError,
    Builder, UsbDevice,
};
use embassy_usb_class::cdc_acm::{CdcAcmClass, State};

// USB配置参数
const USB_CONFIG: Config = Config {
    usb_speed: embassy_stm32::usb_otg::UsbSpeed::FullSpeed,
    pin_dm: None,
    pin_dp: None,
};

#[embassy_executor::task]
async fn usb_task(driver: Driver<'static, USB_OTG_FS>) {
    // 缓冲区分配
    let mut device_descriptor = [0; 256];
    let mut config_descriptor = [0; 256];
    let mut bos_descriptor = [0; 256];
    let mut control_buf = [0; 64];
    
    // CDC ACM类初始化
    let state = State::new();
    
    // USB设备构建
    let mut builder = Builder::new(
        driver,
        &mut device_descriptor,
        &mut config_descriptor,
        &mut bos_descriptor,
        &mut control_buf,
    );
    
    // 添加CDC ACM类
    let mut class = CdcAcmClass::new(&mut builder, state, 64);
    
    // 构建USB设备
    let mut usb = builder.build();
    
    // 运行USB设备
    let mut usb_fut = usb.run();
    
    // 事件处理循环
    loop {
        embassy_futures::select::select(
            usb_fut,
            class.wait_connection(),
        ).await;
    }
}

#[embassy_executor::main]
async fn main(spawner: embassy_executor::Spawner) {
    // 硬件初始化
    let p = embassy_stm32::init(StmConfig::default());
    
    // USB驱动初始化
    let driver = Driver::new(p.USB_OTG_FS, USB_CONFIG);
    
    // 启动USB任务
    spawner.spawn(usb_task(driver)).unwrap();
    
    // 主循环
    loop {
        embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
    }
}

代码说明

  1. 硬件配置部分:

    • 使用embassy_stm32::init初始化STM32硬件
    • 配置USB OTG驱动的工作模式和参数
  2. USB任务部分:

    • 分配必要的缓冲区
    • 初始化CDC ACM类(模拟串口)
    • 构建USB设备描述符
    • 运行USB设备并处理事件
  3. 主程序部分:

    • 初始化硬件和USB驱动
    • 启动独立的USB任务
    • 运行主程序循环

注意事项

  1. 示例基于STM32平台,移植到其他平台需调整初始化代码
  2. 实际项目需根据需求配置USB描述符
  3. 需要完善错误处理机制
  4. 缓冲区大小应根据实际需求调整

许可证信息

本库采用MIT或Apache-2.0双许可证。


1 回复

embassy-usb-synopsys-otg - Rust嵌入式USB设备驱动库

简介

embassy-usb-synopsys-otg 是一个用于嵌入式系统的Rust USB协议栈库,专门支持Synopsys OTG控制器。它是Embassy嵌入式异步运行时生态系统的一部分,提供了高性能的USB设备功能实现。

这个库特别适合需要在嵌入式设备上实现USB功能的开发者,支持多种USB设备类(Device Classes)和自定义功能。

主要特性

  • 支持Synopsys OTG控制器
  • 异步API设计
  • 支持多种USB设备类(HID, CDC, MSC等)
  • 可自定义设备描述符
  • 低内存占用
  • 与Embassy运行时无缝集成

使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
embassy-usb-synopsys-otg = "0.1"
embassy-executor = "0.1"
embassy-time = { version = "0.1", features = ["time-driver"] }

基本示例

以下是一个简单的USB设备初始化示例:

use embassy_executor::Spawner;
use embassy_usb_synopsys_otg::Driver;
use embassy_usb_synopsys-otg::Builder;
use embassy_usb_synopsys-otg::Config;

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // 初始化硬件
    let p = embassy_stm32::init(Default::default());
    
    // 创建USB驱动
    let driver = Driver::new(
        p.USB_OTG_HS,
        p.PA12,
        p.PA11,
        &mut embassy_stm32::usb_otg_hs::CONFIG,
    );
    
    // 配置USB设备
    let mut config = Config::new();
    config.manufacturer = Some("Embassy");
    config.product = Some("USB example");
    config.serial_number = Some("12345678");
    config.max_power = 100;
    config.max_packet_size_0 = 64;
    
    // 创建设备构建器
    let mut builder = Builder::new(
        driver,
        config,
        &mut [0; 256], // 描述符缓冲区
    );
    
    // 这里可以添加各种USB功能类
    // builder.hid(...);
    // builder.cdc(...);
    
    // 构建USB设备
    let usb = builder.build();
    
    // 运行USB任务
    spawner.spawn(usb_task(usb)).unwrap();
    
    // 主应用逻辑...
}

#[embassy_executor::task]
async fn usb_task(usb: embassy_usb_synopsys-otg::UsbDevice<'static, Driver<'static>>) {
    usb.run().await;
}

完整HID设备示例

下面是一个完整的HID键盘设备实现示例:

use embassy_executor::Spawner;
use embassy_usb_synopsys_otg::{Driver, Builder, Config};
use embassy_usb_synopsys_otg::class::hid::{HID, HidReaderWriter, HIDConfig, KeyboardReport};
use embassy_time::Timer;

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // 初始化硬件
    let p = embassy_stm32::init(Default::default());
    
    // 创建USB驱动
    let driver = Driver::new(
        p.USB_OTG_HS,
        p.PA12,
        p.PA11,
        &mut embassy_stm32::usb_otg_hs::CONFIG,
    );
    
    // 配置USB设备
    let mut config = Config::new();
    config.manufacturer = Some("Embassy");
    config.product = Some("HID Keyboard");
    config.serial_number = Some("12345678");
    config.max_power = 100;
    config.max_packet_size_0 = 64;
    
    // 创建设备构建器
    let mut builder = Builder::new(
        driver,
        config,
        &mut [0; 256],
    );
    
    // 添加HID功能类
    let hid = HID::new(&mut builder, HIDConfig {
        report_descriptor: KeyboardReport::desc(),
        request_handler: None,
        poll_ms: 60,
        max_packet_size: 64,
    });

    let hid = hid.into_reader_writer().unwrap();
    
    // 构建USB设备
    let usb = builder.build();
    
    // 启动任务
    spawner.spawn(usb_task(usb)).unwrap();
    spawner.spawn(hid_task(hid)).unwrap();
}

#[embassy_executor::task]
async fn usb_task(usb: embassy_usb_synopsys_otg::UsbDevice<'static, Driver<'static>>) {
    usb.run().await;
}

#[embassy_executor::task]
async fn hid_task(mut hid: HidReaderWriter<'static, Driver<'static>>) {
    let mut report = KeyboardReport {
        modifier: 0,
        reserved: 0,
        leds: 0,
        keycodes: [0; 6],
    };
    
    // 模拟按键按下/释放
    loop {
        // 按下A键
        report.keycodes[0] = 0x04; // HID usage code for 'a'
        
        // 发送按键按下报告
        hid.write(&report).await.ok();
        Timer::after_millis(100).await;
        
        // 释放所有按键
        report.keycodes[0] = 0x00;
        hid.write(&report).await.ok();
        
        Timer::after_secs(1).await;
    }
}

完整CDC串口设备示例

下面是一个完整的USB CDC ACM(串口)设备实现示例:

use embassy_executor::Spawner;
use embassy_usb_synopsys_otg::{Driver, Builder, Config};
use embassy_usb_synopsys_otg::class::cdc_acm::CdcAcmClass;
use embassy_time::Timer;

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // 初始化硬件
    let p = embassy_stm32::init(Default::default());
    
    // 创建USB驱动
    let driver = Driver::new(
        p.USB_OTG_HS,
        p.PA12,
        p.PA11,
        &mut embassy_stm32::usb_otg_hs::CONFIG,
    );
    
    // 配置USB设备
    let mut config = Config::new();
    config.manufacturer = Some("Embassy");
    config.product = Some("CDC Serial");
    config.serial_number = Some("12345678");
    config.max_power = 100;
    config.max_packet_size_0 = 64;
    
    // 创建设备构建器
    let mut builder = Builder::new(
        driver,
        config,
        &mut [0; 256],
    );
    
    // 添加CDC功能类
    let cdc = CdcAcmClass::new(&mut builder, 64);
    
    // 构建USB设备
    let usb = builder.build();
    
    // 启动任务
    spawner.spawn(usb_task(usb)).unwrap();
    spawner.spawn(cdc_task(cdc)).unwrap();
}

#[embassy_executor::task]
async fn usb_task(usb: embassy_usb_synopsys_otg::UsbDevice<'static, Driver<'static>>) {
    usb.run().await;
}

#[embassy_executor::task]
async fn cdc_task(mut cdc: CdcAcmClass<'static, Driver<'static>>) {
    let mut buf = [0; 64];
    
    // 发送欢迎消息
    cdc.write(b"USB CDC Serial Device Ready!\r\n").await.ok();
    
    loop {
        // 读取数据
        let n = match cdc.read(&mut buf).await {
            Ok(n) => n,
            Err(_) => continue,
        };
        
        if n > 0 {
            // 回显接收到的数据
            cdc.write(&buf[..n]).await.ok();
            
            // 添加换行符
            if buf[n-1] != b'\n' {
                cdc.write(b"\r\n").await.ok();
            }
        }
        
        Timer::after_millis(10).await;
    }
}

高级配置

自定义描述符

use embassy_usb_synopsys_otg::descriptor::*;

let mut builder = /* ... */;

builder.device(
    &[
        DeviceDescriptor::new(0x0200, 0xff, 0xff, 0, 64, 0x1234, 0x5678, 0x0100, 1, 2, 3, 1),
        // 接口、端点等描述符...
    ],
    &[
        &langid::ENGLISH_US,
        // 其他字符串描述符...
    ],
);

电源管理

// 在Config中配置电源相关参数
let mut config = Config::new();
config.max_power = 500; // 500mA
config.self_powered = true;

注意事项

  1. 需要根据具体硬件调整引脚和USB控制器配置
  2. 描述符缓冲区大小需要足够容纳所有描述符
  3. 不同的STM32系列可能有不同的USB外设实现
  4. 在低功耗应用中需要考虑USB挂起/恢复功能
回到顶部