STM32 USB转串口分析

STM32 USB转串口分析

芯片:STM32F407VE

编译器:KEIL5

作者:SY

日期:2017-9-18 09:56:00

概述

使用 STM32_USB-Host-Device_Lib_V2.2.0 usb 库,将 stm32 作为 usb 设备,实现 usb 转串口的功能。

移植

按照例程添加相关文件后测试,主机端使用 Windows7 X64 ,可以正常识别 usb 设备,Windows 安装驱动后提示:驱动不能正常工作

原因

可能是需要主机端安装 USB 转串口驱动。

解决

网上搜索后,安装 stmcdc.ini

;------------------------------------------------------------------------------
; STMicroelectronics Comunication Device Class driver (CDC) INF FILE
; (C)2010 Copyright STMicroelectronics
;------------------------------------------------------------------------------

[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%PRVDR%
CatalogFile=stmcdc.cat
DriverVer=04/25/2010,1.3.1

[SourceDisksNames]
1=%DriversDisk%,,,

[SourceDisksFiles]

[Manufacturer]
%MFGNAME%=DeviceList,NT,NTamd64

[DestinationDirs]
DefaultDestDir = 12

;------------------------------------------------------------------------------
;            VID/PID Settings
;------------------------------------------------------------------------------
[DeviceList.NT]
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740

[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740

[DriverInstall.NT]
Include=mdmcpq.inf
CopyFiles=FakeModemCopyFileSection
AddReg=DriverInstall.NT.AddReg

[DriverInstall.NT.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,usbser.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"

[DriverInstall.NT.Services]
AddService=usbser, 0x00000002, DriverServiceInst

[DriverServiceInst]
DisplayName=%SERVICE%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary= %12%\usbser.sys
LoadOrderGroup = Base

;------------------------------------------------------------------------------
;              String Definitions
;------------------------------------------------------------------------------

[Strings]
PRVDR = "STMicroelectronics"
MFGNAME = "STMicroelectronics."
DESCRIPTION = "STMicroelectronics Virtual COM Port"
SERVICE = "STM Virtual COM Port"
DriversDisk = "STM Drivers Disk" 

测试驱动还是不能正常工作

网上搜索发现有驱动安装包的形式:VCP_V1.4.0_Setup.exe ,遂安装,发现还是不能正常工作。

原因

怀疑可能是从机没有移植好,采用 STM32CubeMX 软件自动生成一份下位机程序,测试下来还是和以前移植的程序现象一样

解决

网上搜索原因:stm32的usb虚拟串口驱动win7系统64位和32位不能正常安装的解决办法!stm32 virtual comport win7(终极解决办法) ,原来是 malloc 内存分配失败,扩大堆内存后,终于驱动安装成功了!

原因

既然 STM32CubeMX 可以成功,应该问题就是出在初始化阶段,仿真仔细排查:

uint8_t  usbd_cdc_Init (void  *pdev, 
                               uint8_t cfgidx)
{
  uint8_t *pbuf;

  /* Open EP IN */
  DCD_EP_Open(pdev,
              CDC_IN_EP,
              CDC_DATA_IN_PACKET_SIZE,
              USB_OTG_EP_BULK);
}

隐约感觉 CDC_DATA_IN_PACKET_SIZE 可能会有问题,查看来源:

#define CDC_DATA_IN_PACKET_SIZE                CDC_DATA_MAX_PACKET_SIZE
#define CDC_DATA_MAX_PACKET_SIZE                512  /* Endpoint IN & OUT Packet size */

问题应该出在这里了,我的 usb 使用的是 usb-hs 高速接口,但是物理层仍然使用内部的 phy ,这样使用起来简单,但是最大速度只能达到全速的速度12Mbps ,而全速设备的最大包大小为 64 字节。修改后,测试终于成功了。而且不需要安装任何第三方驱动!

移植过程中最终要的文件:usbd_cdc_vcp.c

/**
  ******************************************************************************
  * @file    usbd_cdc_vcp.c
  * @author  MCD Application Team
  * @version V1.2.0
  * @date    09-November-2015
  * @brief   Generic media access Layer.
  ******************************************************************************
  * @attention
  *
  * 

© COPYRIGHT 2015 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED #pragma data_alignment = 4 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ /* Includes ------------------------------------------------------------------*/ #include "usbd_cdc_vcp.h" #include "stm32f4xx.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ LINE_CODING linecoding = { 115200, /* baud rate*/ 0x00, /* stop bits-1*/ 0x00, /* parity - none*/ 0x08 /* nb. of bits 8*/ }; USART_InitTypeDef USART_InitStructure; /* These are external variables imported from CDC core to be used for IN transfer management. */ extern uint8_t APP_Rx_Buffer []; /* Write CDC received data in this buffer. These data will be sent over USB IN endpoint in the CDC core functions. */ extern uint32_t APP_Rx_ptr_in; /* Increment this pointer or roll it back to start address when writing received data in the buffer APP_Rx_Buffer. */ /* Private function prototypes -----------------------------------------------*/ static uint16_t VCP_Init (void); static uint16_t VCP_DeInit (void); static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len); static uint16_t VCP_DataTx (void); static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len); static uint16_t VCP_COMConfig(uint8_t Conf); CDC_IF_Prop_TypeDef VCP_fops = { VCP_Init, VCP_DeInit, VCP_Ctrl, VCP_DataTx, VCP_DataRx }; static uint8_t g_RxByte; /* Private functions ---------------------------------------------------------*/ /** * @brief VCP_Init * Initializes the Media on the STM32 * @param None * @retval Result of the operation (USBD_OK in all cases) */ static uint16_t VCP_Init(void) { return USBD_OK; } /** * @brief VCP_DeInit * DeInitializes the Media on the STM32 * @param None * @retval Result of the operation (USBD_OK in all cases) */ static uint16_t VCP_DeInit(void) { return USBD_OK; } /** * @brief VCP_Ctrl * Manage the CDC class requests * @param Cmd: Command code * @param Buf: Buffer containing command data (request parameters) * @param Len: Number of data to be sent (in bytes) * @retval Result of the operation (USBD_OK in all cases) */ static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len) { switch (Cmd) { case SEND_ENCAPSULATED_COMMAND: /* Not needed for this driver */ break; case GET_ENCAPSULATED_RESPONSE: /* Not needed for this driver */ break; case SET_COMM_FEATURE: /* Not needed for this driver */ break; case GET_COMM_FEATURE: /* Not needed for this driver */ break; case CLEAR_COMM_FEATURE: /* Not needed for this driver */ break; case SET_LINE_CODING: linecoding.bitrate = (uint32_t)(Buf[0] | (Buf[1] << 8) | (Buf[2] << 16) | (Buf[3] << 24)); linecoding.format = Buf[4]; linecoding.paritytype = Buf[5]; linecoding.datatype = Buf[6]; /* Set the new configuration */ VCP_COMConfig(OTHER_CONFIG); break; case GET_LINE_CODING: Buf[0] = (uint8_t)(linecoding.bitrate); Buf[1] = (uint8_t)(linecoding.bitrate >> 8); Buf[2] = (uint8_t)(linecoding.bitrate >> 16); Buf[3] = (uint8_t)(linecoding.bitrate >> 24); Buf[4] = linecoding.format; Buf[5] = linecoding.paritytype; Buf[6] = linecoding.datatype; break; case SET_CONTROL_LINE_STATE: /* Not needed for this driver */ break; case SEND_BREAK: /* Not needed for this driver */ break; default: break; } return USBD_OK; } /** * @brief VCP_DataTx * CDC received data to be send over USB IN endpoint are managed in * this function. * @param Buf: Buffer of data to be sent * @param Len: Number of data to be sent (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else VCP_FAIL */ static uint16_t VCP_DataTx (void) { if (linecoding.datatype == 7) { APP_Rx_Buffer[APP_Rx_ptr_in] = g_RxByte & 0x7F; } else if (linecoding.datatype == 8) { APP_Rx_Buffer[APP_Rx_ptr_in] = g_RxByte; } APP_Rx_ptr_in++; /* To avoid buffer overflow */ if(APP_Rx_ptr_in == APP_RX_DATA_SIZE) { APP_Rx_ptr_in = 0; } return USBD_OK; } /** * @brief VCP_DataRx * Data received over USB OUT endpoint are sent over CDC interface * through this function. * * @note * This function will block any OUT packet reception on USB endpoint * until exiting this function. If you exit this function before transfer * is complete on CDC interface (ie. using DMA controller) it will result * in receiving more data while previous ones are still not sent. * * @param Buf: Buffer of data received * @param Len: Number of data received (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else VCP_FAIL */ static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len) { for (uint32_t i=0; ireturn USBD_OK; } /** * @brief VCP_COMConfig * Configure the COM Port with default values or values received from host. * @param Conf: can be DEFAULT_CONFIG to set the default configuration or OTHER_CONFIG * to set a configuration received from the host. * @retval None. */ static uint16_t VCP_COMConfig(uint8_t Conf) { return USBD_OK; } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

实现的功能是做一个loopback 测试,只要收到数据立刻发出去。

测试

实际测试下来,波特率设置为 256000bps ,按照 1ms 定时发送,发送:13227744byte 接收:13227744byte 没有丢失数据。

usb 转串口总是被大家认为是不稳定,原因就是在 usb 线拔掉后,串口也随之消失。原来操作系统为串口分配的内存等资源也没有被正确的释放,再将串口线插回去时,会出现打开串口失败!

下面提出操作 USB 转串口的正确方式:

  • 插上 usb 线,打开主机端串口;使用完毕后关闭串口,拔掉 usb 线
  • 插上 usb 线,打开主机端串口;拔掉 usb 线,关闭串口;插上 usb 线,打开串口

失败的方式:

  • 插上 usb 线,打开主机端串口;拔掉 usb 线,插上 usb 线;主机发送数据失败
  • 插上 usb 线,打开主机端串口;拔掉 usb 线,插上 usb 线;关闭串口,打开串口;主机发送数据失败

你可能感兴趣的:(USB,STM32)