使用 CH567 制作一个USB 鼠标

目标:使用CH567 在 USB1 上实现微软Microsoft 5-Button Mouse with IntelliEye(TM) 鼠标。

为了更好的进行调试,首先将UART 设置为 1M的速率,这样做的好处是:调试信息能够更快的发送出来同时避免因为调试影响 USB 的时序。在 MYdebug.h 中修改如下:

#define STDIO_BAUD_RATE 1000000  //波特率为1000000BPS

使用时,将一个 USB 转串口Dongle的 RX接在CH567的PA5引脚上(UART3),共地之后使用 1 000 000波特率即可看到信息。

描述符如下:

1.Device Descriptor

Device Descriptor Microsoft 5-Button Mouse with IntelliEye(TM)

OffsetFieldSizeValueDescription
0bLength112h
1bDescriptorType101hDevice
2bcdUSB20110hUSB Spec 1.1
4bDeviceClass100hClass info in Ifc Descriptors
5bDeviceSubClass100h
6bDeviceProtocol100h
7bMaxPacketSize0108h8 bytes
8idVendor2045Eh
10idProduct20039h
12bcdDevice20300h3.00
14iManufacturer101h"Microsoft"
15iProduct103h"Microsoft 5-Button Mouse with IntelliEye(TM)"
16iSerialNumber100h
17bNumConfigurations101h

2.Configuration Descriptor

Configuration Descriptor 1 Bus Powered, 100 mA

OffsetFieldSizeValueDescription
0bLength109h
1bDescriptorType102hConfiguration
2wTotalLength20022h
4bNumInterfaces101h
5bConfigurationValue101h
6iConfiguration100h
7bmAttributes1A0hBus Powered, Remote Wakeup
4..0: Reserved...00000 
5: Remote Wakeup..1..... Yes
6: Self Powered.0...... No, Bus Powered
7: Reserved (set to one)
(bus-powered for 1.0)
1....... 
8bMaxPower132h100 mA

Interface Descriptor 0/0 HID, 1 Endpoint

OffsetFieldSizeValueDescription
0bLength109h
1bDescriptorType104hInterface
2bInterfaceNumber100h
3bAlternateSetting100h
4bNumEndpoints101h
5bInterfaceClass103hHID
6bInterfaceSubClass101hBoot Interface
7bInterfaceProtocol102hMouse
8iInterface100h

HID Descriptor

OffsetFieldSizeValueDescription
0bLength109h
1bDescriptorType121hHID
2bcdHID20110h1.10
4bCountryCode100h
5bNumDescriptors101h
6bDescriptorType122hReport
7wDescriptorLength20048h72 bytes

Endpoint Descriptor 81 1 In, Interrupt, 10 ms

OffsetFieldSizeValueDescription
0bLength107h
1bDescriptorType105hEndpoint
2bEndpointAddress181h1 In
3bmAttributes103hInterrupt
1..0: Transfer Type......11 Interrupt
7..2: Reserved000000.. 
4wMaxPacketSize20004h4 bytes
6bInterval10Ah10 ms

3.Language ID Descriptor

04 03 09 04

4.String Index 3

Microsoft 5-Button Mouse with IntelliEye(TM)

5. String Index 1

Microsoft

6.SET_CONFIGURATION

7.SET_IDLE 暂时未实现

8. GET_DESCRIPTOR REPORT_DESCRIPTOR 这里返回 HID Descriptor

Interface 0 HID Report Descriptor Mouse

Item Tag (Value)Raw Data
Usage Page (Generic Desktop)05 01 
Usage (Mouse)09 02 
Collection (Application)A1 01 
    Usage (Pointer)09 01 
    Collection (Physical)A1 00 
        Usage Page (Button)05 09 
        Usage Minimum (Button 1)19 01 
        Usage Maximum (Button 5)29 05 
        Logical Minimum (0)15 00 
        Logical Maximum (1)25 01 
        Report Size (1)75 01 
        Report Count (5)95 05 
        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)81 02 
        Report Size (3)75 03 
        Report Count (1)95 01 
        Input (Cnst,Ary,Abs)81 01 
        Usage Page (Generic Desktop)05 01 
        Usage (X)09 30 
        Usage (Y)09 31 
        Usage (Wheel)09 38 
        Logical Minimum (-127)15 81 
        Logical Maximum (127)25 7F 
        Report Size (8)75 08 
        Report Count (3)95 03 
        Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit)81 06 
    End CollectionC0 
    Usage Page05 FF 
    Usage09 02 
    Logical Minimum (0)15 00 
    Logical Maximum (1)25 01 
    Report Size (1)75 01 
    Report Count (1)95 01 
    Feature (Data,Var,Abs,NWrp,Lin,NPrf,NNul,NVol,Bit)B1 22 
    Report Size (7)75 07 
    Report Count (1)95 01 
    Feature (Cnst,Ary,Abs,NWrp,Lin,Pref,NNul,NVol,Bit)B1 01 
End CollectionC0 

代码是从USB1_DevCH372 修改而来的,其中的一些关于Endpoint 2 3 4 的代码并未去除。主要的修改如下:

1. void   USB1DeviceInit( void )  // 初始化USB设备 中,因为鼠标是低速设备,进行如下修改:

R8_USB1_CTRL   = UCST_LS | bUC_INT_BUSY |bUC_DMA_EN;  //设备模式,低速,

2. 用我们自己的描述符替换之前代码中的,在 case USB_GET_DESCRIPTOR: 中。因为我们是 HID设备,所以需要多一个 HID描述符,增加了处理的代码:

// GET_DESCRIPTOR REPORT_DESCRIPTOR
case USB_DESCR_TYP_REPORT:
         printf("REPORT_DESCRIPTOR Start\n");
         pDescr = (PUINT8)( &HidDescr[0] );
         len = sizeof( HidDescr );
		 printf("REPORT_DESCRIPTOR End\n");
         break;

上述完成之后,插入设备,Windows 就会认为有一个USB 鼠标插入系统。为了让鼠标有动作,还需要在Main 中添加如下代码。简单的说有如下2点:

  1. 我们使用 UsbConfig 作为鼠标配置完成的标志,只有 Windows 读取完各种必要的信息之后,进行的数据传输才是有效的;
  2. 鼠标的动作就是放在 Ep1Buffer的 512 字节中,然后给R8_UEP1_TX_CTRL1寄存器赋值即可进行发送;
int main()
{
	Interrupt_init( 1<<INT_ID_USB1 );     /* 系统总中断开启 */
	SysClkInit();           /* 初始化系统时钟 */
	mInitSTDIO_UR3();       /* 调试信息初始化 printf调用 */

	USB1DeviceInit();			/* USB1Device Init */
	printf("USB1 Device Init!\n");

	while(1) {
		if (UsbConfig!=0) {

            printf("Move mouse\n");
            Ep1Buffer[0+512]=0;
            Ep1Buffer[1+512]=0x20;
            Ep1Buffer[2+512]=0;
            Ep1Buffer[3+512]=0;
            R16_UEP1_T_LEN1=4;
            R8_UEP1_TX_CTRL1 = (R8_UEP1_TX_CTRL1 & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            mDelaymS(100);

            Ep1Buffer[0+512]=0;
            Ep1Buffer[1+512]=0;
            Ep1Buffer[2+512]=0x20;
            Ep1Buffer[3+512]=0;
            R16_UEP1_T_LEN1=4;
            R8_UEP1_TX_CTRL1 = (R8_UEP1_TX_CTRL1 & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            mDelaymS(100);

            Ep1Buffer[0+512]=0;
            Ep1Buffer[1+512]=0xE0;
            Ep1Buffer[2+512]=0;
            Ep1Buffer[3+512]=0;
            R16_UEP1_T_LEN1=4;
            R8_UEP1_TX_CTRL1 = (R8_UEP1_TX_CTRL1 & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            mDelaymS(100);

            Ep1Buffer[0+512]=0;
            Ep1Buffer[1+512]=0;
            Ep1Buffer[2+512]=0xE0;
            Ep1Buffer[3+512]=0;
            R16_UEP1_T_LEN1=4;
            R8_UEP1_TX_CTRL1 = (R8_UEP1_TX_CTRL1 & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            mDelaymS(100);

		}
		mDelaymS(5000);
	};

    return 0;
}

整体上并不复杂,但是因为缺少示例,个人感觉整体代码比较乱,如果未来对于功能进行扩展可能会遇到麻烦。

完整代码下载

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注