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,到前天才开始做这个事情. 过程中也是碰到了 ...
随机推荐
- cos-26上传
在开发中常常需要上传文件,上传文件的方式有很多种,这里有一个cos实现的例子. 首先是要拷贝cos.jar包拷贝到WEB-INF/lib目录下,然后才进行编码. 创建一个可以进行自动重命名的Java文 ...
- UILongPressGestureRecognizer的selector多次调用解决方法
当你使用longPress gesture recognizer 时,你可能会发现调用了多次. UILongPressGestureRecognizer *longPress = [[UILongPr ...
- Extjs4 关于Store的一些操作(转)
1.关于加载和回调的问题 ExtJs的Store在加载时候一般是延迟加载的,这时候Grid就会先出现一片空白,等加载完成后才出现数据:因此,我们需要给它添加一个提示信息! 但是Store却没有wait ...
- 《find技巧》-“linux命令五分系列”之一
一天一个命令,做个记录, 我要成大神,哈哈哈 本原创文章属于<Linux大棚>博客. 博客地址为http://roclinux.cn. 文章作者为roc 希望您能通过捐款的方式支持Linu ...
- html的input输入框提示信息 点击隐藏
<input type="text" <!-- 文本框 --> name="textfield" value="请输入...& ...
- 简单学C——第一天
基本功 一.数据类型: 在C语言中,有数据类型这一说法.为何有这一说法?是因为在现实生活中存在着不同的数据,(例如整数,小数,字符即a b c d , . ; " 之类).由于计算机中所有 ...
- JavaScript的组成—ECMAScript、BOM和DOM
JavaScript 是一种基于 ECMAScript 规范的脚本语言,并在此基础上进行了自己的封装.ECMAScript 不是一种编程语言,仅仅是一种脚本语言规范,由欧洲计算机协会制定和发布,任 ...
- Bug in Code
Coder-Strike 2014 - Finals (online edition, Div. 1) C:http://codeforces.com/problemset/problem/420/C ...
- Yukari's Birthday
hdu4430:http://acm.hdu.edu.cn/showproblem.php?pid=4430 题意:题目的意思就是给你一个s,让你求k,r,其中k,r,满足:k^1+k^2+..... ...
- RH6030 单通道触摸感应开关
1.概述: RH6030 是一款单通道电容式触摸感应控制开关IC,可以替代传统的机械式开关. 该 IC 采用CMOS 工艺制造,结构简单,性能稳定.IC 可通过外部引脚配置成多种工作模式,可广泛应用于 ...