[应用相关] STM32-custom usb

[复制链接]
2402|44
 楼主| 欢乐家园 发表于 2021-2-22 21:41 | 显示全部楼层 |阅读模式
如何建立一个自定义的HID工程呢?下面就来讲讲。
首先先介绍下工程的架构,工程的总体架构下图所示,按照下图架构建工程:
STM32 CustomHID 的实现 - ziye334 - ziye334的博客
 楼主| 欢乐家园 发表于 2021-2-22 21:52 | 显示全部楼层
分析下工程布局,首先是APP,这个组里存放着主文件mian.c,管理所有中断服务程序stm3210x_it.c,及其管理外设库头文件的stm32f10x_conf.h。BSP这个组里存放着BSP.c,外设的洗衣初始化都在这个函数中定义,比如说串口的配置,LED灯的配置,系统时钟的配置,各类NVIC的中断配置。在这个文件中,会定义一个BSP_Init()函数,所有配置的都在这个函数中调用,例如:
 楼主| 欢乐家园 发表于 2021-2-22 21:54 | 显示全部楼层
  1. void BSP_Init(void)
  2. {
  3. RCC_Configuration();
  4. Set_USBClock();
  5. USB_Init();
  6. USART1_Configuration(115200);
  7. LED_Configuration();
  8. NVIC_Configuration();
  9. USB_Interrupts_Config();   
  10. }

 楼主| 欢乐家园 发表于 2021-2-22 21:57 | 显示全部楼层
而这个BSP_Init()函数在main中调用,这样就使主函数简洁漂亮了。至于CMSIS这个组则是关于Cotex-M3内核的相关文件看,如core_cm3.c和system_stm32f10x.c。StartUp这个组放置系统的启动文件,不同系类的处理器使用不同的启动文件,这里有必要了解:
 楼主| 欢乐家园 发表于 2021-2-22 21:59 | 显示全部楼层
  1. - startup_stm32f10x_ld_vl.s: for STM32 Low density Value line devices
  2. - startup_stm32f10x_ld.s: for STM32 Low density devices
  3. - startup_stm32f10x_md_vl.s: for STM32 Medium density Value line devices
  4. - startup_stm32f10x_md.s: for STM32 Medium density devices
  5. - startup_stm32f10x_hd.s: for STM32 High density devices
  6. - startup_stm32f10x_xl.s: for STM32 XL density devices
  7. - startup_stm32f10x_cl.s: for STM32 Connectivity line devices

  8. cl:互联型产品,stm32f105/107系列
  9. vl:超值型产品,stm32f100系列
  10. xl:超高密度产品,stm32f101/103系列
  11. ld:低密度产品,FLASH小于64K
  12. md:中等密度产品,FLASH=64 or 128
  13. hd:高密度产品,FLASH大于128
 楼主| 欢乐家园 发表于 2021-2-22 22:01 | 显示全部楼层
我的这个工程选择高密度型的: startup_stm32f10x_hd.s。USB_User文件组放着USB控制与应用相关的文件,在之前的**每个文件都详细介绍过。接着是USB-FS-Device_Driver这个组放着USB的驱动,在之前的**页已经讲述过。最后一个组是STM32F10x_StdPeriph_Driver,它里面存放着外设库文件的驱动代码,很多人为了省事,会把所有的C文件都添加进来,我不建议这么做,还是根据需要添加对应的文件,就拿我们的这个CustomHID工程,我们用到了引脚GPIO、时钟的配置,串口的配置,所以只要添加这几个对应的C库文件就可以了。
 楼主| 欢乐家园 发表于 2021-2-22 22:03 | 显示全部楼层
上面的各个文件大部分可以网上下载的。
 楼主| 欢乐家园 发表于 2021-2-22 22:05 | 显示全部楼层
接下去就讲述如何实现CustomHID功能的。
首先,最重要的文件当然是usb_desc.c这个文件了。这个文件存放着各种描述符,比如说设备描述符、配置描述符等,下面就一一介绍。
设备描述符符的定义如下:
 楼主| 欢乐家园 发表于 2021-2-22 22:06 | 显示全部楼层
  1. /* USB标准设备描述符*/
  2. const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] =
  3. {
  4.     0x12,                       /*bLength:长度,设备描述符的长度为18字节*/
  5.     USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType:类型,设备描述符的编号是0x01*/
  6.     0x00,                       /*bcdUSB:所使用的USB版本为2.0*/
  7.     0x02,
  8.     0x00,                       /*bDeviceClass:设备所使用的类代码*/
  9.     0x00,                       /*bDeviceSubClass:设备所使用的子类代码*/
  10.     0x00,                       /*bDeviceProtocol:设备所使用的协议*/
  11.     0x40,                       /*bMaxPacketSize:最大包长度为64字节*/
  12.     0x34,                       /*idVendor:厂商ID为0x1234*/
  13.     0x12,
  14.     0x10,                       /*idProduct:产品ID为0x1010*/
  15.     0x10,
  16.     0x00,                       /*bcdDevice:设备的版本号为2.00*/
  17.     0x02,
  18.     1,                          /*iManufacturer:厂商字符串的索引*/
  19.     2,                          /*iProduct:产品字符串的索引*/
  20.     3,                          /*iSerialNumber:设备的序列号字符串索引*/
  21.     0x01                        /*bNumConfiguration:设备有1种配置*/
  22. }; /* CustomHID设备描述符 */

 楼主| 欢乐家园 发表于 2021-2-22 22:08 | 显示全部楼层
设备描述符的数组的长度一般为9个字节,该描述符定义了USB协议代号、厂商ID(VID),产品ID(PID)、设备的版本号、以及厂商产品序列号描述符的索引。在USB枚举阶段,USB设备需要通过端口0向USB主机发送设备描述符。
 楼主| 欢乐家园 发表于 2021-2-22 22:09 | 显示全部楼层
配置描述符集合里有着丰富的USB设备的信息,如用了几个接口,用了几个端点,USB设备做什么用等。代码如下:
 楼主| 欢乐家园 发表于 2021-2-22 22:10 | 显示全部楼层
  1.     0x00,         /*nInterfaceProtocol :该接口使用的协议0=none, 1=keyboard, 2=mouse */
  2.     0,            /*iInterface: 该接口字符串的索引 */

  3.     /*****************HID描述符 ********************/
  4.     0x09,         /*bLength: HID描述符的长度为9字节 */
  5.     HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID的描述符类型为0x21 */
  6.     0x10,         /*bcdHID: HID协议的版本为1.1 */
  7.     0x01,
  8.     0x00,         /*bCountryCode: 国家代号 */
  9.     0x01,         /*bNumDescriptors: 下级描述符的数量*/
  10.     0x22,         /*bDescriptorType:下级描述符的类型*/
  11.     CUSTOMHID_SIZ_REPORT_DESC,/* wItemLength: 下一集描述符的长度*/
  12.     0x00,

  13.     /********************输入端点描述符******************/
  14.     0x07,         /* bLength: 端点描述符的长度为7字节*/
  15.     USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x21*/
  16.     0x82,         /* bEndpointAddress: 该端点(输入)的地址,D7:0(OUT),1(IN),D6~D4:保留,D3~D0:端点号*/               
  17.     0x03,         /* bmAttributes: 端点的属性为为中断端点.
  18.          D0~D1表示传输类型:0(控制传输),1(等时传输),2(批量传输),3(中断传输)
  19.            非等时传输端点:D2~D7:保留为0
  20.            等时传输端点:
  21.            D2~D3表示同步的类型:0(无同步),1(异步),2(适配),3(同步)
  22.            D4~D5表示用途:0(数据端点),1(反馈端点),2(暗含反馈的数据端点),3(保留),D6~D7:保留,*/
  23.     0x40,         /* wMaxPacketSize: 该端点支持的最大包长度为64字节*/
  24.     0x00,
  25.     0x02,         /* bInterval: 轮询间隔(2 ms) */
  26.    
  27. /********************输出端点描述符******************/   
  28.     0x07,        /* 端点描述符的长度为7字节 */
  29.     USB_ENDPOINT_DESCRIPTOR_TYPE,    /* bDescriptorType: 端点描述符的类型为0x21*/
  30.     0x01,        /* bEndpointAddress: 该端点(输出)的地址,D7:0(OUT),1(IN),D6~D4:保留,D3~D0:端点号*/
  31.     0x03,        /* bmAttributes: 端点的属性为为中断端点 */
  32.     0x40,        /* wMaxPacketSize: 该端点支持的最大包长度为64字节  */
  33.     0x00,
  34.     0x02,        /* bInterval: 轮询间隔(2 ms) */
  35. };


  36.    


  37.    

  38.    
 楼主| 欢乐家园 发表于 2021-2-22 22:14 | 显示全部楼层
从上面的代码中可以看出,USB设备使用了1个接口、两个端点:一个中断传输输入端点,端点号为2;一个中断传输的输出端点,端点号为1、每个端点能通讯的最大数据包长度为64字节、USB的功能自定义等。配置描述符是在USB主机发送GET_CONFIGURATION请求时,USB设备发送的。
 楼主| 欢乐家园 发表于 2021-2-22 22:14 | 显示全部楼层
还有一个很重要的当然报告描述符了:
 楼主| 欢乐家园 发表于 2021-2-22 22:15 | 显示全部楼层
  1. /* HID的报告描述符*/
  2. const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =
  3. {  
  4. /*short Item   D7~D4:bTag;D3~D2:bType;D1~D0:bSize
  5.    **bTag —主条目 1000:输入(Input) 1001:输出(Output) 1011:特性(Feature)   1010:集合(Collection) 1100:关集合(End Collection)
  6.    **  全局条目 0000:用途页(Usage Page) 0001:逻辑最小值(Logical Minimum) 0010:逻辑最大值(Logical Maximum) 0011:物理最小值(Physical Minimum)
  7.    **  0100:物理最大值(Physical Maximum) 0101:单元指数(Unit Exponet) 0110:单元(Unit) 0111:数据域大小(Report Size)
  8.    **  1000:报告ID(Report ID) 1001:数据域数量(Report Count) 1010:压栈(Push) 1011:出栈(Pop) 1100~1111:保留(Reserved)
  9.    **  局部条目 0000:用途(Usage) 0001:用途最小值(Usage Minimum) 0010:用途最大值(Usage Maximum) 0011:标识符索引(Designator Index)
  10.    **      0100:标识符最小值(Designator Minimum) 0101:标识符最大值(Designator Maximum) 0111:字符串索引(String Index) 1000:字符串最小值(String Minimum)   
  11.    **      1001:字符串最大值(String Maximum) 1010:分隔符(Delimiter) 其他:保留(Reserved)
  12.    **bType—00:主条目(main)  01:全局条目(globle)  10:局部条目(local)  11:保留(reserved)
  13.    **bSize—00:0字节  01:1字节  10:2字节  11:4字节*/

  14. //0x05:0000 01 01 这是个全局条目,用途页为ST页
  15. 0x05, 0x8c, /* USAGE_PAGE (ST Page) */
  16. //0x09:0000 10 01 这是个局部变量,用途为Demo Kit
  17. 0x09, 0x01, /* USAGE (Demo Kit) */
  18. //0xa1:1010 00 01 这是一个主条目,集合为应用集合
  19. 0xa1, 0x01, /* COLLECTION (Application) */

  20. /* 输入报告*/
  21. //0x09:0000 10 01 这是个局部条目,用途为厂商ID
  22. 0x09,0x03, // USAGE ID - Vendor defined
  23. //0x15:0001 01 01 这是个全局条目,逻辑最小值为0
  24. 0x15,0x00, // LOGICAL_MINIMUM (0)
  25. //0x26:0010 01 10 这是个全局条目,逻辑最大值为255
  26. 0x26,0x00, 0xFF, // LOGICAL_MAXIMUM (255)
  27. //0x75:0111 01 01 这是个全局条目,报告大小为8位
  28. 0x75,0x08, // REPORT_SIZE (8bit)
  29. //0x95:1001 01 01 这是个全局条目,报告数量为64
  30. 0x95,0x40, // REPORT_COUNT (64Byte)
  31. //0x81:1000 00 01 这是个主条目,做输入,Data表示这些数据可变,Var表示这些徐居于是独立的变量,Abs表示绝对值
  32. 0x81,0x02, // INPUT (Data,Var,Abs)

  33. /*输出报告*/
  34. //0x09:0000 10 01 这是个局部条目,用途为厂商ID
  35. 0x09,0x04, // USAGE ID - Vendor defined
  36. //0x15:0001 01 01 这是个全局条目,逻辑最小值为0
  37. 0x15,0x00, // LOGICAL_MINIMUM (0)
  38. //0x26:0010 01 10 这是个全局条目,逻辑最大值为255
  39. 0x26,0x00,0xFF, // LOGICAL_MAXIMUM (255)
  40. //0x75:0111 01 01 这是个全局条目,报告大小为8位
  41. 0x75,0x08, // REPORT_SIZE (8bit)
  42. //0x95:1001 01 01 这是个全局条目,报告数量为64
  43. 0x95,0x40, // REPORT_COUNT (64Byte)
  44. //0x91:1001 00 01 这是个全局条目,做输出,Data表示这些数据可变,Var表示这些徐居于是独立的变量,Abs表示绝对值
  45. 0x91,0x02, // OUTPUT (Data,Var,Abs)

  46. 0xc0 /* END_COLLECTION */
  47. };


  48.    
 楼主| 欢乐家园 发表于 2021-2-22 22:16 | 显示全部楼层
关于配置描述符也是至关重要的,它规定了USB通讯的长度,具体格式。据上面的报告描述符说:定义了64*8bit的数据域作为输入,属性是Data、Var、Abs,也就是说USB设备想USB主机每次发送64字节的数据包,每个数据的值(0~255之间)可以用户自定义;还定义了64*8bit的数据域作为输出,属性是Data、Var、Abs,也就是说USB主机箱USB设备每次发送64字节的数据包,每个数据的值(0~255)由USB主机自己定义。
 楼主| 欢乐家园 发表于 2021-2-22 22:16 | 显示全部楼层
接下的一些说明描述符代码如下,就不详细介绍了:
 楼主| 欢乐家园 发表于 2021-2-22 22:17 | 显示全部楼层
  1. /* 语言ID描述符 */
  2. const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] =
  3. {
  4.     CUSTOMHID_SIZ_STRING_LANGID,     /*bLength:本描述符的长度为4字节*/
  5.     USB_STRING_DESCRIPTOR_TYPE,      /*bDescriptorType:字符串描述符的类型为0x03*/
  6.     0x09,                          /*bString:语言ID为0x0409,表示美式英语*/
  7.     0x04
  8. }; /* LangID = 0x0409: U.S. English*/

  9. /*厂商字符串描述符*/
  10. const uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR] =
  11. {
  12.     CUSTOMHID_SIZ_STRING_VENDOR,     /*bLength:厂商字符串描述符的长度*/
  13.     USB_STRING_DESCRIPTOR_TYPE,      /*bDescriptorType:字符串描述符的类型为0x03*/
  14.     ‘M’, 0, ‘y’, 0, ‘U’, 0,‘S’, 0,‘B’, 0, ‘_’, 0, ‘H’, 0,‘I’,0,‘D’,0  /*自定义*/
  15. };

  16. /*产品的字符串描述符*/
  17. const uint8_t CustomHID_StringProduct[CUSTOMHID_SIZ_STRING_PRODUCT] =
  18. {
  19.     CUSTOMHID_SIZ_STRING_PRODUCT,   /* bLength:产品的字符串描述符*/
  20.     USB_STRING_DESCRIPTOR_TYPE,     /* bDescriptorType:字符串描述符的类型为0x03*/
  21.     ‘B’, 0, ‘y’, 0, ’ ‘, 0, ‘v’, 0, ‘i’, 0, ‘e’, 0,‘w’,0,‘t’,0,‘o’,0,‘o’,0,‘l’,0/*自定义*/
  22. };

  23. /*产品序列号的字符串描述符*/
  24. uint8_t CustomHID_StringSerial[CUSTOMHID_SIZ_STRING_SERIAL] =
  25. {
  26.     CUSTOMHID_SIZ_STRING_SERIAL,    /* bLength:产品序列号*/
  27.     USB_STRING_DESCRIPTOR_TYPE,     /* bDescriptorType:字符串描述符的类型为0x03*/
  28.     ‘x’, 0, ‘x’, 0, ‘x’, 0,‘x’, 0,‘x’, 0, ‘x’, 0, ‘x’, 0 /*自定义*/
  29. };


  30.    
 楼主| 欢乐家园 发表于 2021-2-22 22:19 | 显示全部楼层
接下去需要改动的的是usb_prop.c这个文件里的内容。这个文件大部分不需要膝盖,只要修改下CustomHID_Reset()这个函数(名字不定相同)。这个函数的定义如下:
 楼主| 欢乐家园 发表于 2021-2-22 22:20 | 显示全部楼层
/*******************************************************************************
* Function Name  : CustomHID_Reset.
* Description    : CustomHID Mouse reset routine.复位
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void CustomHID_Reset(void)
{
  /* Set CustomHID_DEVICE as not configured */
  pInformation->Current_Configuration = 0;     //设置当前的配置为0,表示没有配置过
  pInformation->Current_Interface = 0;//默认的接口

  /* Current Feature initialization */
  pInformation->Current_Feature = CustomHID_ConfigDescriptor[7];//当前的属性,bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒

#ifdef STM32F10X_CL   
  /* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */
  
  /* Init EP1 IN snd EP1 OUT as Interrupt endpoint */
  OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, EP1_SIZE);
  OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, EP1_SIZE);
#else

  SetBTABLE(BTABLE_ADDRESS);

/*————————————————————————–*/
  /* Initialize Endpoint 0 */
  SetEPType(ENDP0, EP_CONTROL);          //设置端点1为控制端点
  SetEPTxStatus(ENDP0, EP_TX_STALL);  //设置端点0发送延时
  SetEPRxAddr(ENDP0, ENDP0_RXADDR);      //设置端点0的接收缓冲区地址
  SetEPTxAddr(ENDP0, ENDP0_TXADDR);      //设置端点0的发送缓冲区地址
  Clear_Status_Out(ENDP0);           //清除端点0的状态
  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);//设置端点0的接收的计数
  SetEPRxValid(ENDP0);               //使能接收状态

  /* Initialize Endpoint 1 */
     SetEPType(ENDP1, EP_INTERRUPT);    //设置端点1为中断控制端点
     SetEPRxAddr(ENDP1, ENDP1_RXADDR);  //设置端点1的接收缓冲地址
     SetEPRxCount(ENDP1, REPORT_COUNT);     //设置端点1的接收计数
     SetEPRxStatus(ENDP1, EP_RX_VALID);     //设置端点1接收有效
     //SetEPTxStatus(ENDP1, EP_TX_DIS);

  /* Initialize Endpoint 2 */
     SetEPType(ENDP2, EP_INTERRUPT);    //设置端点2为中断控制端点
     SetEPTxAddr(ENDP2, ENDP2_TXADDR);  //设置端点2的接收缓冲地址
     SetEPTxCount(ENDP2, REPORT_COUNT);     //设置端点2的接收计数
     SetEPTxStatus(ENDP2, EP_TX_NAK);   //设置端点2为接收不响应

/*————————————————————————–*/

     bDeviceState = ATTACHED;             //设置设备状态为 ATTACHED状态
  /* Set this device to response on default address */
  SetDeviceAddress(0);                  //设置设备为默认地址
#endif /* STM32F10X_CL */

  bDeviceState = ATTACHED;
}

您需要登录后才可以回帖 登录 | 注册

本版积分规则

114

主题

1067

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部