米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

1.问题描述

本人使用的vivado版本时2019.1,此版本中的lwip版本为lwip211V1.0,虽然代码中已经有关于Realtek芯片的识别定义,但是点击自动识别还是显示phy setup error,借鉴了米联官方的改库教程之后终于成功解决自适应速度的问题。


2.未改库之前的自适应程序运行结果:

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

3.改库的步骤:
 

首先右键工程对应的BSP工程,点击board support package settings,然后勾选LWIP211_v_1_0,

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

 

然后选择Overview->standalone->lwip211,将temac_adapter_options中phy_link_ speed改为Autodetect。

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题
返回对应的BSP工程,找到libsrc下的lwip211_v1_0,在其中找到xmacpsif _physpeed.c文件

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

 

将原有的get_Realtek_phy_speed函数全部注释或者删除,更换为米联提供的代码:

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

 

 

然后保存文件,BSP会自动进行编译。改库即可成功。

 

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

改库之后可以成功运行:

米联ZYNQ7Z020系列的以太网网口芯片RTL8211FD自适应速度的问题

 

改库的代码如下:

static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{
        u16_t temp;
        u16_t control;
        u16_t status;
        u16_t status_speed;
        u32_t timeout_counter = 0;

        xil_printf("Start PHY autonegotiation \r\n");
        XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
        XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
        control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
        XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);

        XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
        XEmacPs_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_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
        XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
                        &control);
        control |= (7 << 12); /* max number of gigabit attempts */
        control |= (1 << 11); /* enable downshift */
        XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
                        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;
                else
                        break;
        }
        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);
                XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);
                timeout_counter++;
                if (timeout_counter == 30)
                {
                        xil_printf("Auto negotiation error \r\n");
                        return 0;
                }
                XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
        }
        xil_printf("autonegotiation complete \r\n");
        XEmacPs_PhyRead(xemacpsp, phy_addr,0x1A, &status_speed);
        if ( (status_speed & 0x30) == 0x20)/* 1000Mbps */
                return 1000;
        else if ( (status_speed & 0x30) == 0x10)/* 100Mbps */
                return 100;
        else if ( (status_speed & 0x30) == 0x00)/* 10Mbps */
                return 10;

        return XST_FAILURE;
}