1.MII/RMII/SMI接口連接和配置
SMI又稱站點管理接口,用於cpu與外置PHY芯片通訊,配置相關參數,包含MDC和MDIO兩個管腳(CPU上有對應引腳,當然用普通GPIO口模擬SMI管理也是可行的,不過按照固定時序寫入和讀取數據)。‘
MII和RMII則是是兩種不同的以太網數據傳輸接口,因為RMII在使用更少接口的情況下具有MII相同的功效,其中MII如下圖連接即可:

特別注意:RMII模式下REF_CLK要連接CPU的MCO引腳,且MCO輸出時鍾應為50MHz。
這里說下我最近遇到的stm32在MII模式不能正常接收數據,后來發現是STM的MII_ER腳被配置成以太網引腳,而實際懸空(並未連接到PHY),導致stm32認為接收出錯,將接收數據丟失。
解決辦法: 如果硬件還未完成設計,則MII_ER最好正確連接到PHY指定端口,可以提前過濾mac子層檢測到的錯誤包。
如果硬件設計已經完成,且出錯,那么就取消MII_ER引腳的配置即可(帶來的后果就是少一層錯誤過濾,問題不大)
2.PHY初始化
一般來說,stm32外部驅動PHY芯片有兩種連接方式,MII和RMII總線,這個與硬件設計有關,不過stm32芯片一般都支持這兩種總線連接方式,因為RMII總線在傳輸效果不變的情況下占用接口更少,因此一般推薦RMII方式.
以DP83848芯片為例:

從上面可以看出RMII總線對應的輸入時鍾要設置為50MHZ, 當然這與你原理圖的布線有,連接PHY芯片X1接口對應GPIO接口的外設區域時鍾就要設定為該值,
考慮到掛在同區域外設的時鍾要求.為了方便設計,對於stm32f207vet6(我用的芯片),將系統時鍾從120MHz改為100MHz,該區域外設時鍾設置為1/2即可。
對於stm32f107vc則需要通過PLL3將MCO端口時鍾拉高到50Mhz輸出到phy。目前來說大部分人對於stm32驅動的移植都是直接把官方例程拿過來用,
但我建議還是對照參考手冊仔細研讀每一項,自己配置ETH參數,因為stm32芯片集成的MAC配置對於數據的接收和發送影響很大。
ETH_DeInit(); /* Software reset */ ETH_SoftwareReset(); /* Wait for software reset */
while (ETH_GetSoftwareResetStatus() == SET); /* ETHERNET Configuration---------------------------------------------*/
/* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */ ETH_StructInit(Ð_InitStructure); /* Fill ETH_InitStructure parametrs */
/*------------------------ ETH_MACCR-----------------------------------*/
//參數是否自動配置,選擇disable需要自動配置默認參數
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable; ETH_InitStructure.ETH_Watchdog = ETH_Watchdog_Disable; //關閉看門狗定時器,允許接收超長幀
ETH_InitStructure.ETH_Jabber = ETH_Jabber_Disable; //關閉jabber定時器,允許發送超長幀
ETH_InitStructure.ETH_InterFrameGap = ETH_InterFrameGap_40Bit; //發送幀間間隙
ETH_InitStructure.ETH_Speed = ETH_Speed_100M; //快速以太網速度
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable; //不啟用自循環模式
ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex; //全雙工模式
/*自動填充/CRC剝離處理不執行,轉發所有幀*/ ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable; #if CHECKSUM_BY_HARDWARE ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; //IPV4頭文件硬件校驗
#endif
/*------------------------ ETH_MACFFR----------------------------------*/ ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable; //MAC過濾只接受通過源目的地址的數據
ETH_InitStructure.ETH_SourceAddrFilter = ETH_SourceAddrFilter_Normal_Enable; //MAC過濾源地址錯誤幀?
ETH_InitStructure.ETH_PassControlFrames = ETH_PassControlFrames_BlockAll; //MAC不轉發任何控制幀
ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable; //接收廣播幀
ETH_InitStructure.ETH_DestinationAddrFilter = ETH_DestinationAddrFilter_Normal; //目的地址過濾結果正常
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable; //混雜模式,啟用幀過濾
ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect; //過濾器正常工作,不傳送控制幀
ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; //單播幀目的地址完美過濾
/*------------------------ DMA ETH_DMAOMR -----------------------------------*/
/* When we use the Checksum offload feature, we need to enable the Store and Forward mode: the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum, if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
/*丟棄校驗錯誤幀不執行(因為未進行硬件校驗)*/ ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Disable; ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Disable; //接收數據超過閾值轉發
ETH_InitStructure.ETH_FlushReceivedFrame = ETH_FlushReceivedFrame_Enable; //描述符被占用和接收FIFO不可用時清空FIFO(解決堵塞)
ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Disable; //發送數據完整幀轉發
ETH_InitStructure.ETH_TransmitThresholdControl = ETH_TransmitThresholdControl_64Bytes; //發送閾值為64Bytes
ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable; //接收FIFO丟棄所有錯誤幀
/*接收FIFO上傳長度不夠的好幀*/
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Enable;
ETH_InitStructure.ETH_ReceiveThresholdControl = ETH_ReceiveThresholdControl_64Bytes; //接收閾值為64Bytes
ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable; //DMA直接發送第二個幀,不需要之前幀回復
/*------------------------ DMA ETH_DMABMR -----------------------------------*/ ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; //傳輸地址對齊
ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable; //固定的突發
ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat; ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat; ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1; //發送和接收比例 2:1
/* Configure Ethernet */ ETH_Init(Ð_InitStructure, DP83848_PHY_ADDRESS); /* Enable the Ethernet Rx-Tx Interrupt*/ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T
, ENABLE);
特別注意:以太網底層部分我主要遇到的bug有兩個
(1).啟動時需要插上網線,否則啟動后以太網工作不正常 問題原因:
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable; //開啟PHY的自適應
如果開啟了自適應(默認代碼是Enable,這就是坑的地方),ETH_Init中會有下面一段
do { timeout++; } while (!(ETH_ReadPHYRegister(PHYAddress, PHY_BSR) & PHY_Linked_Status) && (timeout < PHY_READ_TO)); /* Return ERROR in case of timeout */ if(timeout == PHY_READ_TO) { return ETH_ERROR; }
也就是說一段時間沒有讀到link狀態,就跳出ETH的配置函數了,這也就導致了stm的eth模塊直接沒有初始化(phy即使配置失敗或者不配置也會根據外部引腳有默認的配置), 然而stm的官方庫卻直接跳出,不得不說是很嚴重的bug。
解決辦法: 將ETH_AutoNegotiation_Enable改為ETH_AutoNegotiation_Disable, 根據實際情況配置即可。
(2) 網絡有丟包和卡頓
這個問題其實是上述問題解決后衍生的問題,因為產品更換過幾次phy,用的同一套驅動,結果有的工作正常,有的雖然能工作,但又大數量的丟包。
后來測試發現,更換phy后,不同phy的設置寄存器有差異, 出問題的寫入出錯,而默認配置與stm32內部不一致,導致丟包。解決問題發現如果不細致維護ETH_Init這個庫函數中讀寫寄存器部分,適配PHY在軟件上解決很麻煩,不過在對比了幾家phy的說明書后,通過硬件修改配置引腳高低,可以輕松完成stm32與PHY的適配。
解決辦法: 完全注釋掉ETH_Init中與phy相關的配置,通過外部引腳硬件完成與stm適配,目前測試有dp83848, ip101alf, ip101gr, RTL8201等phy芯片都完美運行。
3.lwip中lwipopt.h文件的修改
