概述
本篇文章主要介绍:
- 如何使用STM32CubeMX创建stm32F407+freertos+usb host的基础工程。
- USB-HOST-CDC驱动运行过程。
- 如何根据4G模块的具体信息修改usb相关代码。
- MCU如何通过usb与4G模块通信,收发数据。
- 调试过程中遇到的问题以及解决办法。
整个过程中在网上搜罗了很多参考资料,有些与我理解不相符的就不罗列了,觉得有用的我会引用并简单说明。
创建工程
关于创建工程,网上资料太多了,freertos的,usb的都有详细教程,我这里就只罗列个大概,不详细展开了。
- 根据实际情况选择芯片。
- 基础配置
- 启用freertos。
- 启用USB。先根据硬件配置好USB对应的GPIO模式,然后配置USB,这里选用的是FS全速模式,单片机做为USB Host,4G模块为Slave(根据EC600U手册描述,也只能为Slave),然后添加usb相关驱动库。
5. 生成代码。根据需要增加其他配置,配置完成后生成代码。
至此,基本工程已经创建完成了,后面再根据需要进行一些代码的修改,因为本篇主要讲述USB的使用,freertos的内容就不叙述了。
USB-HOST-CDC驱动运行过程
此部分简述了设备上电后USB驱动是如何运行的,理解相关的内容,可以略过。
在freertos下,USB-HOST-CDC驱动是在freertos的默认任务下进行的初始化,代码如下:
void MX_USB_HOST_Init(void)
{
/* USER CODE BEGIN USB_HOST_Init_PreTreatment */
/* USER CODE END USB_HOST_Init_PreTreatment */
/* Init host Library, add supported class and start the library. */
if (USBH_Init(&hUsbHostFS, USBH_UserProcess, HOST_FS) != USBH_OK)
{
Error_Handler();
}
if (USBH_RegisterClass(&hUsbHostFS, USBH_CDC_CLASS) != USBH_OK)
{
Error_Handler();
}
if (USBH_Start(&hUsbHostFS) != USBH_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USB_HOST_Init_PostTreatment */
/* USER CODE END USB_HOST_Init_PostTreatment */
}
简单来说,上面的初始化完成后USB驱动就开始运行了。具体包括GPIO模式的配置代码,配置完成后它创建了一个单独的任务 SBH_Process_OS,就是在这个任务里调用了USB的处理函数USBH_Process,USBH_Process函数实现了USB驱动的状态机,包括设备检测、设备枚举等过程,是USB驱动的主要过程函数,借用这篇文章中的图片展示下状态机,该文章对驱动库进行了详细说明,可以看一下:
其中比较重要的是设备枚举部分,截取相关代码如下,关于枚举这篇文章讲解的很详细:
case HOST_ENUMERATION:
/* Check for enumeration status */
status = USBH_HandleEnum(phost);
if (status == USBH_OK)
{
/* The function shall return USBH_OK when full enumeration is complete */
USBH_UsrLog("Enumeration done.");
phost->device.current_interface = 0U;
if (phost->device.DevDesc.bNumConfigurations == 1U)
{
USBH_UsrLog("This device has only 1 configuration.");
phost->gState = HOST_SET_CONFIGURATION;
}
else
{
phost->gState = HOST_INPUT;
}
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, 0U);
#endif
#endif
}
break;
设备枚举成功后,通常就可以通信了,但是因为刚接触USB通信,一直调不通,所以对枚举过程也进行了一些研究,在USBH_HandleEnum函数中会调用到以下接口:
ReqStatus = USBH_Get_DevDesc(phost, 8U);
ReqStatus = USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE);
ReqStatus = USBH_SetAddress(phost, USBH_DEVICE_ADDRESS);
ReqStatus = USBH_Get_CfgDesc(phost, USB_CONFIGURATION_DESC_SIZE);
ReqStatus = USBH_Get_CfgDesc(phost, phost->device.CfgDesc.wTotalLength)