stm32+lwip動態鏈路處理!!!
研究了好幾天stm32+lwip動態鏈路的處理方法,發現大多是寫一些lwip移植,tcp/ip移植之類的東西,沒有與實際項目相關的內容,今天發些乾貨,說說這些天stm32+lwip+ucosii實際項目的一些問題:
1,怎麼實現系統網線的熱插拔?
以我的項目爲例,PHY爲lan8720a。首先要介紹一個重要的函數---GET_PHY_LINK_STATUS();
其實這個函數就是一個宏,用於讀取lan8720a的一個寄存器來查看網線連接狀態,返回值爲0x04爲連接狀態,0 未連接。
1 |
|
物理層初始化部分,這樣處理
物理層包括LAN8720a和stm32 eth DMA+MAC。系統初始化的時候不要初始化MAC和DMA
1 void LAN8720_Init(void) 2 { 3 /*打開該打開的時鐘*/ 4 /*網絡引腳設置 RMII接口 初始化 不寫了。。。。*/ 5 LAN8720_RST=0; //硬件復位LAN8720 6 delay_ms(50); 7 LAN8720_RST=1; //復位結束 8 ETHERNET_NVICConfiguration(); //設置中斷優先級 9 ETH_MACDMA_Config(); 10 } 11 12 void ETH_MACDMA_Config(void) 13 { 14 // u8 rval; 15 //使能以太網MAC以及MAC接收和發送時鐘 16 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx, ENABLE); 17 ETH_DeInit(); //AHB總線重啓以太網 18 ETH_SoftwareReset(); //軟件重啓網絡 19 while (ETH_GetSoftwareResetStatus() == SET);//等待軟件重啓網絡完成 20 // rval = MAC_DMA_Init(); 這些就不在這初始化了 21 // return rval; 22 } 23 u8 MAC_DMA_Init(void) 24 { 25 u8 rval; 26 ETH_StructInit(Ð_InitStructure); //初始化網絡爲默認值 27 ///網絡MAC參數設置 28 ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable; //開啓網絡自適應功能 29 ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable; //關閉反饋 30 ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable; //關閉重傳功能 31 ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable; //關閉自動去除PDA/CRC功能 32 ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable; //關閉接收所有的幀 33 ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//允許接收所有廣播幀 34 ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable; //關閉混合模式的地址過濾 35 ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;//對於組播地址使用完美地址過濾 36 ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; //對單播地址使用完美地址過濾 37 #ifdef CHECKSUM_BY_HARDWARE 38 ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; //開啓ipv4和TCP/UDP/ICMP的幀校驗和卸載 39 #endif 40 //當我們使用幀校驗和卸載功能的時候,一定要使能存儲轉發模式,存儲轉發模式中要保證整個幀存儲在FIFO中, 41 //這樣MAC能插入/識別出幀校驗值,當真校驗正確的時候DMA就可以處理幀,否則就丟棄掉該幀 42 ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; //開啓丟棄TCP/IP錯誤幀 43 ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable; //開啓接收數據的存儲轉發模式 44 ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable; //開啓發送數據的存儲轉發模式 45 46 ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable; //禁止轉發錯誤幀 47 ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable; //不轉發過小的好幀 48 ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable; //打開處理第二幀功能 49 ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; //開啓DMA傳輸的地址對齊功能 50 ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable; //開啓固定突發功能 51 ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat; //DMA發送的最大突發長度爲32個節拍 52 ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat; //DMA接收的最大突發長度爲32個節拍 53 ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1; 54 rval=ETH_Init(Ð_InitStructure,LAN8720_PHY_ADDRESS); //配置ETH 這一步 如果網線沒插 會等很長時間 55 if(rval==ETH_SUCCESS)//配置成功 56 { 57 ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE); //使能以太網接收中斷 58 } 59 return rval; 60 }
是時候編寫鏈路動態處理函數了:
1 void CableLink_changed(void *pdata) 2 { 3 u8 Cable_state = 0;//初始化網線沒插 4 u8 Link_state = 0; //網線連接狀態 中間變量 5 u8 Link_mode = WorkMode;//開啓DHCP了嗎 6 Link_state=GET_PHY_LINK_STATUS(); //先檢測了一次 7 if(Link_state==0x04) Cable_state = 1; //網線連接了 Cable_state 置 1 8 while(1) 9 { 10 Link_state = GET_PHY_LINK_STATUS();//檢測了網線連接 11 if((Link_state == 0)&&(Cable_state == 1)) //網線斷開了(以前是連接着的) 12 { 13 Cable_state = 0; 14 netif_set_link_down(&lwip_netif); 15 if(Link_mode == LINK_DHCP) 16 { 17 lwipdev.dhcpstatus = DHCP_LINK_DOWN; 18 #if LWIP_DHCP 19 dhcp_stop(&lwip_netif); 20 #endif 21 } 22 LCD_ShowString(400,30,60,20,12," "); 23 LCD_ShowString(400,30,60,20,12,"LINK Down"); 24 } 25 if((Link_state == 0x04)&&(Cable_state == 0))//網線重新連上了 26 { 27 Cable_state = 1; 28 MAC_DMA_Init(); //重新配置MAC和DMA 甭管是第一次 還是第N次 都要重新配置一次 29 if(Link_mode == LINK_STATIC) //靜態IP 30 { 31 IP4_ADDR(&(lwip_netif.ip_addr),lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); 32 IP4_ADDR(&(lwip_netif.netmask),lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]); 33 IP4_ADDR(&(lwip_netif.gw),lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); 34 netif_set_link_up(&lwip_netif); 35 OSSemPost(Comm_Dis);//這裏 只在靜態IP 釋放信號 因爲DHCP任務中會釋放 給顯示任務發信號 36 } 37 else //開啓了DHCP 38 { 39 IP4_ADDR(&(lwip_netif.ip_addr),0,0,0,0);//這幾步很重要 40 IP4_ADDR(&(lwip_netif.netmask),0,0,0,0);//當網絡環境發生變化 比如路由器dhcp允許分配的IP發送變化或者系統網線插到別的路由器了 41 IP4_ADDR(&(lwip_netif.gw),0,0,0,0); //重新開啓了dhcp_start(&gnetif),會重新分配IP,不然申請不下來 42 lwip_netif.flags |= NETIF_FLAG_LINK_UP; //關於這裏,感覺只用把NETIF_FLAG_LINK_UP置一就行了,開啓dhcp_start後,隨後會調用 43 //netif_set_link_up(&lwip_netif); //netif_set_up() 來刷存在感 44 lwip_comm_dhcp_Resume(); //開啓dhcp管理任務 45 } 46 LCD_ShowString(400,30,60,20,12," "); //dchp 打開 47 LCD_ShowString(400,30,60,20,12,"LINK ON"); //dchp 打開 48 } 49 delay_ms(500); 50 } 51 }
這是一個ucos任務,差不多 1秒執行2次。
這樣就可以處理動態連理的情況了。
2 靜態IP情況下系統上電刷兩次存在感?
先上圖:
會有兩個Gratutious arp request,一個mac是02:00:00:2a:00:2a 一個是02:00:00:42:00:42 而且他們一個是16進制 1個是十進制。他們都是系統發出的嗎?
我查看了好多文檔,仿真查看寄存器,都不知道爲什麼,無意中我發現了路由器中的靜態arp綁定設置。
原來是當初手賤綁定了。
正在試驗階段,寫的比較粗糙。將就看吧。
懶惰不會讓你一下子跌到 但會在不知不覺中減少你的收穫; 勤奮也不會讓你一夜成功 但會在不知不覺中積累你的成果 越努力,越幸運。