DFU工作过程中USB机制

STM32CubeMX学习笔记(50)——USB接口使用(DFU固件升级 USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。USB 发展到现在已经有 USB1.0/1.1/2.0/3.0 等多个版本。目前用的最多的就是 USB1.1 和 USB2.0,USB3.0 目前已经开始普及。 阅读详情

在一级bootloader运行进入USB启动方式之后,设备进行枚举。枚举过程中会通过PC端发送命令对连接的USB设备进行枚举。当枚举成功之后,在PC端能够看到设备的盘符。

当设备能够被PC正确识别之后,接下来就可以通过烧写工具完成设备的扫描如果成功找到设备,则可以通过USB传输数据到SRAM中,这时候的数据主要包括2k infor文件。一级bootloader在成功的解析2kinfor 之后,PC端会将DFU文件传输到初始化好的DRAM中。并且PC指针跳转到DFU地址处执行,执行过程中会跳转到USB初始化程序过程中。

USB的初始化过程主要分为两个部分,一个部分是初始化UDC设备,第二部分是等待PC端发送的命令并响应。这个过程的描述如下:

 

在USB的初始化过程中会调用VIM_CLKRST_UotgExitRst();函数。

此函数中,

VOID VIM_CLKRST_UotgExitRst(VOID)

{

       __CLKRST_UotgSWRst();//为了防止global rst之后,来不了中断导致挂死

       __CLKRST_UotgExitRst();

       //waitfor uotg swrstdone irq

       while(!__CLKRST_CheckUotgSwrst())//poolling

       {

              //donothing

       };

       __CLKRST_ClearUotgSwrstIrq();

}

会首先设置0x604寄存器的bit25,UOTG_SW_RESET。接着设置0x610寄存器的SW_CFG_UOTG_DONE,bit12。uotg software configuration done flag, high active

然后死等UOTG_RSTDONE_IRQ中断的到来。最后写清中断。

在初始化函数的最后,会调用

UDC_DFU_Init(VIM_USB_DataProcess,VIM_USB_ArmSpeedBinProcess);函数,函数中会将两个函数指针进行赋值给全局变量g_Usb_Process_Call以及g_Usb_SpeedBin_Call,函数指针的定义为typedef VIM_RESULT(* PFatCallBack)(UINT8 *, UINT32);

void UDC_DFU_Init(PFatCallBackp_data_process,PFatCallBack p_speedbin_process)

{    

       VIM_HAL_PrintStr("UDC_DFU_Init:\r\n");

       g_Usb_Process_Call= p_data_process;//处理收到的512字节,就是一个sector

       //其中g_Usb_Process_Call用于USB工具下载IMAGE时对一个sector的处理

       g_Usb_SpeedBin_Call= p_speedbin_process;//装载speed sorting镜像

      

       g_FatCtx.pcall= p_data_process;

    //g_FatCtx.pcall用于U盘拷贝方式对一个sector的处理

      

       g_FatCtx.fat_total_sec= ChkFatBoot(DFU_SIZE);

      

   udc_mass_init(&g_DfuMedOp, 1);

   udc_mass_start();  

}

此函数中会对fat设备的cluster等变量值进行计算,并且初始化mass设备。初始化的过程主要是对设备操作过程中记录状态机等信息的全局变量this_usb_udc进行赋初始值。

void udc_mass_init(PUSB_MED_IF pMedIf,UINT8 lun_num)

{

 

       VIM_HAL_Memset(&g_mass_ctx,0, sizeof(g_mass_ctx));

 

       g_mass_ctx.maxlun= 0;

//     g_DataShared= (UINT8*)VIM_USB_DATA_BUF;

       g_mass_ctx.lun[0].dma_addr[0]= (void *) (((UINT32)g_DmaNotMallocAddr+0x1000)&0xfffff000);

       g_mass_ctx.lun[0].pUmdIf= pMedIf;

       udc_init();

}

在udc_init()中会完成对设备赋初值的操作,主要包括设备的初始状态值,DMA地址等信息以及如下结构体变量值,

USB_MED_IF g_DfuMedOp =

{

       NULL,

       MedBoot_rd_sec,

       MedBoot_wr_sec,

       MedBoot_get_status,

       MedBoot_get_sec_num,

       NULL,

       {

              {'o','o', 'o', 'o', 'o', 'o', 'o', 0x20},//VID

              {'S','U', 'P', 'E', 'R', 0x20, 'D', 'I', 'S', 'K', 0x20, 0x20, 0x20, 0x20, 0x20,0x20},//PID

              {'1','.','0','0'}//VERSIIN

       }

};

在整个初始化过程的最后会通过配置寄存器连接并使能设备为高速设备。

Udc_SetUsbPower(UDC_M_POWER_SOFTCONN|UDC_M_POWER_HSENAB);

至此设备的初始化过程完成,接下来会进入循环等待设备与host端进行交互的操作过程。

 

在udc_mass_process函数中会注册“查询处理usb数据传输状态,进行数据处理”的中断,接受中断并进行处理。

void udc_mass_process(void)

{

   udc_int_usb();//查询处理usb数据传输状态,进行数据处理

 

       if(g_mass_ctx.usb_state!= USB_STATE_CONFIGURED)

              return;

             

       if(g_mass_ctx.umb_state== UMB_IDLE)

       {

              req_cbw();

       }

       elseif(g_mass_ctx.umb_state == UMB_CBW_OK)

       {

              do_cbw();

       }

}

在设备接收到的CBW状态为UMB_CBW_OK时,会通过do_cbw对数据进行分发和处理,这个过程中,主要是通过UmscProcess函数。在case中会看到在PC端程序中传递下来的子命令。

static void do_cbw(void)

{

              UINT32  reqlen = 0;

             

              pCsw->Tag= pCbw->Tag;

              reqlen= UdcGet32Lbuf( (UINT8*)(&pCbw->TransferLength) );

              g_mass_ctx.umb_state= UMB_CBW_PROCESS;

              UmscProcess(&g_mass_ctx.lun[pCbw->Resv_Lun], pCbw->CbOpt, pCbw->CbData,pCbw->Flags, reqlen );

             

}

 

根据上面的描述大体上了解了USB设备注册完成之后设备的一些状态问题。在上面的描述中可以看到打开了USB的中断,这时候设备会进行重新枚举的过程,重新枚举的过程是会首先发送reset命令。在DFU中等待设备reset的过程显得比较漫长。这个过程中需要注意是否能够进行优化。

 

此处还是没有查明到底reset是从代码的那个位置传送下来,还是在udc_mass_process完成注册之后会一直扫描中断,但是后者看起来不像。

 

当接收到reset中断后,会对端点进行重新设置,并且通过调用udc_nuke_req()函数完成实际的操作。

/***************************************************************************************

总线RESET后执行的操作

****************************************************************************************/

static void udc_usbreset(void)

{

       UINT32val;

      UINT8 i;

   VIM_DBG_Print(USB_MSG_DEVICE_RESET);

       //Udc_SetIntUnmask(UDC_INT_USB|UDC_INT_DMA);

       //usbint , all without sof

       val= ~UDC_M_INTR_SOF;

       Udc_SetUsbIrqEn(val);

 

       Udc_SetInIrqEn((0x1<<EP_CTRL)|(0x1<<EP_BULK_IN)|(0x1<<EP_INTR_IN) );

       Udc_SetOutIrqEn((0x1<<EP_CTRL)|(0x1<<EP_BULK_OUT)|(0x1<<EP_INTR_OUT) );//重新使能相应的端点

      

       this_usb_udc.state= USB_STATE_DEFAULT;

       this_usb_udc.highspeed= 1;

 

       //各个端点注册的RESET函数,在udc_ttc.c和udc_bulkonly中定义了this_usb_udc.driver指向的实体结构体

       //g_ttc_driver      and   g_mass_driver

       if(this_usb_udc.driver != NULL )//在TTC中,将命令的各个管道的USBstate设置成usb_state =USB_STATE_DEFAULT

              this_usb_udc.driver->reset();

 

      

       udc_nuke_req();//??????????????????????????????????????????

      

      

       //OUT和中断端点设置BUSY位,为什么?这个BUSY的用处是什么?

       //这两位为1表示不能使能RX端点,即清除它的RXPKTRDY位,不能接收下笔数据

       //这两位在第一次REQ_CBW时被清除,由于系统默认是可以接收数据的,这次就不必

       //人工使能端点接收了

       this_usb_udc.ep[EP_BULK_OUT].busy= 1;//此时g_ep_out=EP_IDX_1

       this_usb_udc.ep[EP_INTR_OUT].busy= 1;//此时EP_INTR_OUT=EP_IDX_3

 

       //清除端点的FIFO和TOG,释放停止状态标志

       for(i=0;i<EP_GT_NUM; i++)

       {

              Udc_EpRst(i, USB_EP_RET_DIR_OUT);//out

              Udc_EpRst(i,USB_EP_RET_DIR_IN); //in

              this_usb_udc.ep[i].halt= 0;

       }

 

}

上面的代码中调用了this_usb_udc.driver->reset();这个函数的赋值是通过对结构体进行整体赋值完成的,

struct usb_driver g_mass_driver =

{

       UsbMassClsReq,

       Usb_MassGetDescBuf,

       UsbMassSetCfg,

       UsbMassReset,

       UsbMassSuspend,

       UsbMassSetIntf

};

usb_driver结构体的定义为:

struct usb_driver {

       void                                    (*udc_vendor_class_req)(structusb_fifo *);

       UINT8*         (*get_desc)(UINT8 highspeed, UINT8type, UINT16* len, UINT8 strIdx);

       void                                    (*set_cfg)(void);

       void                                    (*reset)(void);

       void                                    (*suspend)(void);

       void                                    (*set_interface)(UINT16intface, UINT16 altset);

};

实际过程中UsbMassReset函数完成的操作仅仅是对g_mass_ctx.usb_state进行赋值为 USB_STATE_DEFAULT,设置这个状态会让设备。目前能够看到的在DFU中状态机的操作是在GetConfig的过程中作为控制端点是否可用的状态判断符,

       if(this_usb_udc.state == USB_STATE_DEFAULT )

       {

              udc_CtrlCmdNotSupport();

              return;

       }

如果不支持这样的控制命令那么就会stall endpoint为停止状态。

在udc_nuke_req()函数中,会根据选择的传输方式不同进行不同的控制。通常情况下,控制传输使用FIFO方式,而在需要大量数据传输的bulk传输过程中会使用DMA方式。

USB -- STM32F103 USB DFU设备固件升级(IAP)控制传输讲解(六) STM32F103 USB DFU设备固件升级(IAP)控制传输 阅读详情

相关推荐

STM32CubeMX学习笔记(50)——USB接口使用(DFU固件升级)_usb dfu

修改参数配置。1024 Bytes0x08005800根据下面编译后 .map 文件大小,可以了解程序存储到了哪些区域。来设置Application程序起始地址,避开Bootloader程序地址范围。打开 map 文件后,查看文件最后部分的区域,可以看到一段以 “” 开头的记录(若找不到可用查找功能定位)Bootloader程序的基地址是 0x08000000,大小为 0x00004a84,可知它占用的最高的地址空间为 0x08004a84。

2501_90424728的博客 4836

STM32CubeMX学习笔记(50)——USB接口使用(DFU固件升级)

DFU全称为Download Firmware Update,是ST官方推出的一个通过USB接口进行IAP升级的方案,同串口ISP一样,他们都集成在了芯片内部的Bootloader区段,可以通过配置boot引脚来启动。(具体可参照ST文档:AN2606)。不过内置DFU的芯片大部分型号都比较新,如果你用的型号没有内置DFU程序,没关系我们也可以通过CubeMX来快速生成和移植一个DFU功能程序到你的Flash中来使用。

Leung的博客 1万+

stm32L4xx 通过USB DFU功能升级固件

stm32L4xx 通过USB DFU功能升级固件 背景 因为项目需求,用户不方便用SWD模式下载程序,而且本设备也留有USB,因此考虑用USB DFU模式进行固件升级。 设备上使用的单片机是stm32l476,ST官方在单片机内部bootloader已经支持通过USB方式升级固件,但是需要通过修改MODE来切换是升级固件还是运行用户程序,设备本身也没有留修改mode的按键等,因此考虑修改使

Dukezhao的专栏 4793

关于USB的DFU固件升级的一些问题

在反复报错重启电脑中终于知道,我在某次尝试修改中在CubeMX中reset了USB设置,然后那个USBD_DFU_APP_DEFAULT_ADD 就变成了bootloar的地址0x08000000(我就说为啥串口打印一直都在循环),修改后还是发现2和1 的问题,就发现参考博客程序一进BootLoader程序就跳转到APP了,一跳到APP的话,设备应该就不是在DFU中,然后。),所以栈区的大小一定大于2K才能不会出现问题,这里大小设置可以编译后查看map文件,查看栈的使用情况。如果点击是,立刻电脑重启!

m0_51482794的博客 1558

STM32 USB DFU固件升级的设计与实现

Bootloader需要实现USB接口功能,并在接收到DFU命令时,负责擦除Flash、接收固件数据并进行程序的更新。合理设计Bootloader、PC端DFU固件升级工具和固件升级应用程序,可以满足不同需求下的固件升级要求,并提供高效、稳定的固件升级功能。PC端需要提供对应的DFU固件升级工具,用于与STM32设备通过USB接口进行通信,并发送固件数据。在固件升级过程中,需要保证新旧固件的兼容性,尤其是在固件数据结构和存储方式发生变化时。在PC端DFU固件升级工具中连接设备,并选择需要升级的固件文件。

weixin_66608063的博客 1814

STM32F4通过USB2.0实现DFU升级的全面讲解

深入解析STM32F4如何利用usb2.0实现高效DFU固件升级,涵盖配置流程与通信机制,提升开发效率与设备维护便捷性。

weixin_30923011的博客 1358

USB设备在连接PC时的reset从何而来?

最近在做烧写工具的优化工作,有一些关于USB的内容需要总结一下其中包括设备的初始化过程和枚举过程。 在枚举的过程中,设备会一直等PC端的状态,当等到reset命令时会对设备进行重新枚举。但是这个reset终端是如何而来呢? Halt Conditions A control endpoint may recover from a halt condition upon receiving

曹太强的专栏 8179

STM HAL库USB DFU(实战1)

前言: 本文主要解决的问题是实现IAP功能,包括升级应用程序(APP)和升级数据包到外部Flash。方法是利用USB DFU Class以及ST提供的DfuSe demo软件工具实现,至于DFU class移植直接利用cube生成。 IAP介绍: IAP(In application program)主要为使用者提供了一种更加灵活的固件升级方式,可以根据应用需要定义何时、何种...

RANBIRON的博客 2104

STM32 DFU下载与 DFU生成工具

发一个适合所有STM32的下载教程。由于手头上没有STLINK等可用的调试器,所以一直没能将CANNON用起来,偶然发现STM32支持DFU模式,可以通过USB下载固件,一切搞定。DFU是通过STM32的USB下载的,所以STM32的USB接口得引出。1. 下载安装ST的DFU下载 工具:http://www.st.com/web/en/catalog/tools/FM147/CL1794/SC961/SS1533/PF2579162. CANNON给的示例工程是keil的,设置一下让其 输出hex文件:.

子曰小玖的博客 3万+

USB DFU固件升级实现流程(基于STM32F407ZG,附源码)

使用 Dfuse 工具,利用 USB 的 DFU 功能实现固件升级,Bootloader分配32KBytes的Flash,剩余分配给Application。代码功能已验证,使用探索者开发板直接烧录即可测试。

Freddy_Ssc的博客 2759

STM32实现USB DFU升级功能:系统学习与调试

深入讲解STM32如何实现USB DFU升级功能,结合usb协议底层原理,帮助开发者掌握系统设计与调试技巧,提升固件更新的稳定性与效率。

weixin_42234168的博客 916

STM32:USB 虚拟串口以及使用usb->dfu进行iap

USB虚拟串口不仅简化了硬件设计,避免了传统串口电平转换芯片的使用,还能提供更稳定的通信速率和更远的传输距离。对于调试信息输出、数据采集与监控等应用场景来说,USB虚拟串口是一种非常实用的技术方案。此外,通过USB实现DFU功能,使得用户可以在不依赖额外硬件工具的情况下,方便快捷地对STM32设备进行固件更新,极大地提高了产品的可维护性和用户体验。提示:以下是本篇文章正文内容,下面案例可供参考。

weixin_53950683的博客 3008

(八)基于MuJoCo的LeRobot SO100仿真操控实战指南(操作优化)

本文详细介绍了如何在MuJoCo仿真环境中搭建并优化LeRobot SO100机械臂的操控。通过两种核心模式(纯键盘仿真与实机镜像同步)的实战演示,重点讲解了关键的参数标定方法,以实现虚拟模型与真实硬件的精准同步。文章还提供了性能优化技巧,旨在帮助开发者构建高效、安全的机器人算法开发与测试流程。

weixin_29083649的博客 319

STM32 IAP应用开发——通过内置DFU实现USB升级(方式1)

DFU全称为Download Firmware Update,是ST官方推出的一个通过USB接口进行IAP升级的方案,同串口ISP一样,他们都集成在了芯片内部的Bootloader区段,可以通过配置boot引脚来启动。

ShenZhen_zixian的博客 1万+

从零开始:用7353张VOC/YOLO格式混凝土缺陷数据集训练你的第一个检测模型

本文详细介绍了如何使用7353张VOC/YOLO格式的混凝土缺陷数据集训练首个目标检测模型。从环境配置、数据解析到YOLOv5模型训练与优化,提供了完整的实战指南,特别针对数据不平衡问题给出了解决方案,助力开发者快速掌握混凝土缺陷识别技术。

weixin_42651281的博客 256

NRF24L01模块的5个常见问题及解决方案:从信号干扰到功耗优化

本文深入探讨NRF24L01无线模块在STM32开发中的5大常见问题及解决方案,包括通信距离优化、数据丢失排查、电源噪声抑制、SPI通信故障处理以及低功耗设计。通过代码示例和电路图分析,提供实用的优化策略,帮助开发者提升无线通信的稳定性和效率。

weixin_28256233的博客 226

STM32+CubeMX实现USB DFU下载

本文介绍了基于STM32F446RET6和CubeMX实现USB DFU固件升级的方法。主要内容包括:1)硬件使用Type-C接口和STM32CubeMX配置USB DFU功能;2)将Flash分为bootloader区(扇区0-3)和应用程序区(扇区4-7);3)修改usbd_dfu_if.c文件实现Flash擦写功能;4)提供应用程序跳转函数。该方法通过USB接口实现固件升级,无需额外硬件工具,先通过ST-Link下载引导程序,后续可通过USB直接更新固件。文中详细说明了CubeMX配置步骤和关键代码修

m0_63892330的博客 1275

告别有线:用PVE直通无线网卡,打造一台真正的‘无线’Win10软路由/测试机

本文详细介绍了如何通过PVE直通无线网卡技术,构建全无线Win10软路由或测试机。从硬件选型、PVE环境配置到PCIe和USB双模直通技术,逐步指导实现Wi-Fi AP和蓝牙连接功能,为家庭实验室和小型办公环境提供灵活高效的网络解决方案。

weixin_28683689的博客 587

USB - DFU(dfuse\stm32)、fastboot、dfu-util

usb中cdc dfu hid msc的区别 cdc :communication device class,CDC是通信设备级方案,是USB 转其他的接口的一类设备,比如USB转RS232,USB转Ethernet等 dfu :Device Firmware Upgrade主要使用USB接口,实现固件的上传与下载 hid :humman interface device,人机接口级方案,多为不需...

u012944254的博客 5281

智能车赛道识别:八邻域算法的实战解析与优化

本文深入解析了智能车赛道识别中八邻域算法的核心原理与实战优化。作为兼顾性能与稳定性的经典方案,该算法通过模拟探险家环顾八方的策略,能精准追踪弯道与直道边界。文章详细拆解了代码逻辑,并提供了边界平滑、异常处理及应对十字路口、环岛等复杂场景的关键优化策略,助力开发者提升智能车视觉系统的鲁棒性与实时性。

weixin_29228781的博客 261

Python爬虫实战:利用Playwright和反反爬技术高效抓取Bloomberg金融数据

用户行为分析(鼠标移动、点击模式)请求头检测IP频率限制WebSocket通信验证Canvas指纹识别我们的爬虫需要模拟人类行为,使用代理IP池,并合理控制请求频率。

2201_76125261的博客 1020

学习一下USB DFU

USB DFU(USB Device Firmware Upgrade,USB设备固件升级)是一种用于在USB设备上进行固件更新的标准化协议。

最后一个bug的博客 2535

Vue - 最新详细实现滑块拖动拼图验证,网站登录验证滑块验证功能,拖动滑块到图片缺口的位置即为成功,滑块验证安全检测(详细示例代码,一键复制运行)

您一定见过很多系统都“配备”了滑块验证、拼图验证、找不同等,本质上都是为了验证登录系统的是人还是机器(代码),如下图所示效果: 您打开项目根目录,终端执行如下命令:拼图式拖动滑块验证 验证拖动滑块验证,滑动拼图/图片点选验证 接下来,在中加入以下代码: 如下图所示: 更多配置示例和参数详见官方文档,以下便是如上效果图的代码:.........

🏆 前端领域优质创作者 1万+
上一篇: USB设备在连接PC时的reset从何而来?
下一篇: git使用入门
野-百-合
博客等级 码龄17年 308粉丝 118原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值