当前位置: 首页 > news >正文

利用STM32CubeMX软件生成USB_HOST_CDC驱动ME909s-821ap(4G通信模块)

一、测试平台:
MCU:STM32F429IGT6
工具:STM32CubeMX软件
编译软件:MDK

二、配置步骤
(1).打开STM32CubeMX软件,创建新的工程文件,先生成一个不带操作系统的串口1例程,生成串口的例程这里不再详细介绍。
(2).由于测试通信模块时需要给通信模块发送AT命令,所以在这里我们将串口1接上电脑,通过电脑串口软件下发AT命令,串口1接收中断收到数据之后将AT命令通过USB接口转发给4G通信模块。由于AT命令都是以0x0D 0x0A结束,所以当串口收到0x0A时,则所以数据接收完成,之后将数据转发给4G通信模块。
(3).编写串口1接收中断函数,实现串口1收到以0x0A结尾的数据之后,将数据回传到电脑端串口软件中。由于STM32CubeMX生成的工程中没有开启串口1接收中断,在这里添加上。
__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
在这里插入图片描述
添加串口1接收和发送的函数
///重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
unsigned char bCh=0;
bCh=ch;
HAL_UART_Transmit(&huart1,&bCh,1,10);
return (ch);
}

unsigned char TxdData[UART_BUF_LEN];
unsigned char bRxdFinishFlag=0;
unsigned char RxdData[UART_BUF_LEN];
unsigned char bRxLen=0;
unsigned char UsbRxdData[USB_BUF_LEN];

void Test_USART_TXRX(void)
{
if(1==bRxdFinishFlag)
{
bRxdFinishFlag=0;
HAL_UART_Transmit(&huart1,RxdData,bRxLen,100);
}
}
在这里插入图片描述
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint8_t bData=0;
static uint8_t bCnt=0;

if(__HAL_UART_GET_FLAG( &huart1, UART_FLAG_RXNE ) != RESET)
{		
bData=( uint8_t)READ_REG(huart1.Instance->DR);
	RxdData[bCnt++]=bData;
	if(RxdData[bCnt-1]==0x0A)
	{
		bRxLen=bCnt;
		bCnt=0;
		bRxdFinishFlag=1;
	}   
}

/* USER CODE END USART1_IRQn 0 /
// HAL_UART_IRQHandler(&huart1);
/
USER CODE BEGIN USART1_IRQn 1 */

/* USER CODE END USART1_IRQn 1 */
}
在这里插入图片描述
(4).测试串口1的接收和发送,电脑串口1软件下发0x0A结尾的AT命令,串口1可以接收到下发的命令。
在这里插入图片描述
(5).配置USB_OTG,由于电路板上的USB引出来的管脚是PB14,PB15,所以在这里需要配置USB_OTG_HS,由于电路板上没有外接Phy,所以这里配置为内部的FS Phy,Internal FS Phy选项下Host Only,同时配置中断。
在这里插入图片描述
(6).配置USB_HOST,由于4G通信模块是CDC设备,所以在这里配置为Class For HS IP项下选择Communication Host Class(Virtual Port Com)。因为ME909s模块连接后,配置描述符下一共有5个 Interface , 并且 Interface 中至多有3个Endpoint(下面简称Ep)。所以 USBH_MAX_NUM_ENDPOINTS 需配置 >3 , USBH_MAX_NUM_INTERFACES 需配置 >5.。
在这里插入图片描述
(7).生成代码之后,修改classcode,由于ME909s厂商自定义的classcode是0xFF,所以将USB_CDC_CLASS宏定义修改为0xFF。
#define USB_CDC_CLASS 0x02
#define USB_CDC_CLASS 0xFF //厂商自定义classcode
在这里插入图片描述
(8).修改usbh_cdc.c 中的 USBH_CDC_InterfaceInit 函数,由于ME909s用的是接口0,所以这里接口为0,interface = USBH_FindInterfaceIndex(phost, 0, 0);若为EC20通信模块,则为接口2,interface = USBH_FindInterfaceIndex(phost, 2, 0);
static USBH_StatusTypeDef USBH_CDC_InterfaceInit(USBH_HandleTypeDef *phost)
{

USBH_StatusTypeDef status = USBH_FAIL;
uint8_t interface;
CDC_HandleTypeDef *CDC_Handle;

// 默认系统配置标准CDC接口

// interface = USBH_FindInterface(phost,
// USB_CDC_CLASS,
// ABSTRACT_CONTROL_MODEL,
// COMMON_AT_COMMAND);

/**
 * 注:
 * cubemx生成的例程中,标准的CDC类设备,1个配置描述符中需要2接口
 * 其中一个为Communication Interface Class, 该接口需要一个方向为in的Ep
 * 另外一个为Data Interface Class, 该接口需要一个方向为in的Ep和一个方向为out的Ep
 * 所以USBH_CDC_InterfaceInit函数,调用了两次USBH_FindInterface函数
 * 查找两个匹配的Interface, 分别进行配置
 *
 * USB-TTL串口工具,debug状态下查询设备描述符结构体中,只有一个接口
 * 但是该接口拥有3个Ep, 2个方向为in, 1个方向为out.
 * 由此猜测,串口工具并没有将Interface分开
 * 经测试, Communication Interface使用的Ep为2, Data Interface使用Ep0,1
 *
 * Ec20模块,可以读到5个Interface,但是只有Interface 1 2 3 有3个Ep,0 和 4 只有2个Ep
 * 经测试,接口AT指令的串口Interface为 2.
 * Interface 2中,Communication Interface使用的Ep为0
 * Data Interface使用的Ep为1 和 2
 */

// USB-TTL串口工具接口配置

// interface = USBH_FindInterface(phost,
// USER_USB_CDC_CLASS,
// DIRECT_LINE_CONTROL_MODEL, 02);
// 移远4G模块接口配置
interface = USBH_FindInterfaceIndex(phost, 0, 0);

if (interface == 0xFFU) /* No Valid Interface */
{
	USBH_DbgLog("Cannot Find the interface for Communication Interface Class.",
			phost->pActiveClass->Name);
}
else
{
	USBH_SelectInterface(phost, interface);
	phost->pActiveClass->pData = (CDC_HandleTypeDef*) USBH_malloc(
			sizeof(CDC_HandleTypeDef));
	CDC_Handle = (CDC_HandleTypeDef*) phost->pActiveClass->pData;

	/*Collect the notification endpoint address and length*/
	if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress
			& 0x80U)
	{
		CDC_Handle->CommItf.NotifEp =
				phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
		CDC_Handle->CommItf.NotifEpSize =
				phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
	}

	/*Allocate the length for host channel number in*/
	CDC_Handle->CommItf.NotifPipe = USBH_AllocPipe(phost,
			CDC_Handle->CommItf.NotifEp);

	/* Open pipe for Notification endpoint */
	USBH_OpenPipe(phost, CDC_Handle->CommItf.NotifPipe,
			CDC_Handle->CommItf.NotifEp, phost->device.address, phost->device.speed,
			USB_EP_TYPE_INTR, CDC_Handle->CommItf.NotifEpSize);

	USBH_LL_SetToggle(phost, CDC_Handle->CommItf.NotifPipe, 0U);

	// 默认系统配置标准CDC接口

// interface = USBH_FindInterface(phost,
// DATA_INTERFACE_CLASS_CODE,
// RESERVED,
// NO_CLASS_SPECIFIC_PROTOCOL_CODE);

	if (interface == 0xFFU) /* No Valid Interface */
	{
		USBH_DbgLog("Cannot Find the interface for Data Interface Class.",
				phost->pActiveClass->Name);
	}
	else
	{
		/*Collect the class specific endpoint address and length*/
		if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].bEndpointAddress
				& 0x80U)
		{
			CDC_Handle->DataItf.InEp =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].bEndpointAddress;
			CDC_Handle->DataItf.InEpSize =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].wMaxPacketSize;
		}
		else
		{
			CDC_Handle->DataItf.OutEp =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].bEndpointAddress;
			CDC_Handle->DataItf.OutEpSize =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].wMaxPacketSize;
		}

		if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress
				& 0x80U)
		{
			CDC_Handle->DataItf.InEp =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
			CDC_Handle->DataItf.InEpSize =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
		}
		else
		{
			CDC_Handle->DataItf.OutEp =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
			CDC_Handle->DataItf.OutEpSize =
					phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
		}

		/*Allocate the length for host channel number out*/
		CDC_Handle->DataItf.OutPipe = USBH_AllocPipe(phost,
				CDC_Handle->DataItf.OutEp);

		/*Allocate the length for host channel number in*/
		CDC_Handle->DataItf.InPipe = USBH_AllocPipe(phost,
				CDC_Handle->DataItf.InEp);

		/* Open channel for OUT endpoint */
		USBH_OpenPipe(phost, CDC_Handle->DataItf.OutPipe,
				CDC_Handle->DataItf.OutEp, phost->device.address, phost->device.speed,
				USB_EP_TYPE_BULK, CDC_Handle->DataItf.OutEpSize);
		/* Open channel for IN endpoint */
		USBH_OpenPipe(phost, CDC_Handle->DataItf.InPipe, CDC_Handle->DataItf.InEp,
				phost->device.address, phost->device.speed,
				USB_EP_TYPE_BULK, CDC_Handle->DataItf.InEpSize);

		CDC_Handle->state = CDC_IDLE_STATE;

		USBH_LL_SetToggle(phost, CDC_Handle->DataItf.OutPipe, 0U);
		USBH_LL_SetToggle(phost, CDC_Handle->DataItf.InPipe, 0U);
		status = USBH_OK;
	}
}
return status;

}

(9).修改 USBH_CDC_ClassRequest 函数,经过测试发现,此函数可以不用修改,用原函数即可。
static USBH_StatusTypeDef USBH_CDC_ClassRequest(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_FAIL;
CDC_HandleTypeDef CDC_Handle =
(CDC_HandleTypeDef
) phost->pActiveClass->pData;
// /Issue the get line coding request/
// status = GetLineCoding(phost, &CDC_Handle->LineCoding);
CDC_Handle->data_rx_state = CDC_IDLE;
CDC_Handle->data_tx_state = CDC_IDLE;
CDC_Handle->LineCoding.b.bCharFormat = 0;
CDC_Handle->LineCoding.b.bDataBits = 8;
CDC_Handle->LineCoding.b.bParityType = 0;
CDC_Handle->LineCoding.b.dwDTERate = 115200;
status = USBH_OK;
if (status == USBH_OK)
{
phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
}
return status;
}
在这里插入图片描述
(10).修改usb_host.c文件中的MX_USB_HOST_Process(void)函数
void MX_USB_HOST_Process(void)
{
CDC_HandleTypeDef CDC_Handle = hUsbHostHS.pActiveClass->pData;
/
USB Host Background task */
USBH_Process(&hUsbHostHS);
if (hUsbHostHS.gState == HOST_CLASS)
{
if (CDC_Handle->data_rx_state == CDC_IDLE)
{
USBH_CDC_Receive(&hUsbHostHS, UsbRxdData, USB_BUF_LEN);
}
}
}
在这里插入图片描述
(11).usb_host.c文件中重定义 USBH_CDC_ReceiveCallback 函数
void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef *phost)
{
unsigned char len_rec=0;

len_rec = USBH_CDC_GetLastReceivedDataSize(phost);
HAL_UART_Transmit(&huart1,UsbRxdData,len_rec,100);

}
在这里插入图片描述
(12).修改USBH_UsrLog宏定义
#define USBH_UsrLog(…) do {
printf(“USBH_UsrLog: “) ;
printf(VA_ARGS);
printf(”\n”);
} while (0)
在这里插入图片描述
(13).将串口1收到的数据通过USB转发给4G通信模块。
void Test_USART_TXRX(void)
{
if(1==bRxdFinishFlag)
{
bRxdFinishFlag=0;
// HAL_UART_Transmit(&huart1,RxdData,bRxLen,100);
USBH_CDC_Transmit(&hUsbHostHS, (uint8_t *)RxdData, bRxLen);
}
}
在这里插入图片描述
(14).通过串口软件下发AT命令,可以收到正确的回复。
在这里插入图片描述
(15).若为带freertos操作系统的版本,则需要在USB任务中添加MX_USB_HOST_Process()函数。
在这里插入图片描述

相关文章:

  • 第7章 Spring中的Bean的管理
  • 计算机组成原理_存储系统结构
  • 3D建模|手绘角色模型和手绘场景模型有什么区别?
  • 中成药数据图谱可视化与知识问答平台研究
  • Eclipse配置作者信息
  • Arrays.asList和ArrayList.subList
  • MySQL架构优化
  • python从入门到实践:软件开发目录规范
  • vue3新拟态组件库开发流程——loading组件源码
  • JS中新逻辑赋值运算符使用(?.、? ?、| |=、=)
  • 软考网络工程师需要哪些复习资料?
  • CIPT备考心得分享-下一个考过的就是你
  • 构建集团统一管控体系,低代码派上用场
  • iconfont 使用
  • 4.类的定义,变量类型,方法类型
  • Google 是如何开发 Web 框架的
  • 【mysql】环境安装、服务启动、密码设置
  • 【个人向】《HTTP图解》阅后小结
  • 230. Kth Smallest Element in a BST
  • dva中组件的懒加载
  • Facebook AccountKit 接入的坑点
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • javascript面向对象之创建对象
  • Less 日常用法
  • nodejs实现webservice问题总结
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 初探 Vue 生命周期和钩子函数
  • 从tcpdump抓包看TCP/IP协议
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 高程读书笔记 第六章 面向对象程序设计
  • 诡异!React stopPropagation失灵
  • 如何使用 JavaScript 解析 URL
  • 实现菜单下拉伸展折叠效果demo
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 听说你叫Java(二)–Servlet请求
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • !!Dom4j 学习笔记
  • # 飞书APP集成平台-数字化落地
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (Python) SOAP Web Service (HTTP POST)
  • (WSI分类)WSI分类文献小综述 2024
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)jdk与jre的区别
  • (转)甲方乙方——赵民谈找工作
  • (转)我也是一只IT小小鸟
  • ***详解账号泄露:全球约1亿用户已泄露
  • .chm格式文件如何阅读
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET Core 成都线下面基会拉开序幕
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)