文章目录[隐藏]
环境为STM32CUBEMX+MDK5.27
开发目的:实现与电脑的USB_HS高速通讯,通过ULPI接口外接PHY芯片,模式为custom hid。
板子为微雪open743,模块USB3300也是微雪家的,之前单独买了一个USB3300模块搭配自己手里的743核心板(杜邦线连接),发现USB枚举无法正常。无奈之举,买了一块微雪的开发板。项目着急开发程序,板子只能买,全网做USB3300模块也就微雪一家。
开发流程:
1、微雪只提供了USB_HS的HID和MSC例子,其中HID是模拟鼠标功能,与设计需求不符,为了测试板子功能直接烧录完成测试,程序功能正常,能遥杆控制鼠标移动
2、参考微雪的开发方式,用STM32CUBEMX开配置USB_HS和外部PHY芯片接口。STM32CUBEMX配置如下
框里第一个参数影响USB的刷新时间,影响传输速度,最快可以调到0X01
PS:主要的配置就这些,时钟频率我设置满速480MHZ。
3、生成代码,MDK5.27环境。
4、修改代码
分析一下报文,记录一下
这里我说一下这个报文的要素,第一部分你可以理解为报文头;第二部分你可以理解为USB告诉PC机问我要做什么,这里主要告诉PC机我要做一个接收与发送的设备,USAGE~INPUT这里是描述这个USB设备作为输入的时候的数据格式,下一个USAGE~OUTPUT是描述该USB设备输出的数据格式,其中LOGICAL_MINIMUM是指每个字节数据的最小值,LOGICAL_MAXIMUM是指每个字节数据的最大值,REPORT_COUNT是指定每次传输数据最多多少个字节,REPORT_SIZE是指定每次传输数据每个字节的位数;第三部分是结束标志。
============================================================
下面我插入一个对报文描述符进行一个简单的描述:
标签解析举例(Usage :0x50, 0x01):
(Usage Page标签0x0?)0x05=0000 0101 :
0x05表示前缀,0x01为数据部分,0x05转换成二进制,就是0000 01 01,按照HID类协议5.3 generic item format的定义,这个字节被分成3个部分:
bit0~bit1代表的是这个前缀后面跟的数据长度,这里就是后面0x01的长度,两位可以表示最大4字节的数据,即bsize
bit2~bit3代表的是这个前缀的类型,总共可以有三种类型:0=main,1=global,2=local,3=reserved;
bit4~bit7代表前tag,一般分为input(二进制的1000 00 nn,即bit4~bit7=1000,代表一个tag,bit2~bit3=00,代表main,bit0~bit1=nn,代表这个前缀后面还有nn所代表的数据),output(二进制的 1001 00 nn),feature(1011 00 nn),collection(1010 00 nn),end collection(1100 00 nn)
即:
0000:Usage Page
01: bType,全局(bType=0:主项目;bType=1:全局项目;bType=2:区域项目)
01:bSzie,1字节(bSzie为项目所需数据字节数目,bSzie可为1、2、4,注意bSzie不可为3)
(Page ID)0x01: 表示该Page为Generalic Desktop Controls(Usage ID 0为保留。ID 1到0x1F为”top level” collection保留,这些ID虽然对于Application不是必须,但可以用于识别通用设备类型)
Usage = (usage page:usage ID):其将数据的操控与它的用途作一对一的对应,所以解读报告后就可以知道每个数据作何种操作。所以“传输的数据”和“操作”只是一事件的两种描述方式。用途是以一个32位卷标(称作usage tag)来表示,高16位称作usage page(用途类页),低16位称为usage ID(用途识别名),文件universal serial Bus HID Usage Table完整列出所有的usage pages(用途类页)和usage ID(用途识别名),使用者必须遵照文件的规范来声明操作的用途。用途卷标只是报告描述符诸多标签的一个,利用这些卷标取可以清楚完整的描述符操作的用途。
这里其实说的并不清楚,因为作者有点懒就不细说了,想了解更多的可以百度《圈圈教你玩USB》,这里说的比我好。
程序修改
【1】usbd_custom_hid_if.c
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_HS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x40, // REPORT_COUNT (64)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x40, // REPORT_COUNT (64)
0x75, 0x08, // REPORT_SIZE (8)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
};
【2】usbd_conf.h
#define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 64U
/*---------- -----------*/
#define USBD_CUSTOM_HID_REPORT_DESC_SIZE 34U
【3】usbd_customhid.h
#define CUSTOM_HID_EPIN_ADDR 0x81U
#define CUSTOM_HID_EPIN_SIZE 0x40U
#define CUSTOM_HID_EPOUT_ADDR 0x01U
#define CUSTOM_HID_EPOUT_SIZE 0x40U
5、编译烧写代码
结果:电脑设备管理器没反应
反复插拔USB线,尝试拔掉调试器,偶尔会出现响应,但并不稳定,过一会被断开。头疼了,反复折腾模式,发现无论是虚拟串口还是HID都是如此现象。
6、调试代码,检查细节
STM32CUBEMX经常会生成BUG,对,生成BUG,虐我千百遍。要不是可以省移植USB驱动的功夫,才懒得用
对照了微雪的例子和STM32CUBE文件设置。发现一个有差别的地方,怎么我这生成的程序里打开了GPIOI的时钟,微雪的却没有。
问题原因:cubemx生成的ULPI_DIR引脚是PI11,微雪板子是接到PC2
这这这,ULPI接口的引脚不是固定的吗?还可以有出入?过于相信CUBEMX生成的代码了,惊了。修改了一下程序,再烧写,反应就对了。
然后,在mian.c里加入了测试代码,单上传。
extern USBD_HandleTypeDef hUsbDeviceHS; //外部声明USB的句柄
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t send_buf[64] = {//定义一个USB的发送BUFF
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64};
while (1)
{
/* USER CODE END WHILE */
USBD_CUSTOM_HID_SendReport(&hUsbDeviceHS, send_buf, sizeof(send_buf)); //第一个参数是USB句柄,生成项目就有了的;第二个参数是发送数据;第三个发送的数据长度
//HAL_Delay(10);
/* USER CODE BEGIN 3 */
}
终于对了。
然后是电脑下发,单片机接收功能的实现。
在usbd_custom_hid_if.c内添加以下代码。
unsigned char USB_Recive_Buffer[64]; //USB接收缓存
unsigned char USB_Received_Count = 0;//USB接收数据计数
//这个函数有原形,找到修改即可。
static int8_t CUSTOM_HID_OutEvent_HS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
char i;
/*查看接收数据长度*/
USB_Received_Count = USBD_GetRxCount( &hUsbDeviceHS,CUSTOM_HID_EPOUT_ADDR ); //第一参数是USB句柄,第二个参数的是接收的末端地址;要获取发送的数据长度的话就把第二个参数改为发送末端地址即可
//printf("USB_Received_Count = %d \r\n",USB_Received_Count);
USBD_CUSTOM_HID_HandleTypeDef *hhid; //定义一个指向USBD_CUSTOM_HID_HandleTypeDef结构体的指针
hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceHS.pClassData;//得到USB接收数据的储存地址
for(i=0;i<USB_Received_Count;i++)
{
USB_Recive_Buffer[i]=hhid->Report_buf[i]; //把接收到的数据送到自定义的缓存区保存(Report_buf[i]为USB的接收缓存区)
}
return USBD_OK;
/* USER CODE END 6 */
}
结果:
基本功能已经完成,还需要找个软件来测试下上传速度。
版权声明:本文为CSDN博主「不爱吃糖的胖子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010396127/article/details/117283108
暂无评论