ENDP2_RXADDR,50),作用是接收上位机数据到Receive_Buffer[50]中,上位机发送数据时datasize必须为50,无用的位可以写为0发送。
1.3 USB库应用接口层 1.3.1 usb_istr(.c)
Usb_istr.c提供了一个函数USB_istr()处理所有的USB宏单元中断。
函数void (*pEpInt_IN[7])(void)引用了所有EP*_IN(1-7)的回调函数,函数void
(*pEpInt_OUT[7])(void)引用了所有EP*_out(1-7)的回调函数,如果需要调用相应的回调函数,则应该在usb_config.h中将对应的函数无效声明注释掉如//#define EP2_OUT_Callback NOP_Process,再添加函数的具体内容。
注:在工程中,HID双向通信定义使用端点1发送数据,端点2接收数据,其中端点2接收数据需要用回调函数接收,所以在usb_config.h中将//#define EP2_OUT_Callback NOP_Process注释掉,并且在usb_istr.c中添加了EP2_OUT_Callback的定义: void EP2_OUT_Callback(void) {
PMAToUserBufferCopy(Receive_Buffer, ENDP2_RXADDR,50); SetEPRxStatus(ENDP2, EP_RX_VALID); Usb_ReceivePro(); }
函数的第一句作用是将端点2接收的数据存入大小为50bytes的Receive_Buffer中。 第二句作用是使能端点2的数据接收,第三句是引用自己定义的函数,这个函数用来处理接收到的数据。
1.3.2 usb_conf(.h)
Usb_conf.h定义了BTABLE和PMA中的所有端点地址
注:EP_NUM指需要用到的端点数量。 以下这一段宏定义定义了端点发送或接收缓冲区的大小,
都定义为了64bytes
#define BTABLE_ADDRESS (0x00) //这个是基地址 /* EP0 */
/* rx/tx buffer base address */
#define ENDP0_RXADDR (0x18) #define ENDP0_TXADDR (0x58)
/* EP1 */
/* tx buffer base address */
#define ENDP1_TXADDR (0x100) #define ENDP2_RXADDR (0x140)
下面这一段是回调函数的无效宏定义,相当于一个mask,需要相应的回调函数,则注释掉那一句。
#define EP1_IN_Callback NOP_Process
#define EP2_IN_Callback NOP_Process #define EP3_IN_Callback NOP_Process #define EP4_IN_Callback NOP_Process #define EP5_IN_Callback NOP_Process #define EP6_IN_Callback NOP_Process #define EP7_IN_Callback NOP_Process
#define EP1_OUT_Callback NOP_Process //#define EP2_OUT_Callback NOP_Process #define EP3_OUT_Callback NOP_Process #define EP4_OUT_Callback NOP_Process #define EP5_OUT_Callback NOP_Process #define EP6_OUT_Callback NOP_Process #define EP7_OUT_Callback NOP_Process
1.3.3 usb_prop(.c,.h)
Usb_prop模块实现了USB内核使用的Device_Table,Device_Property和USER_STANDARD_REQUEST结构。
A) Device_Table使用结构体DEVICE定义:
DEVICE Device_Table = {
EP_NUM, 1 }
可以知道Device_Table 的EP_NUM就是需要的端点数,它的宏定义在usb_conf.h中。Device_Table中成员1则代表设备只有一个配置
B) Device_Property使用结构体DEVICE_PROP定义:
DEVICE_PROP Device_Property = {
Joystick_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*/ }
下面解释几个主要关心的回调函数:
1、Joystick_init作用为初始化设备。
2、Joystick_Reset主要作用是对需要的端点进行设置,在工程中使用了endp0,endp1_in,endp2_out,所以必须对这三个端点进行设置。如下:
/* Initialize Endpoint 0 */
SetEPType(ENDP0, EP_CONTROL); SetEPTxStatus(ENDP0, EP_TX_STALL); SetEPRxAddr(ENDP0, ENDP0_RXADDR); SetEPTxAddr(ENDP0, ENDP0_TXADDR); Clear_Status_Out(ENDP0);
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); SetEPRxValid(ENDP0);
/* Initialize Endpoint 1 */
SetEPType(ENDP1, EP_INTERRUPT); SetEPTxAddr(ENDP1, ENDP1_TXADDR); SetEPTxCount(ENDP1, 14);
SetEPTxStatus(ENDP1, EP_TX_NAK); /* Initialize Endpoint 12*/
SetEPType(ENDP2, EP_INTERRUPT); SetEPRxAddr(ENDP2, ENDP2_RXADDR); SetEPRxCount(ENDP2, 50);
SetEPRxStatus(ENDP2, EP_RX_VALID);
endp0为用作控制,不用自己设置。
endp1用作中断输入(方向为设备到主机)端点,在endp1初始化语句中, setEPType(ENDP1, EP_INTERRUPT)设置端点1为中断方式, SetEPTxAddr(ENDP1, ENDP1_TXADDR)设置其输入地址, SetEPTxCount(ENDP1, 14)设置配置Tx 缓冲计数器,
SetEPTxStatus(ENDP1, EP_TX_NAK) 设置端点1发送不应答。
endp2 用作中断输出(方向主机到设备)端点,在endp2初始化语句中
SetEPType(ENDP2, EP_INTERRUPT)设置端点2为中断方式 SetEPRxAddr(ENDP2, ENDP2_RXADDR);设置输出地址 SetEPRxCount(ENDP2, 50);配置RX缓冲计数器 SetEPRxStatus(ENDP2, EP_RX_VALID);设置输入有效
注:配置TX缓冲计数器时注意它的值等于设备发送数据的最大宽度。同理对RX一样。 3、 Joystick_Data_Setup处理主机获取设备的特定描述符的请求,内核文件usb_core无法处
理该请求,因此需要用户分析请求,准备好数据,再传送个内核,特定描述符请求包括获取HID描述符,报告描述符等。
注:函数体RESULT Joystick_Data_Setup(uint8_t RequestNo)
{
uint8_t *(*CopyRoutine)(uint16_t);
CopyRoutine = NULL;
if ((RequestNo == GET_DESCRIPTOR)
&& (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) && (pInformation->USBwIndex0 == 0)) {
if (pInformation->USBwValue1 == REPORT_DESCRIPTOR) {
CopyRoutine = Joystick_GetReportDescriptor; }
else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE) {
CopyRoutine = Joystick_GetHIDDescriptor; }
} /* End of GET_DESCRIPTOR */
/*** GET_PROTOCOL ***/
else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) && RequestNo == GET_PROTOCOL) {
CopyRoutine = Joystick_GetProtocolValue; } if(ReportOffset>=6) ReportOffset=0; */
if (CopyRoutine == NULL) {
return USB_UNSUPPORT; }
pInformation->Ctrl_Info.CopyData = CopyRoutine; pInformation->Ctrl_Info.Usb_wOffset = 0; (*CopyRoutine)(0); return USB_SUCCESS;
}
函数中的判断语句说明
if ((RequestNo == GET_DESCRIPTOR) && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) && (pInformation->USBwIndex0 == 0)) 它的意思是判断主机发送的请求信息,如果是GET_DESCRIPTOR请求类型,并且是标准的USB请求,并且索引USBwIndex0为0,则执行后面的语句,在后面判断语句内部,再通过索引USBwIndex1确定是应该返回ReportDescriptor还是HIDDescriptor。
else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) && RequestNo == GET_PROTOCOL)
相关推荐: