4个版本 (2个重大更新)
0.3.1 | 2023年5月15日 |
---|---|
0.3.0 | 2023年3月8日 |
0.2.0 | 2022年11月28日 |
0.1.0 | 2021年5月26日 |
在 嵌入式开发 中排名 480
每月下载量 95
在 kiffieboot 中使用
20KB
154 行
usbd-dfu-rt

这是一个Rust包,用于实现USB DFU运行时类,用于与usb-device包一起使用。
DFU运行时类
DFU代表设备固件升级。DFU定义了两个USB类
- DFU模式:用于传输新固件并刷新设备
- 运行时:宣布DFU能力,可用来将设备模式更改为DFU升级
此包根据USB DFU类规范版本1.1a实现DFU运行时类。它仅实现运行时类,这意味着它仅实现DFU_DETACH请求。此请求意味着设备应切换到DFU模式,为固件升级做准备。这通常意味着重启到具有DFU功能的引导加载程序,然后处理升级。
用法
要使用此类,用户必须提供一个回调,该回调将执行切换到DFU模式的转换,这非常特定于设备。特定于应用程序的行为由实现DfuRuntimeOps
来定义。
- 定义将实现
DfuRuntimeOps
的类型并保留任何附加状态。 - 在
DfuRuntimeOps
中设置const
设置或使用默认值。 - 实现
DfuRuntimeOps::detach
和可选的DfuRuntimeOps::allow
。 - 定期调用
DfuRuntimeClass::tick
。
DfuRuntimeOps::allow
在接收到 DFU_DETACH 请求时被调用,可以用来拒绝该请求或更改超时值。
根据 DfuRuntimeOps::WILL_DETACH
的值,DfuRuntimeOps::detach
被调用的方式不同。当 WILL_DETACH=false
时,此类会等待检测到主机发出的 USB 重置,然后调用 DfuRuntimeOps::detach
。
当 WILL_DETACH=true
时,从 DfuRuntimeOps::allow
返回的 timeout
被用于在调用 DfuRuntimeOps::detach
前等待。这通常是所需的,因为设备应该能够用接受的方式响应断开连接请求。否则,主机可能会看到断开连接错误。因为应用程序经常需要执行一些清理操作(禁用外围设备等),这个超时机制可以简化用户逻辑:在 DfuRuntimeOps::allow
返回应用程序清理和启动所需的时间,当调用 DfuRuntimeOps::detach
时,应用程序可以简单地切换到 DFU 模式。对于更复杂的逻辑,DfuRuntimeOps
可以在 DfuRuntimeOps::allow
期间存储一些状态,并在忽略 DfuRuntimeOps::detach
的情况下以自定义方式执行断开连接操作。
示例
一些微控制器可能带有内置的 DFU 负载程序固件。这可以用来以最少的努力实现通过 USB 的完整固件更新 - 我们只需要实现 DFU 运行时类,而 DFU 模式在嵌入式负载程序中实现。STM32F072 微控制器就是一个例子。
在 STM32F072 上,在跳转到嵌入式负载程序之前,我们应该禁用所有外围设备,将它们设置为复位状态。这在我们的应用程序中可能有些问题,但我们可以只执行 CPU 重置,这将重置外围设备,然后跳转到嵌入式负载程序。为此,我们需要一种方式让固件检测到发生了重置,因为我们想跳转到 DFU 负载程序。这可以通过在内存中存储一个魔法值并在重置后立即检查它来实现。
以下代码可用于实现上述逻辑。当接收到DFU_DETACH请求时,将调用detach
,设置魔法值并重置MCU。在执行任何初始化RAM的代码之前(由于#[cortex_m_rt::pre_init]
属性),将执行jump_bootloader
例程,因此魔法值将仍然存储重置前的值。然后检查是否应该跳转到嵌入式引导加载程序。请确保在主循环中调用DfuRuntimeClass::tick
。
use core::mem::MaybeUninit;
use cortex_m_rt;
use usbd_dfu_rt::DfuRuntimeOps;
const MAGIC_JUMP_BOOTLOADER: u32 = 0xdeadbeef;
const SYSTEM_MEMORY_BASE: u32 = 0x1fffc800;
#[link_section = ".uninit.MAGIC"]
static mut MAGIC: MaybeUninit<u32> = MaybeUninit::uninit();
#[cortex_m_rt::pre_init]
unsafe fn jump_bootloader() {
if MAGIC.assume_init() == MAGIC_JUMP_BOOTLOADER {
// reset the magic value not to jump again
MAGIC.as_mut_ptr().write(0);
// jump to bootloader located in System Memory
cortex_m::asm::bootload(SYSTEM_MEMORY_BASE as *const u32);
}
}
pub struct DFUBootloader;
impl DfuRuntimeOps for DFUBootloader {
fn detach(&mut self) {
unsafe { MAGIC.as_mut_ptr().write(MAGIC_JUMP_BOOTLOADER); }
cortex_m::peripheral::SCB::sys_reset();
}
}
// Remember to call .tick() regularly!
依赖项
约150KB