USB设备在端点4~7交互数据
在CH582的EVT包USB设备例程中,已有端点0~3的全部代码。端点4~7在手册中有描述,不过在例程中没有给出。
在端点0~7中,端点0与端点4与众不同。端点0只拥有64字节DMA缓存。这是符合USB协议标准的。作为USB设备都要默认支持的端点,USB协议要求设备的端点0是双向通信的;而其他端点是超级加倍,IN和OUT方向各有64字节的DMA缓存。
而端点4,其DMA地址是直接存放在64字节的端点0的DMA地址后的,配置了端点0的DMA地址后,就不必再次配置端点4的DMA。
原因未知,像是贴地砖时,用半块地砖填补到缝隙中,尽可能利用空间,不能浪费(把端点4的DMA区域塞到了端点0后面);后续建筑扩建,在新地方继续铺整块地砖(端点5~7都有独立的DMA缓存)。
不过这也带来一些麻烦,有更多的寄存器需要照顾。部分例程里已经配置好了,不必再关注端点4的配置。
以下是作为USB键鼠,在端点4、端点7中上传报表描述符的参考代码。
/********************************** (C) COPYRIGHT ******************************* * File Name : Main.c * Author : WCH * Version : V1.1 * Date : 2022/01/25 * Description : 模拟USB复合设备,键鼠,支持类命令 ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ #include "CH58x_common.h" uint8_t *pEP5_RAM_Addr; uint8_t *pEP6_RAM_Addr; uint8_t *pEP7_RAM_Addr; //XXX JW 增加端点配置 #define pEP5_OUT_DataBuf (pEP5_RAM_Addr) #define pEP5_IN_DataBuf (pEP5_RAM_Addr + 64) #define pEP6_OUT_DataBuf (pEP6_RAM_Addr) #define pEP6_IN_DataBuf (pEP6_RAM_Addr + 64) #define pEP7_OUT_DataBuf (pEP7_RAM_Addr) #define pEP7_IN_DataBuf (pEP7_RAM_Addr + 64) //XXX JW 增加端点配置 /*增加函数声明*/ void DevEP5_IN_Deal(uint8_t l); void DevEP6_IN_Deal(uint8_t l); void DevEP7_IN_Deal(uint8_t l); void DevEP5_OUT_Deal(uint8_t l); void DevEP6_OUT_Deal(uint8_t l); void DevEP7_OUT_Deal(uint8_t l); void DevEP5_OUT_Deal(uint8_t l) //XXX 增加端点OUT处理 { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP5_IN_DataBuf[i] = ~pEP5_OUT_DataBuf[i]; } DevEP5_IN_Deal(l); } void DevEP6_OUT_Deal(uint8_t l) //XXX 增加端点OUT处理 { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP6_IN_DataBuf[i] = ~pEP6_OUT_DataBuf[i]; } DevEP6_IN_Deal(l); } void DevEP7_OUT_Deal(uint8_t l) //XXX 增加端点OUT处理 { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP7_IN_DataBuf[i] = ~pEP7_OUT_DataBuf[i]; } DevEP7_IN_Deal(l); } void DevEP5_IN_Deal(uint8_t l) //XXX 增加端点IN处理 { R8_UEP5_T_LEN = l; R8_UEP5_CTRL = (R8_UEP5_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; } void DevEP6_IN_Deal(uint8_t l) //XXX 增加端点IN处理 { R8_UEP6_T_LEN = l; R8_UEP6_CTRL = (R8_UEP6_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; } void DevEP7_IN_Deal(uint8_t l) //XXX 增加端点IN处理 { R8_UEP7_T_LEN = l; R8_UEP7_CTRL = (R8_UEP7_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; } /*鼠标键盘数据*/ uint8_t HIDMouse[4] = {0x0, 0x0, 0x0, 0x0}; uint8_t HIDKey[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; /********************************************************************* * @fn DevHIDMouseReport * * @brief 上报鼠标数据 * * @return none */ void DevHIDMouseReport(uint8_t mouse) //XXX 改到端点7 { HIDMouse[0] = mouse; for(uint8_t i=0; i<4; i++) PRINT("%d ", HIDMouse[i]); PRINT("\n"); memcpy(pEP5_IN_DataBuf, HIDMouse, sizeof(HIDMouse)); DevEP5_IN_Deal(sizeof(HIDMouse)); memcpy(pEP7_IN_DataBuf, HIDMouse, sizeof(HIDMouse)); DevEP7_IN_Deal(sizeof(HIDMouse)); } /********************************************************************* * @fn DevHIDKeyReport * * @brief 上报键盘数据 * * @return none */ void DevHIDKeyReport(uint8_t key) //XXX 改到端点4 { HIDKey[2] = key; for(uint8_t i=0; i<8; i++) PRINT("%d ", HIDKey[i]); PRINT("\n"); memcpy(pEP4_IN_DataBuf, HIDKey, sizeof(HIDKey)); DevEP4_IN_Deal(sizeof(HIDKey)); } #define DevEP0SIZE 0x40 // 支持的最大接口数量 #define USB_INTERFACE_MAX_NUM 2 // 接口号的最大值 #define USB_INTERFACE_MAX_INDEX 1 // 设备描述符 const uint8_t MyDevDescr[] = {0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, DevEP0SIZE, 0x3d, 0x41, 0x07, 0x21, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01}; // 配置描述符 const uint8_t MyCfgDescr[] = { 0x09, 0x02, 0x3b, 0x00, 0x02, 0x01, 0x00, 0xA0, 0x32, //配置描述符 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x01, 0x00, //接口描述符,键盘 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3e, 0x00, //HID类描述符 0x07, 0x05, 0x84, 0x03, 0x08, 0x00, 0x0a, //端点描述符 //XXX JW 改到端点4 0x09, 0x04, 0x01, 0x00, 0x01, 0x03, 0x01, 0x02, 0x00, //接口描述符,鼠标 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x34, 0x00, //HID类描述符 0x07, 0x05, 0x87, 0x03, 0x04, 0x00, 0x0a //端点描述符 //XXX JW 改到端点7 }; /* USB速度匹配描述符 */ const uint8_t My_QueDescr[] = {0x0A, 0x06, 0x00, 0x02, 0xFF, 0x00, 0xFF, 0x40, 0x01, 0x00}; /* USB全速模式,其他速度配置描述符 */ uint8_t USB_FS_OSC_DESC[sizeof(MyCfgDescr)] = { 0x09, 0x07, /* 其他部分通过程序复制 */ }; // 语言描述符 const uint8_t MyLangDescr[] = {0x04, 0x03, 0x09, 0x04}; // 厂家信息 const uint8_t MyManuInfo[] = {0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0}; // 产品信息 const uint8_t MyProdInfo[] = {0x0C, 0x03, 'C', 0, 'H', 0, '5', 0, '8', 0, 'x', 0}; /*HID类报表描述符*/ const uint8_t KeyRepDesc[] = {0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x29, 0x91, 0x81, 0x00, 0xC0}; const uint8_t MouseRepDesc[] = {0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x03, 0x81, 0x02, 0x75, 0x05, 0x95, 0x01, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 0xC0, 0xC0}; /**********************************************************/ uint8_t DevConfig, Ready; uint8_t SetupReqCode; uint16_t SetupReqLen; const uint8_t *pDescr; uint8_t Report_Value[USB_INTERFACE_MAX_INDEX+1] = {0x00}; uint8_t Idle_Value[USB_INTERFACE_MAX_INDEX+1] = {0x00}; uint8_t USB_SleepStatus = 0x00; /* USB睡眠状态 */ /******** 用户自定义分配端点RAM ****************************************/ __attribute__((aligned(4))) uint8_t EP0_Databuf[64 + 64 + 64]; //ep0(64)+ep4_out(64)+ep4_in(64) __attribute__((aligned(4))) uint8_t EP1_Databuf[64 + 64]; //ep1_out(64)+ep1_in(64) __attribute__((aligned(4))) uint8_t EP2_Databuf[64 + 64]; //ep2_out(64)+ep2_in(64) __attribute__((aligned(4))) uint8_t EP3_Databuf[64 + 64]; //ep3_out(64)+ep3_in(64) __attribute__((aligned(4))) uint8_t EP5_Databuf[64 + 64]; __attribute__((aligned(4))) uint8_t EP6_Databuf[64 + 64]; __attribute__((aligned(4))) uint8_t EP7_Databuf[64 + 64]; //XXX 增加端点配置 /********************************************************************* * @fn USB_DevTransProcess * * @brief USB 传输处理函数 * * @return none */ void USB_DevTransProcess(void) { uint8_t len, chtype; uint8_t intflag, errflag = 0; intflag = R8_USB_INT_FG; if(intflag & RB_UIF_TRANSFER) { if((R8_USB_INT_ST & MASK_UIS_TOKEN) != MASK_UIS_TOKEN) // 非空闲 { switch(R8_USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP)) // 分析操作令牌和端点号 { case UIS_TOKEN_IN: { switch(SetupReqCode) { case USB_GET_DESCRIPTOR: len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen; // 本次传输长度 memcpy(pEP0_DataBuf, pDescr, len); /* 加载上传数据 */ SetupReqLen -= len; pDescr += len; R8_UEP0_T_LEN = len; R8_UEP0_CTRL ^= RB_UEP_T_TOG; // 翻转 break; case USB_SET_ADDRESS: R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | SetupReqLen; R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; break; case USB_SET_FEATURE: break; default: R8_UEP0_T_LEN = 0; // 状态阶段完成中断或者是强制上传0长度数据包结束控制传输 R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; break; } } break; case UIS_TOKEN_OUT: { len = R8_USB_RX_LEN; if(SetupReqCode == 0x09) { PRINT("[%s] Num Lock\t", (pEP0_DataBuf[0] & (1<<0)) ? "*" : " "); PRINT("[%s] Caps Lock\t", (pEP0_DataBuf[0] & (1<<1)) ? "*" : " "); PRINT("[%s] Scroll Lock\n", (pEP0_DataBuf[0] & (1<<2)) ? "*" : " "); } } break; case UIS_TOKEN_OUT | 1: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { // 不同步的数据包将丢弃 R8_UEP1_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP1_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 1: R8_UEP1_CTRL ^= RB_UEP_T_TOG; R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 2: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { // 不同步的数据包将丢弃 R8_UEP2_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP2_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 2: R8_UEP2_CTRL ^= RB_UEP_T_TOG; R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 3: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { // 不同步的数据包将丢弃 R8_UEP3_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP3_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 3: R8_UEP3_CTRL ^= RB_UEP_T_TOG; R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 4: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { R8_UEP4_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP4_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 4: R8_UEP4_CTRL ^= RB_UEP_T_TOG; R8_UEP4_CTRL = (R8_UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 5: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { // 不同步的数据包将丢弃 R8_UEP5_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP5_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 5: R8_UEP5_CTRL ^= RB_UEP_T_TOG; R8_UEP5_CTRL = (R8_UEP5_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; //XXX 增加端点 break; case UIS_TOKEN_OUT | 6: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { // 不同步的数据包将丢弃 R8_UEP6_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP6_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 6: R8_UEP6_CTRL ^= RB_UEP_T_TOG; R8_UEP6_CTRL = (R8_UEP6_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; //XXX 增加端点 break; case UIS_TOKEN_OUT | 7: { if(R8_USB_INT_ST & RB_UIS_TOG_OK) { // 不同步的数据包将丢弃 R8_UEP7_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP7_OUT_Deal(len); } } break; case UIS_TOKEN_IN | 7: R8_UEP7_CTRL ^= RB_UEP_T_TOG; R8_UEP7_CTRL = (R8_UEP7_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; //XXX 增加端点 break; default: break; } R8_USB_INT_FG = RB_UIF_TRANSFER; } if(R8_USB_INT_ST & RB_UIS_SETUP_ACT) // Setup包处理 { R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK; SetupReqLen = pSetupReqPak->wLength; SetupReqCode = pSetupReqPak->bRequest; chtype = pSetupReqPak->bRequestType; len = 0; errflag = 0; if((pSetupReqPak->bRequestType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD) { /* 非标准请求 */ /* 其它请求,如类请求,产商请求等 */ if(pSetupReqPak->bRequestType & 0x40) { /* 厂商请求 */ } else if(pSetupReqPak->bRequestType & 0x20) { switch(SetupReqCode) { case DEF_USB_SET_IDLE: /* 0x0A: SET_IDLE */ //主机想设置HID设备特定输入报表的空闲时间间隔 Idle_Value[pSetupReqPak->wIndex] = (uint8_t)(pSetupReqPak->wValue>>8); break; //这个一定要有 case DEF_USB_SET_REPORT: /* 0x09: SET_REPORT */ //主机想设置HID设备的报表描述符 break; case DEF_USB_SET_PROTOCOL: /* 0x0B: SET_PROTOCOL */ //主机想设置HID设备当前所使用的协议 Report_Value[pSetupReqPak->wIndex] = (uint8_t)(pSetupReqPak->wValue); break; case DEF_USB_GET_IDLE: /* 0x02: GET_IDLE */ //主机想读取HID设备特定输入报表的当前的空闲比率 EP0_Databuf[0] = Idle_Value[pSetupReqPak->wIndex]; len = 1; break; case DEF_USB_GET_PROTOCOL: /* 0x03: GET_PROTOCOL */ //主机想获得HID设备当前所使用的协议 EP0_Databuf[0] = Report_Value[pSetupReqPak->wIndex]; len = 1; break; default: errflag = 0xFF; } } } else /* 标准请求 */ { switch(SetupReqCode) { case USB_GET_DESCRIPTOR: { switch(((pSetupReqPak->wValue) >> 8)) { case USB_DESCR_TYP_DEVICE: { pDescr = MyDevDescr; len = MyDevDescr[0]; } break; case USB_DESCR_TYP_CONFIG: { pDescr = MyCfgDescr; len = MyCfgDescr[2]; } break; case USB_DESCR_TYP_HID: switch((pSetupReqPak->wIndex) & 0xff) { /* 选择接口 */ case 0: pDescr = (uint8_t *)(&MyCfgDescr[18]); len = 9; break; case 1: pDescr = (uint8_t *)(&MyCfgDescr[43]); len = 9; break; default: /* 不支持的字符串描述符 */ errflag = 0xff; break; } break; case USB_DESCR_TYP_REPORT: { if(((pSetupReqPak->wIndex) & 0xff) == 0) //接口0报表描述符 { pDescr = KeyRepDesc; //数据准备上传 len = sizeof(KeyRepDesc); } else if(((pSetupReqPak->wIndex) & 0xff) == 1) //接口1报表描述符 { pDescr = MouseRepDesc; //数据准备上传 len = sizeof(MouseRepDesc); Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效 } else len = 0xff; //本程序只有2个接口,这句话正常不可能执行 } break; case USB_DESCR_TYP_STRING: { switch((pSetupReqPak->wValue) & 0xff) { case 1: pDescr = MyManuInfo; len = MyManuInfo[0]; break; case 2: pDescr = MyProdInfo; len = MyProdInfo[0]; break; case 0: pDescr = MyLangDescr; len = MyLangDescr[0]; break; default: errflag = 0xFF; // 不支持的字符串描述符 break; } } break; case 0x06: pDescr = (uint8_t *)(&My_QueDescr[0]); len = sizeof(My_QueDescr); break; case 0x07: memcpy(&USB_FS_OSC_DESC[2], &MyCfgDescr[2], sizeof(MyCfgDescr) - 2); pDescr = (uint8_t *)(&USB_FS_OSC_DESC[0]); len = sizeof(USB_FS_OSC_DESC); break; default: errflag = 0xff; break; } if(SetupReqLen > len) SetupReqLen = len; //实际需上传总长度 len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen; memcpy(pEP0_DataBuf, pDescr, len); pDescr += len; } break; case USB_SET_ADDRESS: SetupReqLen = (pSetupReqPak->wValue) & 0xff; break; case USB_GET_CONFIGURATION: pEP0_DataBuf[0] = DevConfig; if(SetupReqLen > 1) SetupReqLen = 1; break; case USB_SET_CONFIGURATION: DevConfig = (pSetupReqPak->wValue) & 0xff; break; case USB_CLEAR_FEATURE: { if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) // 端点 { switch((pSetupReqPak->wIndex) & 0xff) { case 0x83: R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; break; case 0x03: R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; break; case 0x82: R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; break; case 0x02: R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; break; case 0x81: R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; break; case 0x01: R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; break; default: errflag = 0xFF; // 不支持的端点 break; } } else if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { if(pSetupReqPak->wValue == 1) { USB_SleepStatus &= ~0x01; } } else { errflag = 0xFF; } } break; case USB_SET_FEATURE: if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { /* 端点 */ switch(pSetupReqPak->wIndex) { case 0x83: R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_STALL; break; case 0x03: R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_STALL; break; case 0x82: R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_STALL; break; case 0x02: R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_STALL; break; case 0x81: R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_STALL; break; case 0x01: R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_STALL; break; default: /* 不支持的端点 */ errflag = 0xFF; // 不支持的端点 break; } } else if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { if(pSetupReqPak->wValue == 1) { /* 设置睡眠 */ USB_SleepStatus |= 0x01; } } else { errflag = 0xFF; } break; case USB_GET_INTERFACE: pEP0_DataBuf[0] = 0x00; if(SetupReqLen > 1) SetupReqLen = 1; break; case USB_SET_INTERFACE: break; case USB_GET_STATUS: if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { /* 端点 */ pEP0_DataBuf[0] = 0x00; switch(pSetupReqPak->wIndex) { case 0x83: if((R8_UEP3_CTRL & (RB_UEP_T_TOG | MASK_UEP_T_RES)) == UEP_T_RES_STALL) { pEP0_DataBuf[0] = 0x01; } break; case 0x03: if((R8_UEP3_CTRL & (RB_UEP_R_TOG | MASK_UEP_R_RES)) == UEP_R_RES_STALL) { pEP0_DataBuf[0] = 0x01; } break; case 0x82: if((R8_UEP2_CTRL & (RB_UEP_T_TOG | MASK_UEP_T_RES)) == UEP_T_RES_STALL) { pEP0_DataBuf[0] = 0x01; } break; case 0x02: if((R8_UEP2_CTRL & (RB_UEP_R_TOG | MASK_UEP_R_RES)) == UEP_R_RES_STALL) { pEP0_DataBuf[0] = 0x01; } break; case 0x81: if((R8_UEP1_CTRL & (RB_UEP_T_TOG | MASK_UEP_T_RES)) == UEP_T_RES_STALL) { pEP0_DataBuf[0] = 0x01; } break; case 0x01: if((R8_UEP1_CTRL & (RB_UEP_R_TOG | MASK_UEP_R_RES)) == UEP_R_RES_STALL) { pEP0_DataBuf[0] = 0x01; } break; } } else if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { pEP0_DataBuf[0] = 0x00; if(USB_SleepStatus) { pEP0_DataBuf[0] = 0x02; } else { pEP0_DataBuf[0] = 0x00; } } pEP0_DataBuf[1] = 0; if(SetupReqLen >= 2) { SetupReqLen = 2; } break; default: errflag = 0xff; break; } } if(errflag == 0xff) // 错误或不支持 { // SetupReqCode = 0xFF; R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL } else { if(chtype & 0x80) // 上传 { len = (SetupReqLen > DevEP0SIZE) ? DevEP0SIZE : SetupReqLen; SetupReqLen -= len; } else len = 0; // 下传 R8_UEP0_T_LEN = len; R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 默认数据包是DATA1 } R8_USB_INT_FG = RB_UIF_TRANSFER; } } else if(intflag & RB_UIF_BUS_RST) { R8_USB_DEV_AD = 0; R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_USB_INT_FG = RB_UIF_BUS_RST; } else if(intflag & RB_UIF_SUSPEND) { if(R8_USB_MIS_ST & RB_UMS_SUSPEND) { ; } // 挂起 else { ; } // 唤醒 R8_USB_INT_FG = RB_UIF_SUSPEND; } else { R8_USB_INT_FG = intflag; } } /********************************************************************* * @fn DevWakeup * * @brief 设备模式唤醒主机 * * @return none */ void DevWakeup(void) { R16_PIN_ANALOG_IE &= ~(RB_PIN_USB_DP_PU); R8_UDEV_CTRL |= RB_UD_LOW_SPEED; mDelaymS(2); R8_UDEV_CTRL &= ~RB_UD_LOW_SPEED; R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU; } /********************************************************************* * @fn DebugInit * * @brief 调试初始化 * * @return none */ void DebugInit(void) { GPIOA_SetBits(GPIO_Pin_9); GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); UART1_DefInit(); } /********************************************************************* * @fn main * * @brief 主函数 * * @return none */ int main() { SetSysClock(CLK_SOURCE_PLL_60MHz); DebugInit(); PRINT("start\n"); pEP0_RAM_Addr = EP0_Databuf; pEP1_RAM_Addr = EP1_Databuf; pEP2_RAM_Addr = EP2_Databuf; pEP3_RAM_Addr = EP3_Databuf; pEP5_RAM_Addr = EP5_Databuf; pEP6_RAM_Addr = EP6_Databuf; pEP7_RAM_Addr = EP7_Databuf; //XXX 增加配置 R8_UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | RB_UEP7_RX_EN | RB_UEP7_TX_EN; //XXX 增加配置 R16_UEP5_DMA = (uint16_t)(uint32_t)pEP1_RAM_Addr; R16_UEP6_DMA = (uint16_t)(uint32_t)pEP2_RAM_Addr; R16_UEP7_DMA = (uint16_t)(uint32_t)pEP3_RAM_Addr; //XXX 增加配置 R8_UEP5_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_UEP6_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_UEP7_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //XXX 增加配置 USB_DeviceInit(); PFIC_EnableIRQ(USB_IRQn); while(1) { mDelaymS(1000); // //鼠标左键 // DevHIDMouseReport(0x01); // mDelaymS(100); DevHIDMouseReport(0x00); mDelaymS(200); // // //键盘按键“wch” // mDelaymS(1000); // DevHIDKeyReport(0x1A); // mDelaymS(100); // DevHIDKeyReport(0x00); // mDelaymS(200); // DevHIDKeyReport(0x06); // mDelaymS(100); // DevHIDKeyReport(0x00); // mDelaymS(200); // DevHIDKeyReport(0x0B); mDelaymS(100); DevHIDKeyReport(0x00); } } /********************************************************************* * @fn DevEP1_OUT_Deal * * @brief 端点1数据处理 * * @return none */ void DevEP1_OUT_Deal(uint8_t l) { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP1_IN_DataBuf[i] = ~pEP1_OUT_DataBuf[i]; } DevEP1_IN_Deal(l); } /********************************************************************* * @fn DevEP2_OUT_Deal * * @brief 端点2数据处理 * * @return none */ void DevEP2_OUT_Deal(uint8_t l) { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP2_IN_DataBuf[i] = ~pEP2_OUT_DataBuf[i]; } DevEP2_IN_Deal(l); } /********************************************************************* * @fn DevEP3_OUT_Deal * * @brief 端点3数据处理 * * @return none */ void DevEP3_OUT_Deal(uint8_t l) { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP3_IN_DataBuf[i] = ~pEP3_OUT_DataBuf[i]; } DevEP3_IN_Deal(l); } /********************************************************************* * @fn DevEP4_OUT_Deal * * @brief 端点4数据处理 * * @return none */ void DevEP4_OUT_Deal(uint8_t l) { /* 用户可自定义 */ uint8_t i; for(i = 0; i < l; i++) { pEP4_IN_DataBuf[i] = ~pEP4_OUT_DataBuf[i]; } DevEP4_IN_Deal(l); } /********************************************************************* * @fn USB_IRQHandler * * @brief USB中断函数 * * @return none */ __INTERRUPT __HIGH_CODE void USB_IRQHandler(void) /* USB中断服务程序,使用寄存器组1 */ { USB_DevTransProcess(); }