ImageVerifierCode 换一换
格式:DOCX , 页数:29 ,大小:30.48KB ,
资源ID:5987384      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5987384.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(USB解析.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

USB解析.docx

1、USB解析STM32官方USB例程详解一、USB的“JoyStickMouse”例程结构分析1、例程的结构(1)底层结构包 括5个文件:usb_core.c(USB总线数据处理的核心文件),usb_init.c,usb_int.c(用于端点数据输入输入中断处 理),usb_mem.c(用于缓冲区操作),usb_regs.c(用于寄存器操作)。它们都包含了头文件“usb_lib.h”。在这个头文件中,又 有以下定义:#include usb_type.h#include usb_regs.h#include usb_def.h#include usb_core.h#include usb_ini

2、t.h#include usb_mem.h#include usb_int.husb_lib.h中又包含了七个头文件,其中usb_type.h中主要是用typedef为stm32支持的数据类型取一些新的名称。usb_def.h中主要是定义一些相关的数据类型。还有一个未包含在usb_lib.h中的头文件,usb_conf.h用于USB设备的配置。(2)上层结构上 层结构总共5个文件:hw_config.c(用于USB硬件配置)、usb_pwr.c(用于USB连接、断开操作)、usb_istr.c(直接处理 USB中断)、usb_prop.c(用于上层协议处理,比如HID协议,大容量存储设备协议)

3、、usb_desc.c(具体设备的相关描述符定义和处 理)。可见,ST的USB操作库结构十分清晰明了,我先不准备直接阅读源代码。而是先利用MDK的软件模拟器仿真执行,先了解一下设备初始化的流程。2、设备初始化所做的工作(1)Set_System(void)这个是main函数中首先调用的函数,它位于hw_config.c文件中。它的主要功能是初始化时钟系统、使能相关的外围设备电源。配置了JoyStickMouse所用到的5个按键,并且配置了两个EXTI中断,一个是用于把USB从挂起模式唤醒,还有一个用途未知。(2)USB_Interrupts_Config();这个是main函数中调用的第二个函

4、数,它也位于hw_config.c文件中。主要功能是配置USB所用到的中断。跟踪到代码中,主要设配置了USB低优先级中断和唤醒中断,又有一个EXTI中断功能未知。(3)Set_USBClock()这个是main函数中调用的第三个函数,它也位于hw_config.c文件中。它的功能是配置和使能USB时钟。(4)USB_Init(void)这个是main函数中调用的第四个函数,它也位于usb_init.c文件中。它初始化了三个全局指针,指向DEVICE_INFO、USER_STANDARD_REQUESTS和DEVICE_PROP结构体。后面两个是函数指针结构体,里面都是USB请求实现、功能实现的

5、函数指针。void USB_Init(void)pInformation = &Device_Info;pInformation-ControlState = 2;pProperty = &Device_Property;pUser_Standard_Requests = &User_Standard_Requests;/* Initialize devices one by one */pProperty-Init();这三个结构体都是与具体设备枚举和功能实现相关的,定义在usb_prop.c和usb_desc.c文件中。DEVICE_PROP Device_Property =Joysti

6、ck_init,Joystick_Reset,Joystick_Status_In,Joystick_Status_Out,Joystick_Data_Setup,Joystick_NoData_Setup,Joystick_Get_Interface_Setting,Joystick_GetDeviceDescriptor,Joystick_GetConfigDescriptor,Joystick_GetStringDescriptor,0,0x40 /*MAX PACKET SIZE*/;USER_STANDARD_REQUESTS User_Standard_Requests =Joys

7、tick_GetConfiguration,Joystick_SetConfiguration,Joystick_GetInterface,Joystick_SetInterface,Joystick_GetStatus,Joystick_ClearFeature,Joystick_SetEndPointFeature,Joystick_SetDeviceFeature,Joystick_SetDeviceAddress;Usb_init()函数调用pProperty-Init()(实质上就是Joystick_init)完成设备的初始化。上层程序调用下次函数是常规性的操作。而下层函数(usb_

8、init相对于usb_prop是输入底层操作文件)调用上层文件函数我们称之为回调。回调函数的意义在于同一种操作模式、提供不同的回调函数则可以实现不同的功能。Windows中处理消息,好像也用到了这种模式。回调函数的实现方法是函数指针数组。这是指针的高级应用。这是函数的代码:void Joystick_init(void)/* Update the serial number string descriptor with the data from the uniqueID*/Get_SerialNum();/获取设备序列号,转变为unicode字符串pInformation-Current_C

9、onfiguration = 0;/* Connect the device */PowerOn();/连接USB设备,实质是能让主机检测到了。/* USB interrupts initialization */_SetISTR(0);/* clear pending interrupts */wInterrupt_Mask = IMR_MSK;_SetCNTR(wInterrupt_Mask); /* set interrupts mask */bDeviceState = UNCONNECTED;实质上,代码执行到这里,开发板已经可以响应主机发来的数据了。但我还是先把main()函数的代

10、码看完吧。(5)SysTick_Config();这个函数调用主要是为程序中用到的精确延时作配置。3、进入主循环进入主循环的工作就两个:Joystick_Send(JoyState()。JoyState()用来获取按键的状态。Joystick_Send(JoyState()用来把按键状态发到主机。当然这里真正的发送工作并不是由该代码完成的。它的工作只是将数据写入IN端点缓冲区,主机的IN令牌包来的时候,SIE负责把它返回给主机。主要代码如下:UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);/从用户复制四个字节到端点1缓冲区,控制

11、端点的输入缓冲区。SetEPTxValid(ENDP1); /* enable endpoint for transmission */4、中断处理过程大致理解(1)usb_istr()函数中的中断处理简单分析有用的代码大概以下几段,首先是处理复位的代码,调用设备结构中的复位处理函数。wIstr = _GetISTR();if (wIstr & ISTR_RESET & wInterrupt_Mask)_SetISTR(u16)CLR_RESET); /清复位中断Device_Property.Reset();处理唤醒的代码:if (wIstr & ISTR_WKUP & wInterrupt

12、_Mask)_SetISTR(u16)CLR_WKUP);Resume(RESUME_EXTERNAL);处理总线挂起的代码:if (wIstr & ISTR_SUSP & wInterrupt_Mask)if (fSuspendEnabled) /* check if SUSPEND is possible */Suspend();else/* if not possible then resume after xx ms */Resume(RESUME_LATER);/* clear of the ISTR bit must be done after setting of CNTR_FS

13、USP */_SetISTR(u16)CLR_SUSP);处理端点传输完成的代码,这段是最重要的,它调用底层usb_int.c()文件中的CTR_LP()函数来处理端点数据传输完成中断。if (wIstr & ISTR_CTR & wInterrupt_Mask)CTR_LP(); /* servicing of the endpoint correct transfer interrupt */二、STM32处理器的USB接口1、接口模块的内部结构在书上有一个很好的USB内部接口模块内部结构图,比较好的解释了各个模块之间的关系,我这里试着用我自己的理解阐述一下吧。首先在总线端(与D+、D-相

14、连的那一端),通过模拟收发器与SIE连接。SIE(串行接口控制器)使用48MHz的专用时钟。与SIE相关的的有三大块:CPU内部控制、中断和端点控制寄存器,挂起定时器(这个好像是USB协议的要求,总线在一定时间内没有活动,SIE模块能够进入SUSPEND状态以节约电能),还有包缓冲区接口模块。说到包缓冲区接口模块,这个对应的含义是,USB设备应该提供USB包缓冲区。这块缓冲区同时受到SIE和CPU核心的控制,用于CPU与SIE共享达到数据传输的目的。所以CPU通过APB1总线接口访问,SIE通过包缓冲区接口模块访问,中间通过Arbiter来协调访问。当然我们关注的中心点是控制、中断和端点控制寄

15、存器。我们通过这些寄存器来获取总线传输的状态,控制各个端点的状态,并可以产生中断来让CPU处理当前的USB事件。CPU可以通过APB1总线接口来访问这些寄存器。它们使用的都是PCLK1时钟。2、USB模块的寄存器认识(1)控制寄存器CNTR传输完成中断允许位。CTRM,1有效,如果SIE置位传输完成标志,则相应的数据传输完成中断发生。第15位包缓冲区溢出中断允许位错误中断允许位唤醒中断允许位。WKUPM。1有效,如果唤醒请求标志位置位,则产生唤醒中断。挂起中断允许位。SUSPM,1有效,当总线挂起标志置位时,发生挂起中断。复位中断允许位。RESETM。1有效,软件强制复位和总线复位信号,都能触

16、发复位中断。帧首中断允许位期望帧首中断允许位。ESOFM。它的含义是没有收到帧首信号,允许发生中断。第8位 向主机发送的唤醒请求,RESUME。1有效,主机收到该信号,将唤醒设备。这个由软件置位。第4位强制挂起控制,FSUSP。1有效。与由于总线无活动引起挂起的效果相同。低功耗模式。前提是先进入挂起状态。由软件设置,一般又硬件复位(被唤醒后自动清零)。断电模式控制位。PDWN。此位为1时,USB模块关闭。强制复位控制。FRES。与总线上的复位信号产生相同的效果。也能产生复位中断.第0位。(2)中断状态寄存器ISTR这个寄存器主要是反映USB模块当前的状态的。第15-8为与控制寄存器的中断允许是

17、意义对应的。相应的标志位置位,且中断未屏蔽,则向CPU发出对应的中断。CTR标志,数据传输完成后硬件置1.PMAOVR标志ERR标志WKUP请求,总线检测到主机唤醒请求时由硬件置位。SUSP请求标志位。RESET请求标志位。SOF帧首标志ESOF,期待帧首标志。 DIR传输方向,此位由硬件控制。IN时为0,OUT为1.第4位。发生数据传输的端点的地址。(3) USB设备地址寄存器第7位,EF,USB模块允许位。如果EF=0,则USB模块将停止工作。第6-0位。USB当前使用的地址。复位时为0.(4)端点状态和配置寄存器,8个寄存器,支持8个双向端点和16个单向端点。 CTR_RX,正确接收标志

18、位。第15位。DTOG_RX,用于检测的数据翻转位。一般由硬件自动设置,软件写1可使其手动翻转。STAT_RX,占据两位。00表示该端点不可用,无回应。01表示响应STALL10响应NAK11表示端点有效,可接收数据。SETUP标志。收到SETUP令牌包时置位。用户收到数据后需检查次位。第11位。EP_TYPE,两位,表示端点类型。00表示批量端点。01表示控制端点10表示等时端点。11表示中断端点。EP_KIND,端点特殊类型。在EP_TYPE=01时,表示设备期望主机的0字节状态包。CTR_TX。正确发送标志。主机的IN包之后。第7位。DTOG_TX,用于检测的数据翻转位。一般由硬件自动设

19、置,软件写1可使其手动翻转。STAT_TX,占据两位。00表示该端点不可用,无回应。01表示响应STALL10响应NAK11表示端点有效,可发送数据。端点地址:EA【3:0】,表明该寄存器对应的端点号码。比如1、2号寄存器都可以对应端点1(在双缓冲情况下)。第3-0位。 (5)端点描述符表相关寄存器首先有一个描述符表地址寄存器,指明了包缓冲区内端点描述符表的地址。每一个端点都对应一个描述附表。描述符表也在包缓冲区内。每个端点寄存器对应的描述符表的地址可根据公式计算。单缓冲、双向的端点描述符表有四项,每项占据两个字节:分别是端点n的发送缓冲区地址、发送字节数、接收缓冲区地址、接收字节数。了解US

20、B相关寄存器的知识以后,接下来就可以分析“JoyStickMouse”详细的工作过程了。三、USB的“JoyStickMouse”工作过程详细分析1、初始化过程叙述从main()函数开始(1)Set_System(void)的工作过程由于这些代码都是采用库代码,所以我主要分析每个代码具体做了什么工作。有些常用、类似的代码这里就不列出来了。先将RCC部分复位,系统使用内部振荡HSI,8MHzRCC_DeInit();。使能HSERCC_HSEConfig(RCC_HSE_ON);设置HCLK = SYSCLKRCC_HCLKConfig(RCC_SYSCLK_Div1);设置PCLK2,PCLK

21、1RCC_PCLK2Config(RCC_HCLK_Div1);设置PLL,使能PLLPLL采用HSE,输出=HSE X 9;RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);系统时钟采用PLL输出RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);使能PWR控制,目的是为了控制CPU的低功耗模式;将所有输入口初始化为模拟输入GPIO_AINConfig();使能USB上拉控制GPIO端口的时钟,这个端口设置为低电平时,USB外设会被集线器检测到,并报告给主机,这也是设备枚举的开始;将这个端口的模式设置为开漏

22、输出;初始化上下左右四个按键为上下拉输入;配置GPIOG8为EXTI8中断输入引脚,这个是在外部按键输入引起中断。配置EXTI18中断。这个是发生USB唤醒事件时用。EXTI_InitStructure.EXTI_Line = EXTI_Line18; / USB resume from suspend modeEXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);(2)USB_Interrupts

23、_Config(void)的工作过程设置向量表位置在FLASH起始位置NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x00);设置优先级分组,1位用于抢占组级别。其余用于子优先级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);接下来配置、使能了三个中断,包括USB低优先级中断、USB唤醒中断(EXTI18)、和EXTI8(按键控制)中断。它的优先级设置有些问题,明明只有一位用于抢占优先级。它把EXTI8的抢占优先级设为2。结果在调试时发现,它的抢占优先级仍然是0。(3)Set_USBClock()的工作过程这个代

24、码就两句话:RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);作用是设置并使能USB时钟,从RCC输出可以看到,USB时钟是48MHz。(4)USB_Init()的工作过程void USB_Init(void)pInformation = &Device_Info;pInformation-ControlState = 2;pProperty = &Device_Property;/这个是设备本身支持的属性和方法pUser_Standard_Req

25、uests = &User_Standard_Requests; /这个是主机请求的实现方法。pProperty-Init(); /回调设备的初始化例程。这个主要是初始化了三个全局结构体指针,pInformation表明当前连接的状态和信息,pProperty表明设备支持的方法,pUser_Standard_Requests是主机请求实现的函数指针数组。Device_Info是一个结构体,包括11个成员变量。这里是将它的ControlState设为2,意义现在还不十分明了。typedef struct _DEVICE_INFOu8 USBbmRequestType;/* bmRequestTy

26、pe */u8 USBbRequest;/* bRequest */u16_u8 USBwValues;/* wValue */u16_u8 USBwIndexs;/* wIndex */u16_u8 USBwLengths;/* wLength */u8 ControlState;/* of type CONTROL_STATE */u8 Current_Feature;u8 Current_Configuration;/* Selected configuration */u8 Current_Interface;/* Selected interface of current confi

27、guration */u8 Current_AlternateSetting;/* Selected Alternate Setting of currentinterface*/ENDPOINT_INFO Ctrl_Info;/端点信息结构体DEVICE_INFO;最后调用pProperty-Init(),实质就是调用Joystick_init(void)。在这个函数中,首先获取设备版本,并转换为Unicode存入版本号字符串。Get_SerialNum();设备当前配置置为0。然后调用PowerOn(),这个函数实质上将D+上拉,此时USB设备就能被集线器检测到了。因此分析进入下一个流程。

28、2、进入设备检测状态(1)在PowerOn()中执行的情况。在USB_init()中调用PowerOn(),而它先调用USB_Cable_Config(ENABLE),这个函数实质上将USB连接控制线设置为低电平,然后设备就可以检测到设备了。当集线器报告设备连接状态,并收到主机指令后,会复位USB总线,这需要一定的时间(这段时间内设备应该准备好处理复位指令)。但是现在设备初始化程序将继续往下进行,因为它还没有使能复位中断。wRegVal = CNTR_FRES;_SetCNTR(wRegVal);/这句话实际上使能了USB模块的电源,因为上电复位时,CNTR寄存器的断电控制为PDWN位是1,模

29、块是断电的。这句话虽然将强制复位USB模块,但由于复位中断允许位没有使能,不会引起复位中断,而间接上由使PDWN=0,模块开始工作。_SetCNTR是一个宏,将wRegVal赋值给CNTR寄存器,此时所有的中断被屏蔽。再接下来两句指令又将清除复位信号。然后清除所有的状态位。_SetISTR(0);接下来是很关键的两句话:wInterrupt_Mask=CNTR_RESETM| CNTR_SUSPM | CNTR_WKUPM;_SetCNTR(wInterrupt_Mask);后面一个语句执行后,复位中断已经被允许,而此时集线器多半已经开始复位端口了。或者说稍微有限延迟,设备固件还能继续初始化一

30、些部件,但已经不会影响整个工作流程了。所以接下来,分析直接进入复位中断。(2)复位中断的处理。当复位中断允许、且总线被集线器复位的时候,固件程序进入USB_LP中断。中断程序直接调用USB_Istr(void)程序。接下来讲对中断位进行判断:if (wIstr & ISTR_RESET & wInterrupt_Mask)_SetISTR(u16)CLR_RESET);/先清除复位中断位Device_Property.Reset();/进入设备定义的复位过程。实际上是调用JoyStick_Reset()函数进行处理。(3)JoyStick_Reset()函数的处理。这里将一句句来分析:void Joystick_Reset(void)pInformation-Current_Configuration = 0;/当前配置为0pInformation-Current_Interface = 0;/当前接口为0pInformation-Current_Feature = Joystick_ConfigDescriptor7;

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1