打印
[STM32F2]

F205 虚拟串口通信可靠性问题

[复制链接]
2640|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
seawwh|  楼主 | 2016-12-27 14:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
F205 虚拟串口通信可靠性问题

最近在一个项目中,发现F205 USB的虚拟串口向PC机发送长报文的过程中偶尔会失败,主机收到的报文长度不够。为了固定问题,取消了其他代码做了一个简单的测试环境。
  使用 F205 的USB FS 端口做VCP device 与主机通信,程序是使用ST最新库中的Project\USB_Device_Examples\VCP\EWARM 略加修改而成。
通信测试程序十分简单:
  主机通过虚拟串口发送2个字节的长度信息L,F205收到之后发送L长度字节的数据包返回到Host,反复发送统计通信的可靠性。

运行环境: XP, F205版本:STM32F205RGT6 7B494 VQ  PHL  7B 608,F205外部的时钟为 12M,
因此代码中做了相应的修改:
#define HSE_VALUE            12000000  // 配合12M时钟
#define PLL_M                12
#define APP_RX_DATA_SIZE     8192      // 发送缓冲区加大到8K

static uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{
  uint32_t i;
  for (i=0; i<Len; i++) {
    APP_Rx_Buffer[APP_Rx_ptr_in++]=Buf[i];
    if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
      APP_Rx_ptr_in = 0;
  }  
  return USBD_OK;
}

uint8_t  Bu[8192];
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len) {

  uint32_t  Cnt;
  Cnt=Buf[0]+((u16)Buf[1]<<8);  // 收到的长度信息L
  VCP_DataTx( Bu, Cnt);         // 回发数据包
  return USBD_OK;
}

测试发现问题: 当F205发送数据长度为4096以上的时候,有时PC机收数据包长度不够,
沙发
Xflyan| | 2016-12-27 15:27 | 只看该作者
请检查USB相关的 buffer 是否都申请了足够长的空间,包括上位机的

使用特权

评论回复
板凳
huangcunxiake| | 2016-12-27 16:42 | 只看该作者
上位机软件不给力造成的吧

使用特权

评论回复
地板
seawwh|  楼主 | 2016-12-27 22:47 | 只看该作者
上位机使用的是 Delphi 开发的,使用了TMS Async 控件。为了防止是控件的问题,特别将该控件升级到了最新版本。但问题依旧。
工作缓冲的大小,在上位机和F205都开的足够大。

使用特权

评论回复
5
Xflyan| | 2016-12-27 23:26 | 只看该作者
seawwh 发表于 2016-12-27 22:47
上位机使用的是 Delphi 开发的,使用了TMS Async 控件。为了防止是控件的问题,特别将该控件升级到了最新版 ...

那所谓的收取的数据包长度不够是每次固定的还是随机的,发出多少收到多少?如果是固定在具体又丢了多少字节?

使用特权

评论回复
6
玄德| | 2016-12-28 08:44 | 只看该作者

F407,基本完全用库函数,通信可靠性没有问题。

讨厌的是装驱动。

使用特权

评论回复
7
icecut| | 2016-12-28 11:11 | 只看该作者
玄德 发表于 2016-12-28 08:44
F407,基本完全用库函数,通信可靠性没有问题。

讨厌的是装驱动。

我 拍摄 usb 教程的时候,专门讲了 vcp, vcp 代码可靠,没有严重问题.只存在小的兼容性问题
问题是 lz 这么用法根本就是错的....
发送的时候就直接写进缓冲区....
你确定上一包发送完了?
buff 用8k.但是你一次就写4k,你确定下次写的时候上次发送完了?

使用特权

评论回复
8
icecut| | 2016-12-28 11:15 | 只看该作者
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  /* USER CODE END 7 */
  return result;
}

这是我用的 f405的代码.建议你用最新版本 stm32cubemx 生成最新的205的代码,你看看区别...
固定大小 buff 的东西都不能随便扔...
当然上面的代码是原生的,buff 利用率并不够.要改也不是 lz 你那样

使用特权

评论回复
9
玄德| | 2016-12-28 11:39 | 只看该作者
icecut 发表于 2016-12-28 11:11
我 拍摄 usb 教程的时候,专门讲了 vcp, vcp 代码可靠,没有严重问题.只存在小的兼容性问题
问题是 lz 这么 ...


官方库函数会处理packet、frame问题,
一个packet最大64字节,最后一个packet少于64字节,这些处理都做过了。
只要没修改库函数,并且确保缓冲区不溢出,直接往缓冲区填数据是没问题的。


使用特权

评论回复
10
icecut| | 2016-12-28 11:49 | 只看该作者
玄德 发表于 2016-12-28 11:39
官方库函数会处理packet、frame问题,
一个packet最大64字节,最后一个packet少于64字节,这些处理都做 ...

他这不是 usb 的问题 他自己代码有问题

使用特权

评论回复
11
seawwh|  楼主 | 2016-12-28 12:19 | 只看该作者
Xflyan 发表于 2016-12-27 23:26
那所谓的收取的数据包长度不够是每次固定的还是随机的,发出多少收到多少?如果是固定在具体又丢了多少字 ...

目前初步发现出错的规律:

将  APP_RX_DATA_SIZE  设为  8192
发送报文长度固定为 4106,出问题时收到的数据为 4096,缺少10个字节。

使用下面的程序,执行2048次成功发送后出现现问题,每次复位后可以重现。Len=4106
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {

  APP_Rx_ptr_in= (APP_Rx_ptr_in+Len) % APP_RX_DATA_SIZE;
  return USBD_OK;
}

使用下面的程序,每次执行都可以重现问题, Len=4106
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {

  APP_Rx_ptr_in=APP_Rx_ptr_out=4096;
  APP_Rx_ptr_in= (APP_Rx_ptr_in+Len) % APP_RX_DATA_SIZE;
  return USBD_OK;
}

使用下面的程序,极少出错。 Len=4106
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {

  APP_Rx_ptr_in  =Len;
  APP_Rx_ptr_out =0;
  return USBD_OK;
}

注: 上述过程省略了Buf数据复制到APP_Rx_Buffer的过程;
   发送报文4106-4112 的表现均相同。
出错的情况与主机USB端口的忙碌程度好像有关,如果主机正在U盘访问,问题容易出现。

使用特权

评论回复
12
seawwh|  楼主 | 2016-12-28 12:22 | 只看该作者
icecut 发表于 2016-12-28 11:11
我 拍摄 usb 教程的时候,专门讲了 vcp, vcp 代码可靠,没有严重问题.只存在小的兼容性问题
问题是 lz 这么 ...

我的APP_Rx_Buffer的大小为8192,每次写4106。由于每次写都是在上位机的命令下才启动的,
因此不会出现缓冲区溢出的情况。
上位机的重复做下列动作:
     上位机发出读长度4106数据命令,
     F205 收到后按照命令给出的长度后发数据。
     上位机等待接收等待最长时间2秒,接收计数;

使用特权

评论回复
13
Simon21ic| | 2016-12-28 12:26 | 只看该作者
本帖最后由 Simon21ic 于 2016-12-28 12:31 编辑

我记得以前用stm32做MTK的串口下载线,921600bps下,都没啥稳定性问题
我们自己的标准CDC驱动:https://github.com/versaloon/vsf ... e/CDC/vsfusbd_CDC.c
使用流的方式实现数据通道

使用特权

评论回复
14
icecut| | 2016-12-28 12:36 | 只看该作者
你这么测试.每次都从缓冲区开始0处发数,发4106个.
如果这样不出错.就是你代码错误....

使用特权

评论回复
15
seawwh|  楼主 | 2016-12-28 12:56 | 只看该作者
Simon21ic 发表于 2016-12-28 12:26
我记得以前用stm32做MTK的串口下载线,921600bps下,都没啥稳定性问题
我们自己的标准CDC驱动:https://git ...

Simon21ic

  你提供的CDC驱动是PC机一侧的驱动吗?  如果是如何安装这一驱动呢? 你的驱动与Win下的驱动有什么优势?

  另外,你提供的CDC驱动,支持RTS/DTR 等信号的控制与某些控制线的输入中断吗?

使用特权

评论回复
16
Xflyan| | 2016-12-28 14:14 | 只看该作者
本帖最后由 Xflyan 于 2016-12-28 14:15 编辑
seawwh 发表于 2016-12-28 12:19
目前初步发现出错的规律:

将  APP_RX_DATA_SIZE  设为  8192

使用下面的程序,极少出错。 Len=4106
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {
  APP_Rx_ptr_in  =Len;
  APP_Rx_ptr_out =0;
  return USBD_OK;
}

如果这种情况极少出错,那应该就是你的USB取数据时,计数出现错误了
USB发送分两个过程
1、你填充数据到 buffer,修改 APP_Rx_ptr_in
2、USB通过 APP_Rx_ptr_out 与 APP_Rx_ptr_in 相等来判断是否有数据发送,如果有,USB取数据后更新 APP_Rx_ptr_out

如果您填 APP_Rx_ptr_in 没有错,那就是 APP_Rx_ptr_out 更新出错了,导致数据没有完整发送
整个过程跟USB驱动没多大关系,就是你的代码问题

使用特权

评论回复
17
seawwh|  楼主 | 2016-12-28 16:47 | 只看该作者
Xflyan 发表于 2016-12-28 14:14
使用下面的程序,极少出错。 Len=4106
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {
  APP_R ...

回复:Xflyan

使用下面的程序,每次执行都可以重现问题, Len=4106
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {

  APP_Rx_ptr_in=APP_Rx_ptr_out=4096;
  APP_Rx_ptr_in= (APP_Rx_ptr_in+Len) % APP_RX_DATA_SIZE;
  return USBD_OK;
}
可简化为
static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) {

  APP_Rx_ptr_out= 4096;
  APP_Rx_ptr_in = (4096+Len) % APP_RX_DATA_SIZE;
  return USBD_OK;
}
如果说代码有问题的话,其实代码就是上面的两行。
值得注意的是,上面的代码是有意造成了一个 APP_Rx_ptr_out>APP_Rx_ptr_in 的初始条件,
在此条件下,驱动程序会有两段发送过程:
  1. 先发送4096字节,共64包,然后发送0长度包;此时APP_Rx_ptr_out指针到达缓冲区边界;
  2. 发送10字节的数据包。
我感觉在发送数据包较大且在缓冲区中折回的情况下比较容易出错。

使用特权

评论回复
18
Xflyan| | 2016-12-28 17:55 | 只看该作者
seawwh 发表于 2016-12-28 16:47
回复:Xflyan

使用下面的程序,每次执行都可以重现问题, Len=4106

不是这里的代码问题,检查一下你的 USB中断 Callback 的那几个函数,也就是USB从 buffer 取数据的过程

使用特权

评论回复
19
Simon21ic| | 2016-12-28 19:37 | 只看该作者
seawwh 发表于 2016-12-28 12:56
Simon21ic

  你提供的CDC驱动是PC机一侧的驱动吗?  如果是如何安装这一驱动呢? 你的驱动与Win下的驱 ...

stm32里跑的驱动代码,PC端用标准驱动。可以支持其他IO

使用特权

评论回复
20
Rollo| | 2016-12-28 21:33 | 只看该作者
发送的时候就直接写进缓冲区

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

368

帖子

1

粉丝