TCPIP协议学习(三)STM32中ETH驱动配置注意事项
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直接发送第⼆个帧,不需要之前帧回复
tcpip协议pdf/*------------------------ 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⽂件的修改
参见设置
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论