使用USB HID主要是为了免驱,通过自定义USB HID可以利用USB口来做很多事,比如串口打印,串口升级都可以通过usb口来实现,这样可以省去一个USB转串口器件同时也不用装驱动,如下实现可以通过usb hid进行自定义收发,类似串口自定义收发。
如下代码基本都是基于沁恒EVT改造而来,
GitHub - iot-lorawan/ch58x_usbhid_custom: custom usb hid in ch58x
usb配置相关,该配置声明了使用usb 自定义hid,
#include "CH58x_common.h"
#define RepDataLoadLen 64
#define DevEP0SIZE 0x40
// 设备描述符
/* Device Descriptor */
const UINT8 MyDevDescr[] =
{
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, DevEP0SIZE,
0x86, 0x1A, 0xE1, 0xE6,
0x00, 0x01, 0x01, 0x02, 0x00, 0x01,
};
/* USB配置描述符(全速) */
UINT8 MyCfgDescr[ ] =
{
0x09,0x02,0x29,0x00,0x01,0x01,0x04,0xA0,0x23, //配置描述符
0x09,0x04,0x00,0x00,0x02,0x03,0x00,0x00,0x05, //接口描述符
0x09,0x21,0x00,0x01,0x00,0x01,0x22,0x22,0x00, //HID类描述符
0x07,0x05,0x81,0x03,0x40,0x00,0x01, //端点描述符(全速间隔时间改成1ms)
0x07,0x05,0x01,0x03,0x40,0x00,0x01, //端点描述符
};
/* USB报告描述符 */
const UINT8 CompatibilityHIDRepDesc[ ] =
{
0x06, 0x00,0xff,
0x09, 0x01,
0xa1, 0x01, //集合开始
0x09, 0x02, //Usage Page 用法
0x15, 0x00, //Logical Minimun
0x26, 0x00,0xff, //Logical Maximun
0x75, 0x08, //Report Size
0x95, RepDataLoadLen, //Report Counet
0x81, 0x06, //Input
0x09, 0x02, //Usage Page 用法
0x15, 0x00, //Logical Minimun
0x26, 0x00,0xff, //Logical Maximun
0x75, 0x08, //Report Size
0x95, RepDataLoadLen, //Report Counet
0x91, 0x06, //Output
0xC0
};
/* Language Descriptor */
const UINT8 MyLangDescr[] =
{
0x04, 0x03, 0x09, 0x04
};
/* Manufactor Descriptor */
const UINT8 MyManuInfo[] =
{
0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0
};
/* Product Information */
const UINT8 MyProdInfo[] =
{
0x0C, 0x03, 'C', 0, 'H', 0, '1', 0, '0', 0, 'x', 0
};
/* USB序列号字符串描述符 */
const UINT8 MySerNumInfo[ ] =
{
/* 0123456789 */
22,03,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,57,0
};
/* USB设备限定描述符 */
const UINT8 MyUSBQUADesc[ ] =
{
0x0A, 0x06, 0x00, 0x02, 0xFF, 0x00, 0xFF, 0x40, 0x01, 0x00,
};
/**********************************************************/
uint8_t DevConfig, Ready;
uint8_t SetupReqCode;
uint16_t SetupReqLen;
const uint8_t *pDescr;
uint8_t Report_Value = 0x00;
uint8_t Idle_Value = 0x00;
uint8_t USB_SleepStatus = 0x00; /* USB睡眠状态 */
/*鼠标键盘数据*/
uint8_t HIDMouse[4] = {0x0, 0x0, 0x0, 0x0};
uint8_t HIDKey[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
/******** 用户自定义分配端点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)
USB逻辑交互,放在usb中断函数里执行
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)
{
if(pEP0_DataBuf[0])
PRINT("Light on Num Lock LED!\n");
else if(pEP0_DataBuf[0] == 0)
PRINT("Light off Num Lock LED!\n");
}
}
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;
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 */
Idle_Value = EP0_Databuf[3];
break; //这个一定要有
case DEF_USB_SET_REPORT: /* 0x09: SET_REPORT */
break;
case DEF_USB_SET_PROTOCOL: /* 0x0B: SET_PROTOCOL */
Report_Value = EP0_Databuf[2];
break;
case DEF_USB_GET_IDLE: /* 0x02: GET_IDLE */
EP0_Databuf[0] = Idle_Value;
len = 1;
break;
case DEF_USB_GET_PROTOCOL: /* 0x03: GET_PROTOCOL */
EP0_Databuf[0] = Report_Value;
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 = sizeof( MyCfgDescr );
break;
case USB_DESCR_TYP_STRING:
/* 获取字符串描述符 */
switch( (pSetupReqPak->wValue)&0xff )
{
case 0:
/* 语言字符串描述符 */
pDescr = MyLangDescr;
len = MyLangDescr[0];
break;
case 1:
/* USB产商字符串描述符 */
pDescr = MyManuInfo;
len = MyManuInfo[0];
break;
case 2:
/* USB产品字符串描述符 */
pDescr = MyProdInfo;
len = MyProdInfo[0];
break;
case 3:
/* USB序列号字符串描述符 */
pDescr = MySerNumInfo;
len = sizeof( MySerNumInfo );
break;
default:
errflag = 0xFF;
break;
}
break;
case USB_DESCR_TYP_REPORT:
/* USB设备报告描述符 */
pDescr = CompatibilityHIDRepDesc;
len = sizeof( CompatibilityHIDRepDesc );
break;
case USB_DESCR_TYP_QUALIF:
/* 设备限定描述符 */
pDescr = ( PUINT8 )&MyUSBQUADesc[ 0 ];
len = sizeof( MyUSBQUADesc );
break;
case USB_DESCR_TYP_SPEED:
/* 其他速度配置描述符 */
errflag = 0xFF;
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;
}
}
__INTERRUPT
__HIGH_CODE
void USB_IRQHandler(void) /* USB中断服务程序,使用寄存器组1 */
{
USB_DevTransProcess();
}
USB端点收发部分接口,IN OUT都是从host端即电脑端而言
/*********************************************************************
* @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);
PRINT("DevEP1_OUT_Deal:%d\r\n",l);
}
/*********************************************************************
* @fn DevEP2_OUT_Deal
*
* @brief 端点2数据处理
*
* @return none
*/
void DevEP2_OUT_Deal(uint8_t l)
{ /* 用户可自定义 */
uint8_t i;
PRINT("DevEP2_OUT_Deal:%d\r\n",l);
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;
PRINT("DevEP3_OUT_Deal:%d\r\n",l);
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;
PRINT("DevEP4_OUT_Deal:%d\r\n",l);
for(i = 0; i < l; i++)
{
pEP4_IN_DataBuf[i] = pEP4_OUT_DataBuf[i];
}
DevEP4_IN_Deal(l);
}
主函数:
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;
USB_DeviceInit();
PFIC_EnableIRQ(USB_IRQn);
while(1)
{
mDelaymS(100);
#if 0
uint8_t i;
for(i = 0; i < 64; i++)
{
pEP1_IN_DataBuf[i] = 0x30+i;
}
DevEP1_IN_Deal(64);
#endif
}
}
使用usb hid收发助手调试