DFU工作过程中USB机制
在一级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方式。
DFU工作过程中USB机制的更多相关文章
- 测试或运维工作过程中最常用的几个linux命令?
大家在测试工作过程中,可能会遇到需要你去服务器修改一些配置文件,譬如说某个字段的值是1 则关联老版本,是0则关联新版本,这时候你可能就需要会下vi的命令操作:或者查看session设置的时长,可能需 ...
- 之前工作过程中自定义的代码生成器模版,codesimit
动软代码生成器 和codesmith 5年前的东西,或许有些过时 动软的功能有限,改的也比较简单,已弃. codesmith可定制性强,当时自已改的,提高了团队的整体工作效率. codesmith代码 ...
- SVC 工作过程中出现的错误记录(SEO项目)
1.同一のキーを含む項目が既に追加されています.追加的项目中含有重复主键) /seo' アプリケーションでサーバー エラーが発生しました. 同一のキーを含む項目が既に追加されています. 説明: 現在の ...
- java jvm概述及工作过程中的内存管理
java jvm 有分层的思想. java类..java文件,源文件,源代码,源程序 编译器不能把源代码直接编译成0101,除非是java语言写的操作系统. windows认识的可执行文件 ...
- Nginx reopen reload作用及工作过程
http://www.iigrowing.cn/nginx-reopen-reload-zuo-yong-ji-gong-zuo-guo-cheng.html Nginx reopen reload作 ...
- JVM加载类的过程,双亲委派机制中的方法
JVM加载类的过程: 1)JVM中类的整个生命周期: 加载=>验证=>准备=>解析=>初始化=>使用=>卸载 1.1.加载 类的加载阶段,主要是获取定义此类的二进 ...
- RT3070 USB WIFI 在连接socket编程过程中问题总结
最近耗时多天,成功的将RT3070驱动.并解决了socket的网络编程,成功的在BA9G10上面实现了USB wif.连上家里的无线路由器,通过ubuntu下面建立的服务端程序,将BA9G10中的数据 ...
- 阿里面试官:Android中binder机制的实现原理及过程?
Binder 是 Android 系统中非常重要的组成部分.Android 系统中的许多功能建立在 Binder 机制之上.在这篇文章中,我们会对 Android 中的 Binder 在系统架构中的作 ...
- 将数据的初始化放到docker中的整个工作过程(问题记录)
将数据的初始化放到docker中的整个工作过程 由于是打算作为个人博客,所以对于install这个步骤,我从一开始就打算删掉的,前面一个多星期一直在修bug,到前天才开始做这个事情. 过程中也是碰到了 ...
随机推荐
- 浅说prop与attr的区别
jquery中attr和prop的区别 在高版本的jquery引入prop方法后,什么时候该用prop?什么时候用attr?它们两个之间有什么区别?这些问题就出现了. 关于它们两个的区别,网上的答 ...
- dedecms自定义表单提交成功如何返回当前页面
在plus/diy.php找到showmsg($bkmsg, $goto);改成showmsg($bkmsg, -1);
- truncate 命令删除恢复
truncate命令可以一次性删除当前表中所有记录并且不留任何日志,同时这个表的ID就自动初化从1开始,今天我就来给大家尝试一个利用truncate清除记录之后恢复过程. 实际线上的场景比较复杂,当时 ...
- jquery元素查找方法集锦
jQuery常用的元素查找方法总结 $("#myELement") 选择id值等于myElement的元素,id值不能重复在文档中只能有一个id值是myElement所以得到 ...
- DEDECMS 关键字不能小于2个字节!
今天在做DEDECMS模板时,突然遇到了“关键字不能小于2个字节!”晕,是怎么回事呢?百度了一下,找到了答案,把他记录下来,方便自己日后再遇到这种问题时,可以查询: <form name=&qu ...
- bzoj2597: [Wc2007]剪刀石头布
Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道 ...
- protocol(协议) 和 delegate(委托)也叫(代理)---辨析
protocol和delegate完全不是一回事. 协议(protocol),(名词)要求.就是使用了这个协议后就要按照这个协议来办事,协议要求实现的方法就一定要实现. 委托(delegate),(动 ...
- Windows开发技术的历史
原文地址:http://www.kuqin.com/windows/20090315/40172.html Windows已经有22年的历史,这22年来,微软官方主力推行的编程语言与API有四个分水岭 ...
- BZOJ 1257 余数之和
Description 给出正整数\(n\)和\(k\),计算\(j(n, k)=k\;mod\;1\;+\;k\;mod\;2\;+\;k\;mod\;3\;+\;-\;+\;k\;mod\;n\) ...
- Inna and Binary Logic
Codeforces Round #234 (Div. 2) E:http://codeforces.com/problemset/problem/400/E 题意:给你n个数,然后每相邻的两个数可以 ...