久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9349|回復: 4
打印 上一主題 下一主題
收起左側

VCP例程用于數據傳輸時丟失數據的處理

[復制鏈接]
跳轉到指定樓層
樓主
ID:98618 發表于 2015-12-19 14:53 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本文作者:Miler Shao
幾天前有個工程師在使用STM32F4芯片的VCP功能時,發現數據接收異常,反映每次上位機發送過來的數據只要超過了64個字節就只收到后面的64字節數據,小于64字節正常。因為只是通過網絡隨便的一個留言,其它信息不詳,但我懷疑其原因可能跟下面的案例類似。

下面的案例是之前ST MCU FAE跟客戶一起經歷過的,并將相關過程和解決方案形成一份文檔并發布出來了。我覺得該案例可能具有一定代表性,并把它轉載過來分享給大家。該方面的文檔在ST MCU中文官網[www.stmcu.com.cn]的設計資源本地化資料部分可以找到。

************************************************************

VCP 例程用于數據傳輸時丟失數據的處理


問題回顧:

某客戶工程師在其產品的設計中,使用了STM32F205VET6。據其工程師講述:他使用 ST 的 USB 固件庫 中的 VCP 例程來實現虛擬串口的功能,但是他發現虛擬串口一次輸出的數據(從串口到上位機)如果 超過 2Kbytes 就會造成數據丟失,只輸出尾部的 2Kbytes。客戶工程師檢查代碼發現 USB 的 FIFO 大小 由宏定義 APP_RX_DATA_SIZE決定,而 APP_RX_DATA_SIZE 的大小剛好為 2Kbytes。所以他認為此FIFO 設計太小而造成的,于是他將 FIFO 的大小改成 5Kbyte,不過修改后并不能解決問題。

調研:

1.打開“STM32F105/7, STM32F2 and STM32F4 USB on-the-go Host and devicelibrary (UM1021)” 庫里邊的 VCP 例程,位于“...\STM32_USB-Host- Device_Lib_V2.1.0\Project\USB_Device_Examples\VCP”中。對其進行測試,并沒有出現所說的問 題,APP_RX_DATA_SIZE 的大小仍然為 2Kbytes,不管傳輸的數據是2Kbytes 還是 5Kbytes 甚至是 25Kbytes,完全沒有問題。


2.了解客戶程序UART 所設置的波特率,為 115200,與原 VCP 例程一致。USB 采用的是 FullSpeed, 全速 USB 總線的幀周期為 1ms。


3.在 usbd_conf.h 中可以看到 APP_RX_DATA_SIZE 的定義在這里,為2048,它定義了 APP_Rx_Buffer 的大小。APP_Rx_Buffer 其實是一個循環緩沖區,APP_Rx_ptr_in 指明了其數據進來的位置,當USART 接收到數據時,將數據存儲于 APP_Rx_ptr_in 指定的位置;APP_Rx_ptr_out指明其數據取出 的位置,當 USB 到 FIFO 中取出數據時,起始地址由 APP_Rx_ptr_out 決定。


4.打開 VCP 項目,觀察其程序通信部分。當 USART 每接收到字節時,進入 EVAL_COM_IRQHandler 函數,

調用 VCP_Tx(0,0)函數,將收到的字節存儲于 APP_Rx_Buffer[APP_Rx_ptr_in]中,在APP_Rx_Buffer 中的位置由 APP_Rx_ptr_in 指定。在VCP_Tx 函數中,

if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)

{

APP_Rx_ptr_in = 0;

}

可以看到當APP_Rx_ptr_in 達到 APP_RX_DATA_SIZE 時,將其置0,也就是在循環緩沖區中繞了一圈回到緩沖區起始地址。


5. 再來看 APP_Rx_Buffer是如何被 USB 取走,并送到上位機的。在 usbd_cdc_core.c中,我們在 usbd_cdc_SOF 函數中看到:

if (FrameCount++ == CDC_IN_FRAME_INTERVAL)

{

FrameCount = 0; Handle_USBAsynchXfer(pdev);

}

可以看到,USB每CDC_IN_FRAME_INTERVAL個幀調用一次 Handle_USBAsynchXfer 到 APP_Rx_Buffer 中去取數據。CDC_IN_FRAME_INTERVAL 同樣定義在 usbd_conf.h 中,全速的時候,其值為5。在定義的這邊,我們可以看到:

APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000should be > CDC_IN_FRAME_INTERVAL

其目的是在于告訴我們APP_RX_DATA_SIZE、MAX_BAUDARATE 和 CDC_IN_FRAME_INTERVAL的關系,以 保證 APP_Rx_Buffer 是夠用不發生溢出。


6.接著看 Handle_USBAsynchXfer函數,同樣,我們可以看到:

if (APP_Rx_ptr_out == APP_RX_DATA_SIZE)

{

APP_Rx_ptr_out = 0;

}

也就是當APP_Rx_ptr_out 達到 APP_RX_DATA_SIZE 時,將其置0,也就是在循環緩沖區中繞了一圈回到緩沖區起始地址。

if (APP_Rx_prt_out == APP_Rx_ptr_in)

{

USB_Tx_State = 0; return;

}

當 APP_Rx_prt_out 趕上 APP_Rx_ptr_in 時,證明 Buffer 里邊的數據已經發送完畢,返回。再往下看:

if(APP_Rx_ptr_out > APP_Rx_ptr_in) /* rollback */

{

APP_Rx_length= APP_RX_DATA_SIZE - APP_Rx_ptr_out; //①

}

else

{

APP_Rx_length= APP_Rx_ptr_in - APP_Rx_ptr_out; //②

}

第1種情況為APP_Rx_ptr_out 比 APP_Rx_ptr_in 大,也就是說APP_Rx_ptr_in 已經繞了一圈,而 APP_Rx_ptr_out 還沒有繞一圈,比如下面情況:


這種情況下:APP_Rx_length 設置為 APP_Rx_ptr_out 當前圈里還剩下數據長度;

第②種情況為 APP_Rx_ptr_in 比APP_Rx_ptr_out 大,也就是 APP_Rx_ptr_in 和APP_Rx_ptr_out 處 于同一圈,于是數據情況比如下面情況:

這種情況下:APP_Rx_length 設置為 APP_Rx_ptr_in 減去 APP_Rx_ptr_out,即當前所有數據長度。程序的后面就是對USB 包的設置,然后發送數據。

7.結合 EVAL_COM_IRQHandler和 Handle_USBAsynchXfer 函數對 APP_Rx_Buffer的處理,我們可以發現, 有一種情況在程序中是沒有做處理的:

當 APP_Rx_ptr_in 繞了一圈回來,并追上 APP_Rx_ptr_out 時,這個時候,若 USART 繼續接收到數據,APP_Rx_ptr_in 指針繼續增長, 就會造成新來的數據沖掉還沒被 USB 取走的舊數據。但是,目前ST官方提供的USB 庫的 VCP 例程是實時的。USART 收進來,USB 就會取走送到上位機。而 且USB 將數據送往上位機 的速率是大于 USART 接收數據的速率的。換言之,它是不會發生這種情況的.

之前所分析的:

APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000should be > CDC_IN_FRAME_INTERVAL 這個要求,正是保證APP_Rx_Buffer 安全的重要條件。

8.至此,我們懷疑客戶并不是照搬VCP 例程,而是對其做了修改。拜訪客戶,了解到確實如此。客戶由于其應用需要,將 VCP 程序拆成兩部分,先是用 USART 把所有的數據接收進來,放到 RAM 中,然 后再將數據送到 APP_Rx_Buffer,由 USB 將數據送往上位機。這樣,問題就來了,由于客戶 USART 先從外部接收到并保存于RAM 的數據大于 5Kbytes,而 CPU 將 RAM 中的數據搬往 APP_Rx_Buffer的 速率遠大于 USB 將 APP_Rx_Buffer 送往上位機的速率。這樣就造成了APP_Rx_ptr_in 繞了一圈回來 追上 APP_Rx_ptr_out并造成溢出的情況,甚至可能是 APP_Rx_ptr_in 繞了幾圈,而 APP_Rx_ptr_out 卻還未開始動,因為 USB 每 CDC_IN_FRAME_INTERVAL*1ms 才送一次數據。

9.建議客戶修改其程序,在將數據從 RAM 中搬往 APP_Rx_Buffer 的時候,不能采用原 VCP 例程中 USART 一樣的操作方式,也就是存一個字節到 APP_Rx_Buffer,APP_Rx_ptr_in 指針加 1,并繞圈。 新的程序需要在此基礎上判斷,當 APP_Rx_ptr_in 指針加1 后,若等于 APP_Rx_ptr_out,置 “APP_Rx_Buffer 滿”標志位,并停止將 RAM 中的數據搬往 APP_Rx_Buffer。等 USB 從 APP_Rx_Buffer 中取走數據,再清“APP_Rx_Buffer 滿”標志位,允許將 RAM 中的數據繼續搬往 APP_Rx_Buffer。

10.客戶修改程序,問題解決。

結論:

修改 VCP 例程時,沒有對 APP_Rx_Buffer 的操作有足夠的了解,造成在其特定應用中產生了數據溢出問題。

處理:

在將數據存入APP_Rx_Buffer 時,對 APP_Rx_ptr_in 指針在循環緩沖區中繞一圈回來后,是否會追上APP_Rx_ptr_out 指針進行監控,以避免數據溢出。

建議:

在對例程進行修改用來供自己的應用使用的時候,我們不僅需要把接口看清楚,更需要把參考例程的原理流程應用背景看明白。

=============================================================

后記:上面文檔分析得詳細,看懂了原理就好。整個過程可以抽象為一個生活實例。有個池子,一邊給池子里進水,一邊取水,做到不溢出就好。如果進水快,取水慢,中途不做任何監控處理的話,池子再大也有溢出的時候。結合上面案例,存放數據指針折回并追上取出數據指針時就是溢出臨界點,此時緩沖區里全是待取走的數據,如果此時又來新數據自然出現覆蓋問題

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:185829 發表于 2017-4-3 20:12 | 只看該作者
注意的要點問題很重要
回復

使用道具 舉報

板凳
ID:185829 發表于 2017-4-3 20:13 | 只看該作者
臨界點的判斷是非0?
回復

使用道具 舉報

地板
ID:224453 發表于 2019-8-23 09:25 | 只看該作者
最終是如何解決的
回復

使用道具 舉報

5#
ID:224453 發表于 2019-8-23 14:02 | 只看該作者
該問題已經解決 保證out始終不與in相等,假如套圈那就while等待一下,確保out 發送成功 再去填充buff
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 黄色毛片在线播放 | 成人a视频 | 久久久久成人精品亚洲国产 | 久久亚洲春色中文字幕久久久 | 国产精品久久在线 | 日本又色又爽又黄的大片 | 日韩一区二区视频 | 亚洲三区视频 | 免费看黄视频网站 | 二区三区视频 | 国产精品久久久久久久久久久免费看 | 日韩专区中文字幕 | 欧美视频三区 | 日韩精品成人一区二区三区视频 | 国产国语精品 | 国产精品毛片一区二区三区 | 国产清纯白嫩初高生视频在线观看 | 国产精品美女久久久久久久久久久 | 亚洲国产成人精品女人久久久 | 国产视频精品区 | 黄色片网站国产 | 国产第一页在线观看 | 日韩中文一区二区三区 | 九九热在线视频 | 国产精品日产欧美久久久久 | 日韩精品极品视频在线观看免费 | 天天干天天玩天天操 | 欧美 日韩 在线播放 | 国产成都精品91一区二区三 | 久久久精 | 国产男女猛烈无遮掩视频免费网站 | 亚洲成人精品 | 国产综合视频 | 99国产精品99久久久久久粉嫩 | 亚洲最新网址 | 黄色免费网站在线看 | 亚洲一区二区三区四区五区午夜 | 日本一区二区三区四区 | 99久久夜色精品国产亚洲96 | 国产精品成人一区二区 | 在线精品观看 |