本帖最后由 WoodData 于 2022-5-9 08:46 编辑
有幸中了一块极海的APM32E103开发板,初次接触极海的MCU。板子上主要是最小系统,IO全部引出,很简洁的板子。看到板子上有USB接口,就想试试USB外设做个设备。下载了开发板的资料和开发包,发现关于USB的例子只有一个USB鼠标。好好研究了一下这个例子。就准备试试改一下做成USB手柄设备。下面就是记录下做的手柄设备过程。
首先照着usb鼠标的例子修改一下,改改USB设备相关的描述符。
配置描述符,鼠标只用了一个输入端点,而手柄一般需要输入和输出各一个端点。描述符修改如下
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] Configuration descriptor
*/
const uint8_t g_hidMouseConfigDescriptor[HID_MOUSE_CONFIG_DESCRIPTOR_SIZE] =
{
/** bLength */
0x09,
/** bDescriptorType */
USB_DESC_CONFIGURATION,
/** wTotalLength */
HID_MOUSE_CONFIG_DESCRIPTOR_SIZE & 0XFF, HID_MOUSE_CONFIG_DESCRIPTOR_SIZE >> 8,
/** bNumInterfaces */
0X01,
/** bConfigurationValue */
0X01,
/** iConfiguration */
0X00,
/** bmAttributes */
0XE0,
/** MaxPower */
0X32,
/** bLength */
0X09,
/** bDescriptorType */
USB_DESC_INTERFACE,
/** bInterfaceNumber */
0X00,
/** bAlternateSetting */
0X00,
/** bNumEndpoints */
0X02,
/** bInterfaceClass */
0X03,
/** bInterfaceSubClass */
0X00,
/** nInterfaceProtocol */
0X00,
/** iInterface */
0X00,
/** bLength */
0X09,
/** bDescriptorType = HID */
0x21,
/** bcdHID */
0X00, 0X01,
/** bCountryCode */
0X00,
/** bNumDescriptors */
0X01,
/** bDescriptorType */
0X22,
/** wItemLength */
HID_MOUSE_REPORT_DESCRIPTOR_SIZE & 0XFF, HID_MOUSE_REPORT_DESCRIPTOR_SIZE >> 8,
//IN endpoint
/** bLength */
0X07,
/** bDescriptorType */
USB_DESC_ENDPOINT,
/** bEndpointAddress */
0X81,
/** bmAttributes */
0X03,
/** wMaxPacketSize */
0X40, 0X00,
/** bInterval */
0X10,
//OUT endpoint
/** bLength */
0X07,
/** bDescriptorType */
USB_DESC_ENDPOINT,
/** bEndpointAddress */
0X01,
/** bmAttributes */
0X03,
/** wMaxPacketSize */
0X40, 0X00,
/** bInterval */
0X10
};
然后就是手柄的报告描述符
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] HID report descriptor
*/
const uint8_t g_hidMouseReportDescriptor[HID_MOUSE_REPORT_DESCRIPTOR_SIZE] =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x33, // USAGE (RX)
0x09, 0x34, // USAGE (RY)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x09, 0x36, // USAGE (Silder)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x39, // USAGE (Hat switch)
0x15, 0x01, // LOGICAL_MINIMUM (1)
0x25, 0x08, // LOGICAL_MAXIMUM (8)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x42, // INPUT (Data,Var,Abs,Null)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x10, // REPORT_COUNT (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
};
下面是USB端点的初始化,这个初始化是在USB复位中处理的
void HidMouse_Reset(void)
{
uint8_t i;
s_usbConfigStatus = 0; //usb not config,disable send data
USBD_SetBufferTable(USB_BUFFER_TABLE_ADDR);
//endpoint 0 init
USBD_ResetEPKind(USBD_EP_0);
USBD_SetEPType(USBD_EP_0, USBD_EP_TYPE_CONTROL);
USBD_SetEPTxStatus(USBD_EP_0, USBD_EP_STATUS_STALL);
USBD_SetEPTxAddr(USBD_EP_0, USB_EP0_TX_ADDR);
USBD_SetEPRxStatus(USBD_EP_0, USBD_EP_STATUS_VALID);
USBD_SetEPRxAddr(USBD_EP_0, USB_EP0_RX_ADDR);
USBD_SetEPRxCnt(USBD_EP_0, USB_EP_PACKET_SIZE);
//endpoint 1 init
USBD_SetEPType(USBD_EP_1, USBD_EP_TYPE_INTERRUPT);
USBD_SetEPTxAddr(USBD_EP_1, USB_EP1_TX_ADDR);
USBD_SetEPTxCnt(USBD_EP_1, 0x8);
USBD_SetEPRxAddr(USBD_EP_1, USB_EP1_RX_ADDR);
USBD_SetEPRxCnt(USBD_EP_1, 0x4);
USBD_SetEPRxTxStatus(USBD_EP_1, USBD_EP_STATUS_NAK, USBD_EP_STATUS_VALID);
//endpoint addr
for(i = 0; i < USB_EP_NUM; i++)
{
USBD_SetEpAddr((USBD_EP_T)i, i);
}
USBD_SetDeviceAddr(0);
USBD_Enable();
}
USB的输出端点处理
void HidMouse_EPHandler(uint8_t ep, uint8_t dir)
{
if(dir == 0) //out endpoint
{
switch(ep)
{
case USBD_EP_0:
break;
case USBD_EP_1:
USBD_ReadDataFromEP(USBD_EP_1,s_usb_recv_buff,4);
USBD_SetEPRxStatus(USBD_EP_1, USBD_EP_STATUS_VALID); //recv data valid
//recv data process
if(s_usb_recv_buff[0]&0x01)
{
GPIO_ResetBits(GPIOE,GPIO_PIN_5);
}else
{
GPIO_SetBits(GPIOE,GPIO_PIN_5);
}
if(s_usb_recv_buff[1]&0x01)
{
GPIO_ResetBits(GPIOE,GPIO_PIN_6);
}else
{
GPIO_SetBits(GPIOE,GPIO_PIN_6);
}
break;
case USBD_EP_2:
break;
case USBD_EP_3:
break;
case USBD_EP_4:
break;
case USBD_EP_5:
break;
case USBD_EP_6:
break;
case USBD_EP_7:
break;
}
}else
{
//in endpoint
switch(ep)
{
case USBD_EP_0:
break;
case USBD_EP_1:
s_statusEP = 1; //endpoint1 can send data
break;
case USBD_EP_2:
break;
case USBD_EP_3:
break;
case USBD_EP_4:
break;
case USBD_EP_5:
break;
case USBD_EP_6:
break;
case USBD_EP_7:
break;
}
}
}
USB的输入报告处理
void HidMouse_Write(uint8_t key)
{
static int8_t x = 0;
static int8_t y = 0;
uint8_t buffer[8] = {0, 0, 0, 0};
switch (key)
{
case HID_MOUSE_KEY_LEFT:
x -= 10;
buffer[5] = 3;
buffer[6] = 0x01;
break;
case HID_MOUSE_KEY_RIGHT:
x += 10;
buffer[5] = 7;
buffer[6] = 0x02;
break;
case HID_MOUSE_KEY_UP:
y -= 10;
break;
case HID_MOUSE_KEY_DOWN:
y += 10;
break;
default:
return;
}
buffer[0] = x;
buffer[1] = y;
s_statusEP = 0; //send over flag
USBD_WriteDataToEP(USBD_EP_1, buffer, sizeof(buffer)); //write data to buffer
USBD_SetEPTxStatus(USBD_EP_1, USBD_EP_STATUS_VALID); //send data valid
}
主要修改以上内容,中间经过多次调试,最终成功枚举到USB手柄设备,并且输入输出数据正常。
下面是识别的USB手柄。用了 板上的2个按键模拟数据。
下面输出数据,调试可以看到接收数据。
在调试的过程中也发现了一些问题。
首先USB那个1.5k电阻上拉是跳线帽控制的,这个很不方便,每次还要手动拔插一下。
再就是用户手册文档USB那块发现一些明显错误,明显是从其他那抄来的,都不检查一下。开始看得奇奇怪怪的。
程序下面:
|