CH32-USB模拟HID设备分析

USB HID 设备是符合 USB HID 类规范的设备,它允许设备与计算机进行通信,实现人机交互功能,带有USB功能的CH32的EVT库里有模拟HID的dmeo,此例程与串口2交互实现USB与串口的透传功能。

鉴于很多USB初学者,此博客旨在通过详细的步骤,让客户快速上手此例程。

以V307的USBFS接口为例,USBD的与USBFS也是同理,USBHS的端点最大包长为512,而不同于USBD与USBFS的64字节。

一,重要外设参数初始化

 

/* Variables init */
    Var_Init();//USB与串口2交互缓冲区参数初始化

    /* UART2 init */
    UART2_Init();//串口2初始化
    UART2_DMA_Init();//串口2DMA初始化

    /* Usb Init */
    USBFS_RCC_Init();
    USBFS_Device_Init(ENABLE);
    NVIC_EnableIRQ(USBFS_IRQn);

    /* Timer init */
    TIM2_Init();//用作超时定时器
配置描述符里说明端点描述符与USB端点初始化一一对应,1为下传端点,2为上传端点。

 

 二,数据交互。

        if(USBFS_DevEnumStatus)//USBFS_DevEnumStatus USB枚举成功标志,不判断此位进行上传USB数据,可能会导致丢包或者异常。
        {
            UART2_Rx_Service();//串口接收的数据,通过USB端点2上传至USB主机。
            UART2_Tx_Service();//USB主机下发的HID数据通过串口2发送出来。
            HID_Set_Report_Deal();//此位HID类命令,通过端点0下发。
        }
1.先看ART2_Rx_Service();函数
这里只贴出USB上传部分
if (pkg_len)//如果串口2的DMA缓冲区有数据
            {
                USBFSD->UEP2_DMA = (uint16_t)(uint32_t)USBFS_EP2_Buf;//USB端点(上传)的DMA指向USBFS_EP2_Buf缓冲区
                USBFS_EP2_Buf[0] = pkg_len;//此次传输的串口接收的一包数据的总长度赋值给USB缓冲区的第一个元素。
                memcpy(USBFS_EP2_Buf + 1,&UART2_RxBuffer[UART2_Rx_Deal_Ptr],pkg_len);将剩下的数据赋值给剩下的buf。
                USBFSD->UEP2_TX_LEN = pkg_len + 1;
                USBFS_Endp_Busy[DEF_UEP2] = 1;//上传忙标志位,在USB上传完成中断中清零,需要上传的时候可以判断此标志为0再进行上传操作。
                USBFSD->UEP2_TX_CTRL = (USBFSD->UEP2_TX_CTRL & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK;            // Start Upload
                UART2_Rx_RemainLen -= pkg_len;//剩余数据
                UART2_Rx_Deal_Ptr += pkg_len;//处理数据

                if (UART2_Rx_Deal_Ptr >= DEF_UART2_BUF_SIZE)
                {
                    UART2_Rx_Deal_Ptr = 0x00;//处理数据清零结束
                }

            }

 此处理获取串口一包接收的数据,然后将这些数据拆成若干个慢64字节的数据包发出去(最后一包满64或不满64字节),此处理将第一个数据改成此包的数据长度,所有pkg_len 最大为63,占一个字节,若是数据满63字节,加上pkg_len 的本身的一个字节,则构成满包64字节。此点是透传的重要之点。处理的时候加上了本包的数据长度。

2.

 
这里必须要贴出端点1的接收中断,串口2发送的数据来自于此。
     case USBFS_UIS_TOKEN_OUT | DEF_UEP1:
                        if ( intst & USBFS_UIS_TOG_OK )
                        {
                            /* Write In Buffer */
                            USBFSD->UEP1_RX_CTRL ^= USBFS_UEP_R_TOG;
                            RingBuffer_Comm.PackLen[RingBuffer_Comm.LoadPtr] = USBFSD->RX_LEN;//此次接收的长度
                            RingBuffer_Comm.LoadPtr ++;//环形缓冲区加载包数
                            if(RingBuffer_Comm.LoadPtr == DEF_Ring_Buffer_Max_Blks)//满了归零
                            {
                                RingBuffer_Comm.LoadPtr = 0;
                            }
                            USBFSD->UEP1_DMA = (uint32_t)(&Data_Buffer[(RingBuffer_Comm.LoadPtr) * DEF_USBD_FS_PACK_SIZE]);//USB端点接收DMA根据接收包数在环形缓冲区里偏移。
                            RingBuffer_Comm.RemainPack ++;//环形缓冲区未处理包数自增
                            if(RingBuffer_Comm.RemainPack >= DEF_Ring_Buffer_Max_Blks-DEF_RING_BUFFER_REMINE)//当未处理包距离缓冲区最大包还有4包时,停止USB停止接收
                            {
                                USBFSD->UEP1_RX_CTRL = (USBFSD->UEP1_RX_CTRL & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK;
                                RingBuffer_Comm.StopFlag = 1;//置停止接收标志位。
                            }
                        }
UART2_Tx_Service();
 /* Pass-through USB-HID data to uart2 */
        if(RingBuffer_Comm.RemainPack)
        {
            pkg_len = Data_Buffer[(RingBuffer_Comm.DealPtr) * DEF_USBD_FS_PACK_SIZE];      // Get the valid data length
            if (pkg_len)
            {
                if (pkg_len > ( DEF_USBD_FS_PACK_SIZE - 1 ) )
                {
                    pkg_len = DEF_USBD_FS_PACK_SIZE - 1;                                   // Limit the length of this transmission
                }
                pbuf = &Data_Buffer[(RingBuffer_Comm.DealPtr) * DEF_USBD_FS_PACK_SIZE] + 1;//同理此处buf加一,将HID的调试助手发送的第一个数据不通过串口发送,第一个数据只代表帧头或者同步标志等等,用于程序判断,此处应注意。
                UART2_DMA_Tx( pbuf, pkg_len );
                UART2_Tx_Flag = 1;
            }
三,至此,透传数据流程大致走完。现在看具体实操。
1.打开bushound选择HID设备

 2.串口2接PA2接RX,PA3接TX。打开HIDTool,选择HID设备1A86的VID的,连接。工具下载地址

https://www.wch.cn/downloads/HIDAssist_ZIP.htm

串口发送63个字节,程序处理后将第一个数据改成0x3f等与63,后面的是数据。串口发送,HID工具与bushound显示如下

注:HID调试助手,需要一次接受满64字节才会显示,多了的也不显示,但是此时你可以用bushound观察。

 

 通过HIDtool工具下发数据如下

 当HIDtool发送不满64字节时,工具会自动补全。由此看到发送前面3个U,到串口这边只显示两个U,第一个U没有显示,由此第一个字节用户使用可以当作标志或同步位。

 

 

 

 

 

posted @ 2025-04-25 16:05  WCH_CH32  阅读(709)  评论(0)    收藏  举报