Use el software STM32CubeMX para generar el controlador USB_HOST_CDC ME909s-821ap (módulo de comunicación 4G)

1. Plataforma de prueba:
MCU: STM32F429IGT6
Herramienta: Software STM32CubeMX
Software de compilación: MDK

2. Pasos de configuración
(1) Abra el software STM32CubeMX, cree un nuevo archivo de proyecto y genere una rutina de puerto serie 1 sin sistema operativo.La rutina para generar un puerto serie no se describirá en detalle aquí.
(2) Dado que es necesario enviar comandos AT al módulo de comunicación al probar el módulo de comunicación, aquí conectamos el puerto serie 1 a la computadora y emitimos el comando AT a través del software del puerto serie de la computadora.Después del puerto serie 1 recibe la interrupción y recibe los datos, el comando AT se enviará a través del USB.La interfaz se reenvía al módulo de comunicación 4G. Dado que todos los comandos AT terminan con 0x0D 0x0A, cuando el puerto serie recibe 0x0A, la recepción de datos se completa y luego los datos se reenvían al módulo de comunicación 4G.
(3) Escriba la función de interrupción de recepción del puerto serie 1 para darse cuenta de que después de que el puerto serie 1 reciba los datos que terminan en 0x0A, devolverá los datos al software del puerto serie en la computadora. Dado que la interrupción de recepción del puerto serie 1 no está habilitada en el proyecto generado por STM32CubeMX, agréguela aquí.
__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
inserte la descripción de la imagen aquí
Agregar funciones de recepción y envío del puerto serie 1
///Redireccionar la función de biblioteca c printf a 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);
	}
}

inserte la descripción de la imagen aquí

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 */
}

inserte la descripción de la imagen aquí
(4) Pruebe la recepción y el envío del puerto serie 1. El software del puerto serie 1 de la computadora envía comandos AT que terminan en 0x0A, y el puerto serie 1 puede recibir los comandos emitidos.
inserte la descripción de la imagen aquí
(5). Configure USB_OTG. Dado que los pines de USB en la placa de circuito son PB14 y PB15, USB_OTG_HS debe configurarse aquí. Dado que no hay Phy externo en la placa de circuito, se configura como FS Phy interno, FS Phy interno En la opción Host Only, configure la interrupción al mismo tiempo.
inserte la descripción de la imagen aquí
(6). Configure USB_HOST. Dado que el módulo de comunicación 4G es un dispositivo CDC, configúrelo aquí como Class For HS IP y seleccione Communication Host Class (Virtual Port Com). Porque después de conectar el módulo ME909s, hay 5 interfaces en el descriptor de configuración y hay como máximo 3 puntos finales (en lo sucesivo, Ep) en la interfaz. Por lo tanto, USBH_MAX_NUM_ENDPOINTS debe configurarse >3, USBH_MAX_NUM_INTERFACES debe configurarse >5.
inserte la descripción de la imagen aquí
(7). Después de generar el código, modifique el código de clase. Dado que el código de clase personalizado por el fabricante del ME909 es 0xFF, modifique la definición de la macro USB_CDC_CLASS a 0xFF.
#define USB_CDC_CLASS 0x02
#define USB_CDC_CLASS 0xFF //Código de clase personalizado del fabricante
inserte la descripción de la imagen aquí
(8).Modifique la función USBH_CDC_InterfaceInit en usbh_cdc.c. Dado que ME909s usa la interfaz 0, la interfaz aquí es 0, interfaz = USBH_FindInterfaceIndex(phost, 0, 0 ); if es un módulo de comunicación EC20, es la interfaz 2, interfaz = 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) Modifique la función USBH_CDC_ClassRequest.Después de la prueba, se encuentra que esta función no necesita ser modificada, y se puede usar la función original.

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;
}

inserte la descripción de la imagen aquí
(10) Modifique la función MX_USB_HOST_Process (void) en el archivo usb_host.c

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);
    	}
    }
}

inserte la descripción de la imagen aquí
(11) Redefina la función USBH_CDC_ReceiveCallback en el archivo .usb_host.c

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);
}

inserte la descripción de la imagen aquí
(12) Modificar la definición de la macro USBH_UsrLog

#define USBH_UsrLog(...) do {
      
      	\
                            printf("USBH_UsrLog: ") ; \
                            printf(__VA_ARGS__); \
                            printf("\n"); \
} while (0)	

inserte la descripción de la imagen aquí
(13) Reenvía los datos recibidos por el puerto serie 1 al módulo de comunicación 4G a través de USB.

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);
	}
}

inserte la descripción de la imagen aquí
(14) Envíe el comando AT a través del software del puerto serie y podrá recibir la respuesta correcta.
inserte la descripción de la imagen aquí
(15) Para la versión con sistema operativo freertos, debe agregar la función MX_USB_HOST_Process() en la tarea USB.
inserte la descripción de la imagen aquí
(16) Atención especial, pruebe el USB_HOST_CDC con FreeRtos para controlar el módulo de comunicación 4G.Después de desconectar el módulo de comunicación 4G y volver a conectar el módulo de comunicación 4G, el módulo de comunicación 4G se puede enumerar, pero no hay respuesta al enviar comandos AT. Después de la prueba, se debe a que la función USBH_CDC_Receive(&hUsbHostFS, UsbRxdData, USB_BUF_LEN) no se ejecuta después de volver a conectar. La depuración encontró que la variable CDC_Handle->data_rx_state no es igual a CDC_RECEIVE_DATA_WAIT después de volver a conectar. Para resolver este problema, en Después de enumerar correctamente el módulo 4G, restablezca el valor de CDC_Handle->data_rx_state a CDC_IDLE. Agregue RESET_USB_CDC() en USBH_UsrLog(“Se inició la clase %s.”, phost->pActiveClass->Nombre);
inserte la descripción de la imagen aquí

void RESET_USB_CDC(void)
{
    
    
	CDC_HandleTypeDef *CDC_Handle = hUsbHostFS.pActiveClass->pData;
	CDC_Handle->data_rx_state = CDC_IDLE;
}

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qizhi321123/article/details/126622434
Recomendado
Clasificación