每一个PHY芯片都是一个拦路虎,不管是硬件还是软件。上次说到KSZ,这次我们来说说RTL8211这个芯片。
硬件设计
设计同样是参考的开发板上的设计,硬件设计同样是有问题的。这次的是参考的小梅哥的设计,先看下图:
我们关注一下这里的两个网口灯的电路设计。按照此电路设计,在最后驱动的时候,当不插网线的时候,以太网连接器上的黄色灯常亮,也就是这里的LED2驱动的灯。可以看到是因为这里有个ETH_DVDDH
的电源。
那么我们看下芯片的数据手册上的设计:
说的很明确,针对上拉和下拉的pin脚,外接LED时的电路是不一样的。因此需要改正,我们重新修改电路后,两个灯就正常了。改正如下:
软件驱动
这里我主要关注的是怎么控制LED灯的状态,所以先来看下几个LED的工作状态:
上面这张图,列举出来RTL8211支持的3个LED灯,每个灯都可以支持Link
指示或者Active
指示。但是我们设计中使用了其中的两个,即LED1
和LED2
。
通常来说,网络的连接状态我们需要一个常量的灯来指示,当网线插上时应该有一个常量的灯来指示已连接;当有数据交互的时候应该有一个灯闪烁来指示有数据在传输。
在我们设计中,定义LED1为连接指示灯(绿色);LED2为数据传输指示灯(黄色)。所以我们的工作就是配置寄存器,使这两个灯工作在其正确的状态。
上图中的红框中的内容是最重要的,它告诉我们怎么去配置寄存器,来实现我们的目的。这个不需要分析了。
直接来看寄存器配置吧
LED_MODE
:1 关于这里MODE的配置,建议去看一下手册中的MODEA和MODEB对比一下。
LED2_ACT
:1 上面已经定义了LED2是用来指示数据传输的,也就是用来闪烁的,所以这里使能
LED2_LINK_1000
:0 LED2的功能是ACT,所以这里的LINK就不使能了
RSVD
:0 预留的直接为0
LED2_LINK_100
:0 LED2的功能是ACT,所以这里的LINK就不使能了
LED2_LINK_10
:0 LED2的功能是ACT,所以这里的LINK就不使能了
LED1_ACT
:0 LED1的功能是LINK,所以这里的ACT就不使能了
LED1_LINK_1000
:1 LED1的功能是LINK,所以这里的LINK使能
RSVD
:0 预留的直接为0
LED1_LINK_100
:1 LED1的功能是LINK,所以这里的LINK使能
LED1_LINK_10
:1 LED1的功能是LINK,所以这里的LINK使能
以下LED0的功能都不需要使用的,都默认为0。这里配置需要注意的是:比如配置LED1为LINK功能的时候,它里面有各个速率下的配置,我们都要同时使能,而且,同一个LED不要配置成不同的功能,这样很难分辨。
还有个需要关注的点就是配置节能模式Engrgy-efficient Ethernet,节能以太网:
根据手册上描述和实际测试,当节能模式设置为1时,灯会间歇性闪烁,因此实际使用中要把对应的LED的节能模式对应位配置为0,即不开启节能模式。建议所有的都直接关掉,因为看网上说是有问题的
示例代码
static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t control;u16_t status;u16_t status_speed;u32_t timeout_counter = 0;u32_t temp_speed;u16_t led_mod;xil_printf("Start PHY autonegotiation \r\n");xil_printf("This is a realtek phy \r\n");//开灯
#if 1XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0D04);XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x11, 0x0000);XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0000);
#endif#if 1XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0D04);//XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x10, 0x617F);XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x10, 0xC160);XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0000);#endif
#if 0//led control registerXEmacPs_PhyWrite(xemacpsp, phy_addr, 31,0x0d04);XEmacPs_PhyRead(xemacpsp, phy_addr, 16, &led_mod);//led_mod &= 0x7FFF;//LED Mode A//led_mod |= 0x4100;//led_mod = 0xC160;xil_printf("led_mod is :%x \r\n",led_mod);XEmacPs_PhyWrite(xemacpsp, phy_addr, 16,led_mod);XEmacPs_PhyWrite(xemacpsp, phy_addr, 31,0);
#endifXEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);control |= IEEE_ASYMMETRIC_PAUSE_MASK;control |= IEEE_PAUSE_MASK;control |= ADVERTISE_100;control |= ADVERTISE_10;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,&control);control |= ADVERTISE_1000;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;control |= IEEE_STAT_AUTONEGOTIATE_RESTART;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_RESET_MASK;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);while (1) {XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);if (control & IEEE_CTRL_RESET_MASK)continue;elsebreak;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);xil_printf("Waiting for PHY to complete autonegotiation.\r\n");while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {sleep(1);timeout_counter++;xil_printf("attempt counters %d \r\n",timeout_counter);if (timeout_counter == 30) {xil_printf("Auto negotiation error \r\n");return XST_FAILURE;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);}xil_printf("autonegotiation complete \r\n");XEmacPs_PhyRead(xemacpsp, phy_addr,26,&status_speed);//if (status_speed & 0x400) {// temp_speed = status_speed & IEEE_SPEED_MASK;if(status_speed & 0x04){if((status_speed & 0x20) == 0x20)return 1000;else if((status_speed & 0x10) == 0x10)return 100;elsereturn 10;}//else if((status_speed & 0x10) == 0x10)// return 100;// if (temp_speed == IEEE_SPEED_1000)// return 1000;// else if(temp_speed == IEEE_SPEED_100)// return 100;// else// return 10;//}return XST_FAILURE;
}