stm32+lwip動態鏈路處理!!!

stm32+lwip動態鏈路處理!!!

研究了好幾天stm32+lwip動態鏈路的處理方法,發現大多是寫一些lwip移植,tcp/ip移植之類的東西,沒有與實際項目相關的內容,今天發些乾貨,說說這些天stm32+lwip+ucosii實際項目的一些問題:

1,怎麼實現系統網線的熱插拔?

 以我的項目爲例,PHY爲lan8720a。首先要介紹一個重要的函數---GET_PHY_LINK_STATUS();

 其實這個函數就是一個宏,用於讀取lan8720a的一個寄存器來查看網線連接狀態,返回值爲0x04爲連接狀態,0 未連接。

1

#define GET_PHY_LINK_STATUS() (ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & 0x00000004)

 物理層初始化部分,這樣處理

 物理層包括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(&ETH_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(&ETH_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綁定設置。

原來是當初手賤綁定了。

 正在試驗階段,寫的比較粗糙。將就看吧。

懶惰不會讓你一下子跌到 但會在不知不覺中減少你的收穫; 勤奮也不會讓你一夜成功 但會在不知不覺中積累你的成果 越努力,越幸運。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章