USB事务处理:
在 USB 协议中,USB 的数据传输由信息包组成,这些信息包组合
起来可以构成完整的事务处理。USB 事务处理是 USB 主机和 USB 功能
设备之间数据传输的基本单位。USB 的信息包和事务处理具有特定的
格式。
Packet buff的使用
每个双向EP对应两个packet buffer,分别
用于发送和接收软件通过packet buffer
• 软件通过packet buffer interface来访问它们
• 这些packet buffer的位置和大小都可配置,由buffer描述表指定
• Buffer描述表本身也在这块memory里,它自己的地址是由USB_BTABLE寄存器指定的
• USB外设硬件不会把本EP的数据溢出到与其相邻的其他packet
usb_prop.c中:CustomHID_Reset(void)中
端点(EP)的初始化
首次连接主机,主机会下发从机复位
端点(EP)资源:
有8个双向端点
• 双向EP0是必备的
• 其他EPi,应用可同时使用收、发两个方向或只使用一个方向
各device demo对EP的使用情况:
1. 应用中使用到的EP尽量内部编号考前(0~7),这样可以使得【硬件缓冲描述表】 尽可能小
2. 库函数默认把EPx的地址设置成x
SetDeviceAddress(Val) @ uint32_t nEP = Device_Table.Total_Endpoint; for (i = 0; i < nEP; i++) { _SetEPAddress((uint8_t)i, (uint8_t)i); } _SetDADDR(Val | DADDR_EF); 设置设备地址的同时使能USB模块 IN packet 的处理: OUT/SETUP packet的处理: Control transfer的处理 : 双缓冲端点: 结构体初始化: 分配了一个结构体(Device_Info)来记录收到的主机命令,以及设备当前状态;并用一个指针(plnformation)来指向它 //USB驱动将主机发送过来的USB设备的设置包保存在设备信息结构表中 typedef struct _DEVICE_INFO { u8 USBbmRequestType; /* bmRequestType */ 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 configuration */ u8 Current_AlternateSetting;/* Selected Alternate Setting of current interface*/ ENDPOINT_INFO Ctrl_Info; }DEVICE_INFO; typedef struct _ENDPOINT_INFO { /*当从设备发送数据时:copydata()可获取数据缓冲区的长度,如果长度为0,copydata()返回数据的总长度如果不支持请求,则返回0,如果返回-1,停止进行下一步,初始化,如果不是0,返回数据指针*/ u16 Usb_wLength;//待发送数据 u16 Usb_wOffset;//原始数据偏移量 u16 PacketSize; u8 *(*CopyData)(u16 Length); }ENDPOINT_INFO; 状态表示: typedef enum _CONTROL_STATE { WAIT_SETUP, /* 0 */ SETTING_UP, /* 1 */ IN_DATA, /* 2 */ OUT_DATA, /* 3 */ LAST_IN_DATA, /* 4 */ LAST_OUT_DATA, /* 5 */ WAIT_STATUS_IN, /* 7 */ WAIT_STATUS_OUT, /* 8 */ STALLED, /* 9 */ PAUSE /* 10 */ } CONTROL_STATE; /* The state machine states of a control pipe */ //USB驱动将主机发送过来的USB设备的设置包保存在设备信息结构表中 typedef struct _DEVICE_INFO { u8 USBbmRequestType; /* bmRequestType */ 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 configuration */ u8 Current_AlternateSetting;/* Selected Alternate Setting of current interface*/ ENDPOINT_INFO Ctrl_Info; }DEVICE_INFO; 处理主机的setup: *处理主机的setup请求 80 06 00 01 00 00 40 00 *******************************************************************************/ u8 Setup0_Process(void) { union { u8* b; u16* w; } pBuf; //取的端点0的接收缓冲区地址 pBuf.b = PMAAddr + (u8 *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */ if (pInformation->ControlState != PAUSE) { pInformation->USBbmRequestType = *pBuf.b++; /* 请求类型,标明方向和接收对象(设备、接口还是端点),80:设备到主机 */ pInformation->USBbRequest = *pBuf.b++; /* 请求代码:首次为6:标明主机要获取设备描述符 */ pBuf.w++; /* word not accessed because of 32 bits addressing */ pInformation->USBwValue = ByteSwap(*pBuf.w++); /* 标明是啥请求 */ pBuf.w++; /* word not accessed because of 32 bits addressing */ pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* 用来说明端点号或 */ pBuf.w++; /* word not accessed because of 32 bits addressing */ pInformation->USBwLength = *pBuf.w; /* 该请求应答的长度 */ } pInformation->ControlState = SETTING_UP; if (pInformation->USBwLength == 0) { /* 第2阶段: */ NoData_Setup0(); } else { /* 第1阶段,交互设备描述符。交互完,主机复位USB,进入第2阶段*/ Data_Setup0(); } return Post0_Process(); } //完成描述符的输出准备 void DataStageIn(void) { ... DataBuffer = (*pEPinfo->CopyData)(Length);//用户描述符缓冲区地址,18字节 UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);//将描述符复制到发送缓冲区 SetEPTxCount(ENDP0, Length);//设置发送长度 pEPinfo->Usb_wLength -= Length; pEPinfo->Usb_wOffset += Length; vSetEPTxStatus(EP_TX_VALID);//使能端点发送,主要主机的令牌包一来,就启动发送 USB_StatusOut();/* USB接收有效 */ Expect_Status_Out: pInformation->ControlState = ControlState;//进入第2阶段 } DataStageOut 结构体初始化二 分配了一个结构体(Device_Property)来定义该设备的各个回掉函数; 并用一个指针(pProperty)来指向它 DEVICE_PROP Device_Property = { CustomHID_init, CustomHID_Reset, CustomHID_Status_In, CustomHID_Status_Out, CustomHID_Data_Setup, CustomHID_NoData_Setup, CustomHID_Get_Interface_Setting, CustomHID_GetDeviceDescriptor, CustomHID_GetConfigDescriptor, CustomHID_GetStringDescriptor, 0, 0x40 /*MAX PACKET SIZE*/ }; 结构体定义如下: void (*Init)(void); /* Initialize the device */ void (*Reset)(void); /* Reset routine of this device */ /* Device dependent process after the status stage */ void (*Process_Status_IN)(void); void (*Process_Status_OUT)(void); RESULT (*Class_Data_Setup)(u8 RequestNo); RESULT (*Class_NoData_Setup)(u8 RequestNo); RESULT (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting); u8* (*GetDeviceDescriptor)(u16 Length); u8* (*GetConfigDescriptor)(u16 Length); u8* (*GetStringDescriptor)(u16 Length); u8* RxEP_buffer; u8 MaxPacketSize; 结构体初始化三、 User_Standard_Requests 分配了一个结构体(User_Standard_Requests)来定义该设备用来响应主机标准命令时的各种回调函数; 并用一个指针(pUser_Standard_Requests) 来指向它 初始化: void USB_Init(void) 看一下设备本身的属性和方法: 看一下初始化的过程: pProperty->Init(); • 获取序列号 根据该芯片的Unique ID来更新“序号字符串”(MASS_StringSerial[26]) • 连接设备: PowerOn() • 拉低PB14来使能USB_D+线上的上拉电阻 • 置位并复位FRES@USB_CNTR来对USB外设进行复位 • 复位ISTR所有位来清除可能pending的中断 • 设置本应用关心的中断事件: RESET、 SUSP、 WKUP 整个USB通信是由中断驱动的 不同应用关心不同的中断事件: 首先分析下RESET中断: 首次连接主机,主机会下发从机复位 1、 CustomHID_Reset • 初始化EP • EP0:控制类型;发送NAK、接收Valid;设置接收buffer地址和长度;设置发送buffer地址 • EP1:批量类型;发送NAK、接收Disable;设置发送buffer地址 • EP2:批量类型;发送Disable、接收VALID;设置接收buffer地址和长度 设置状态标志: 2、CTR中断 • 硬件置位表示一个transaction正确完成了 • 软件需要根据EP_ID和DIR来得知这次transaction是发生在哪个EP上的何种 transaction(SETUP/OUT/IN transaction?) void CTR_LP(void) 1、extract highest priority endpoint number (wIstr = _GetISTR()); EPindex = (u8)(wIstr & ISTR_EP_ID); 端口号为0时: /* save RX & TX status */ /* and set both to NAK */ 参看传输方向 if((wIstr&ISTR_DIR)==0)//方向为IN,主机发送完成 { //首先清除CTR_TX _ClearEP_CTR_TX(ENDP0); In0_Process(); //恢复EP0的RX和TX的状态 _SetEPRxStatus(ENDP0, SaveRState); _SetEPTxStatus(ENDP0, SaveTState); } else//接收,分为setup接收和数据接收 { 。。。 } Setup0_Process() 第一步:从EP0的接收Packet buf中读取主机命令 pInformation->ControlState = SETTING_UP; 第二步: 交互设备描述符: //函数指针参数为16位参数,返回值是指向8位变量的指针 u8 *(*CopyRoutine)(u16); 【作用和意义】 通过这个函数获得用户的数据缓冲区地址,从而可以在OUT过程中把收到的数据拷贝到用户缓冲区,或在IN过程中把用户缓冲区的数据拷贝到USB发送缓冲区 OUT过程,多个DATA_OUT传输,库需要多次调用回调函数CopyRoutine,返回将要容纳已经收在硬件buf中数据的缓 冲区指针 IN过程,多个DATA_IN传输, 每次需要向主机传输数据时, USB库都会调用一次回调函数CopyRoutine,它返回一 个包含要发送的数据的缓冲区指针,库再把这个缓冲区的内容拷贝的硬件buf以择机发送出去 In0_Process(void) 完成描述符的输出准备: DataStageln(void) ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; ENDPOINT_INFO pInformation Out0_Process() UserToMABufferCopy
上一篇:STM32 USB 枚举分析
下一篇:stm32f407系列单片机usb高速模式下的速度测试
推荐阅读最新更新时间:2024-11-12 17:18
设计资源 培训 开发板 精华推荐
- 使用 NXP Semiconductors 的 MSCMMX6QZDK08AB 的参考设计
- TCR4S33DWBG、200mA、3.3V输出电压CMOS低压降稳压器的典型应用
- 数字电路制作07-三人表决器
- AM6TW-4824DZ ±24V 6 瓦双路输出 DC-DC 转换器的典型应用
- TWR-KV10Z32: Kinetis® KV1x系列塔式系统模块
- 使用 NXP Semiconductors 的 XC68HC705X4 的参考设计
- ESPlay Micro S3版
- EVAL-AD7660CB,AD7660 评估板,16 位,100 Ksps PulSAR 模数转换器
- LTC3417AIFE-2 的典型应用电路,1.8V at 1.5A/2.5V at 1A 降压稳压器
- AM3GH-1212SZ 12V DC/DC转换器的典型应用