完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
`前面我们介绍了新出USB设备类型WebUSB,其中使用MM32 MCU实现WebUSB功能。既然可以通过网页与USB设备通信,那是否可以做别的功能,比如USB-DFU,当然是可以的,我们通过网页进行DFU功能,即WebDFU功能。因此我们本节我们讲解如何在MM32 MCU实现WebDFU功能。 DFU是使用USB作为微控制器和编程工具之间的通信信道,通常是PC。在DFU类规格书说明中指出所有的DFU命令、状态和数据交换都需要通过端点0进行。命令集和基本协议都定义好的,但是上层协议(数据格式,错误信息等)是客户相关的。也就是说DFU类并没有定义数据传输格式(s19,16进制,纯2进制等等) 由于一个设备同时进行DFU操作和正常运行功能活动是不现实的,因此在DFU操作期间必须停止正常运行活动,这就意味着设备必须改变运行模式——也就是说我们在进行固件更新时比如打印机不再是打印机了,它是一个flash存储器编程器。但是支持DFU的设备不能自主改变模式,这需要接受外部(人或者主机操作系统)的干预。 对于DFU功能,其完成实现固件升级可以分为4个不同阶段。 01 枚举 设备把自身的一些特性告知主机,嵌入在设备正常运行描述符中的一个DFU类接口描述符和相关的函数符能够完成这个目的,并且能够为通过控制管道的类专用的请求提供目标。 02 DFU枚举 主机和设备同意开始固件升级,主机向设备发出USB复位,设备发出第二个描述符集合,并且为传输阶段做准备,这会是相应设备的运行时驱动无效,并使得DFU驱动不受其他目标为该设备通信妨碍,重编程设备的固件。 03 传输 主机将固件映像传输给设备,功能描述符中的参数用于确保非易失性存储器编程的块大小和时序的正确性。状态请求用于保持主机和设备之间的同步。 04 显示 一旦设备向主机报告重新编程完成,主机箱设备则发送u***复位,设备重枚举并执行升级后的固件。为了保证只有DFU驱动加载,有必要的在枚举DFU描述符集合改变id-product字段。 本节我们来讲解如何在MM32 MCU实现WebDFU设备功能,对于MM32 MCU来说,实现WebDFU只需要在之前程序基础上修改添加部分代码即可,按照开源的WebDFU协议加入功能。 本次我们采用MM32L373 miniboard作为测试开发板。为了方便大家使用MM32 MCU的WebDFU设备功能,我们重新封装好全部代码,用户不需要自己配置那些麻烦的描述符等参数,只需要知道用之前的单一设备函数即可。 软件资源如下: 对于MM32 MCU的WebDFU,我们可以配置WebDFU的参数。 #define USBD_DFU_DNLOAD_ENABLE 1 #define USBD_DFU_UPLOAD_ENABLE 0 #define USBD_DFU_STRDESC L"USB_DFU" #define USBD_DFU_XFERBUF_SIZE 1024 #define USBD_WEBUSB_VENDOR_CODE 0x21 #define USBD_WEBUSB_BASE_LANDING_URL "devanlai.github.io/webdfu/dfu-util/?vid=" #define USBD_WEBUSB_LANDING_URL CONCAT_MACRO_TO_STRING(USBD_WEBUSB_BASE_LANDING_URL, USBD_DEVDESC_IDVENDOR) #define USBD_WEBUSB_ORIGIN_URL "devanlai.github.io/" #define USBD_WEBUSB_IF_NUM USBD_DFU_IF_NUM 参数设置如上。当进行DFU升级时候,可以看到电脑上显示的设备名称为USB_DFU,就是配置的USBD_DFU_STRDESC参数。 在使用MM32 WebDFU功能之前先调用USB初始化函数来初始化USB协议栈。 int main(void) { // USB Device Initialization and connect u***d_init(); u***d_connect(__TRUE); while (!u***d_configured()) // Wait for USB Device to configure { } while (1) { …… } } 然后依然和之前一样只是在WebUSB基础上修改添加WebDFU相关参数函数接口即可,代码如下: //DFU初始化 void u***d_dfu_init(void) { DFU_Reset(); current_write_addr = 0; } //USB DFU开始升级 BOOL USBD_DFU_StartUpgrade(void) { error_t err = flash_manager_init(target_device); current_write_addr = target_device.flash_start; switch (err) { case ERROR_SUCCESS: initialized = true; break; case ERROR_RESET: case ERROR_ALGO_DL: case ERROR_ALGO_DATA_SEQ: case ERROR_INIT: case ERROR_SECURITY_BITS: case ERROR_UNLOCK: DFU_SetStatus(DFU_STATUS_ERR_PROG); break; case ERROR_ERASE_SECTOR: case ERROR_ERASE_ALL: DFU_SetStatus(DFU_STATUS_ERR_ERASE); break; case ERROR_WRITE: DFU_SetStatus(DFU_STATUS_ERR_WRITE); break; case ERROR_FAILURE: case ERROR_INTERNAL: default: DFU_SetStatus(DFU_STATUS_ERR_UNKNOWN); break; } return (err == ERROR_SUCCESS) ? (__TRUE) : (__FALSE); } //复位目标 static bool reset_target(bool error_condition) { current_write_addr = 0; if (initialized) { error_t err = flash_manager_uninit(); switch (err) { case ERROR_SUCCESS: if (config_get_auto_rst()) { // Target is reset and run by the uninit } else if (!error_condition) { // Reset and run the target at the end of a successful upgrade target_set_state(RESET_RUN); } break; case ERROR_RESET: case ERROR_ALGO_DL: case ERROR_ALGO_DATA_SEQ: case ERROR_INIT: case ERROR_SECURITY_BITS: case ERROR_UNLOCK: DFU_SetStatus(DFU_STATUS_ERR_PROG); break; case ERROR_ERASE_SECTOR: case ERROR_ERASE_ALL: DFU_SetStatus(DFU_STATUS_ERR_ERASE); break; case ERROR_WRITE: DFU_SetStatus(DFU_STATUS_ERR_WRITE); break; case ERROR_FAILURE: case ERROR_INTERNAL: default: DFU_SetStatus(DFU_STATUS_ERR_UNKNOWN); break; } initialized = false; return (err == ERROR_SUCCESS); } return true; } //USB DFU结束升级 BOOL USBD_DFU_FinishUpgrade(void) { return reset_target(false) ? (__TRUE) : (__FALSE); } //USB DFU写数据 BOOL USBD_DFU_WriteBlock(const U8 *buffer, U16 blockSize) { error_t err = flash_manager_data(current_write_addr, (U8*)buffer, blockSize); switch (err) { case ERROR_SUCCESS: current_write_addr += blockSize; break; case ERROR_RESET: case ERROR_ALGO_DL: case ERROR_ALGO_DATA_SEQ: case ERROR_INIT: case ERROR_SECURITY_BITS: case ERROR_UNLOCK: DFU_SetStatus(DFU_STATUS_ERR_PROG); break; case ERROR_ERASE_SECTOR: case ERROR_ERASE_ALL: DFU_SetStatus(DFU_STATUS_ERR_ERASE); break; case ERROR_WRITE: DFU_SetStatus(DFU_STATUS_ERR_WRITE); break; case ERROR_FAILURE: case ERROR_INTERNAL: default: DFU_SetStatus(DFU_STATUS_ERR_UNKNOWN); break; } return (err == ERROR_SUCCESS); } 这样我们就完成MM32 MCU的WebDFU功能,将程序下载到板子中,USB插上电脑,电脑上会枚举出USB DFU。在USB DFU枚举成功后,我们需要检查是否真的可以被WebDFU网页识别。 打开https://devanlai.github.io/webdfu/dfu-util/通过该网页检测WebDFU工作状态,网页如下图所示: |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2248个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11681 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5922 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10955 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4571 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4298 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
964浏览 1评论
792浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 08:29 , Processed in 0.590152 second(s), Total 59, Slave 44 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号