#usb-device #dfu #no-std

no-std usbd-dfu

用于 usb-device 设备的 DFU 协议

6 个版本 (3 个重大更新)

0.4.0 2024年3月9日
0.3.1 2023年5月6日
0.3.0 2023年3月18日
0.2.0 2021年8月8日
0.0.3 2023年5月6日

#291硬件支持

每月41次 下载

MIT 许可证

52KB
625

usbd-dfu

Crates.io Docs.rs

实现了对 usb-device 设备的 DFU 协议版本 1.1a。

关于

DFU 协议旨在提供一个标准,以便 USB 设备的固件可以进行升级。通常情况下,设备的固件由两部分组成:一个大的主固件和一个较小的引导加载程序。当设备开机时,引导加载程序启动,并运行主固件或进入“固件更新”模式。

协议实现尽量遵循由意法半导体(STMicroelectronics)的 AN3156 和 USB 设备固件升级规范(Revision 1.1)所指定的 DFU 1.1a 协议。

该库仅实现协议,实际编程、擦除或读取内存或闪存的代码不在库中,并预期由库用户提供。

支持的操作

  • 读取(设备到主机)- 上传命令
  • 写入(主机到设备)- 下载命令
  • 擦除
  • 全部擦除

不支持的操作

  • 读取解除保护 - 擦除所有内容并移除读取保护。

限制

  • 最大 USB 传输大小限制为 usb-device 对控制端点传输的支持大小,默认为 128 字节。

  • DFU_GETSTATUS 中的 iString 字段始终为 0。不支持特定厂商的错误描述字符串。

DFU 工具

有许多支持 DFU 协议的 USB 设备烧录工具实现,例如

许可证

本项目根据 MIT 许可证 许可(LICENSE)。

贡献

除非您明确声明,否则您提交给本项目以供包含在内的任何贡献都将按照上述方式许可,不附加任何额外条款或条件。

示例

以下示例尝试专注于 DFUClass,与目标控制器初始化和配置(USB、中断、GPIO 等)相关的部分不在示例范围内。

查看示例以获取更多信息。

请参阅 usb-device 库的文档,这些库支持目标微控制器并提供相应的硬件抽象层(HAL)。

use usb_device::prelude::*;
use usbd_dfu::*;

// DFUClass will use MyMem to actually read, erase or program the memory.
// Here, a set of constant parameters must be set. These parameters
// either change how DFUClass behaves, or define host's expectations.

struct MyMem {
    buffer: [u8; 64],
    flash_memory: [u8; 1024],
}

impl DFUMemIO for MyMem {
    const MEM_INFO_STRING: &'static str = "@Flash/0x00000000/1*1Kg";
    const INITIAL_ADDRESS_POINTER: u32 = 0x0;
    const PROGRAM_TIME_MS: u32 = 8;
    const ERASE_TIME_MS: u32 = 50;
    const FULL_ERASE_TIME_MS: u32 = 50;
    const TRANSFER_SIZE: u16 = 64;

    fn read(&mut self, address: u32, length: usize) -> Result<&[u8], DFUMemError> {
        // TODO: check address value
        let offset = address as usize;
        Ok(&self.flash_memory[offset..offset+length])
    }

    fn erase(&mut self, address: u32) -> Result<(), DFUMemError> {
        // TODO: check address value
        self.flash_memory.fill(0xff);
        // TODO: verify that block is erased successfully
        Ok(())
    }

    fn erase_all(&mut self) -> Result<(), DFUMemError> {
        // There is only one block, erase it.
        self.erase(0)
    }

    fn store_write_buffer(&mut self, src:&[u8]) -> Result<(), ()>{
        self.buffer[..src.len()].copy_from_slice(src);
        Ok(())
    }

    fn program(&mut self, address: u32, length: usize) -> Result<(), DFUMemError>{
        // TODO: check address value
        let offset = address as usize;

        // Write buffer to a memory
        self.flash_memory[offset..offset+length].copy_from_slice(&self.buffer[..length]);

        // TODO: verify that memory is programmed correctly
        Ok(())
    }

    fn manifestation(&mut self) -> Result<(), DFUManifestationError> {
        // Nothing to do to activate FW
        Ok(())
    }
}

let mut my_mem = MyMem {
    buffer: [0u8; 64],
    flash_memory: [0u8; 1024],
};

// Create USB device for a target device:
// let usb_bus_alloc = UsbBus::new(peripheral);
// let usb_dev = UsbDeviceBuilder::new().build();

// Create DFUClass
let mut dfu = DFUClass::new(&usb_bus_alloc, my_mem);

// usb_dev.poll() must be called periodically, usually from USB interrupt handlers.
// When USB input/output is done, handlers in MyMem may be called.
usb_dev.poll(&mut [&mut dfu]);

示例引导加载程序实现

请参阅usbd-dfu-example 以获取一个功能示例。

依赖项

约1.5MB
约28K SLoC