lwip運行一段時間後ping時間延長

原文:http://blog.sina.com.cn/u/2766292570


很多網友在學習LWIP的時候,都遇到過:剛開始ping 設備的時候返回時間都在1ms以下,可是工作了一段時間後,ping返回的時間卻越來越長,甚至達到了超時的程度,通過使用ip tool等抓包工具可以發現,其實是有數據返回的,只不過返回的間隔太久了,有的達到了3000ms以上,可是這已經超出了tcp的數據包間隔要求。一旦出現了這種情況以後,只有通過復位單片機才能恢復,別無他法。我在學習lwip的時候也遇到了這個問題,研究了好幾次,都沒能解決。

後來終於在網上看到了問題的原因:

使用了中斷的方式接收網卡數據包,在每次中斷中只讀取網卡的一個數據包。如果一次中斷髮生,而網卡內事實上可能存在有多個數據包,這樣如果只讀一個,最終導致網卡內數據包積壓,所以會出現ping延遲的現象。如果數據包長期積壓,還可能出現因網卡緩衝區滿而無法接收數據的情況,由於無接收中斷產生,控制器也不會處理積壓數據的現象,從而發生網卡假死的現象,系統無法接收數據。

    這裏的正確解決方法是,在一箇中斷中,需要讀取並處理所有的已經接收的數據包

從網上可以看到,有些比較厲害的網友給出瞭解決方案,就是修改ethernetif.c文件中的ethernetif_input函數,修改後的函數:

 void ethernetif_input( void * pvParameters )
{
struct pbuf *p;
 
for( ;; )
{
if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
TRY_GET_NEXT_FRAGMENT:
p = low_level_input( s_pxNetIf );
if (p != NULL)
{
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
{
pbuf_free(p);
p=NULL;
}
else
{
xSemaphoreTake( s_xSemaphore, 0);
goto TRY_GET_NEXT_FRAGMENT;
}
}  
 
}
}
}
可是我修改了之後,程序啓動之後卻直接崩潰了,這真心難過,好不容易找到了一個解決方案,卻不能用,欲哭無淚啊。心中不免暗想:是不是網友沒有測試過自己的代碼呢?可是給出這種解決方案的不止一個網友,怎麼可能是不能用的呢?於是我掛上了jlink,不調不知道,一條嚇一跳,程序竟然進入了HardFault_Handler函數,崩潰了!很多網友都給出了以上的解決方案,可是卻從沒有人提過還會引入這個問題啊!沒辦法,問題既然出了,就只能想辦法解決。
       經過一番周折之後,發現原來是frame.descriptor->Status = ETH_DMARxDesc_OWN;這條語句引起的。於是查看與它相關的函數調用,最終發現原來問題再這裏:
static struct pbuf * low_level_input(struct netif *netif)
{
  struct pbuf *p, *q;
  u16_t len;
  int l =0;
  FrameTypeDef frame;
  u8 *buffer;
  
  p = NULL;
  frame = ETH_RxPkt_ChainMode();
當總線忙的時候,ETH_RxPkt_ChainMode();返回的frame沒有給frame.descriptor指向一個地址,所以
後面在對這個地址變量賦值的時候就出錯了
 
  frame.descriptor->Status = ETH_DMARxDesc_OWN; 
經過一番刻苦銘心的慘疼,終於找到了問題的癥結,也算是沒有白費這半天功夫。
解決方案:
                 在 frame = ETH_RxPkt_ChainMode();執行之後增加一個判斷,便可解決這個問題
if(frame.length == ETH_ERROR) //總線錯誤,DMA現在忙
{
return p;
}
測試:
       在增加本文修改之前,只要在調試的時候設置斷點,停下來後再運行,ping數據包,返回的時間基本都在幾百毫秒,按照本文修改之後,又可以恢復到1ms以內了。困擾我幾個月的問題,終於在今天得到了解決!
爲了感謝網友的無私奉獻,特記錄今天的修改過程,給出解決方案,如有不對之處,還請指出。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章