Vitis 2023.2使用LWIP配置RTL8211F时出现的问题记录

目录

问题现象

查找原因

猜想验证

解决方案


问题现象

最近把Vivado更新到了2023,SDK工具也更新到了Vitis 2023.2,更新之前的工程后也随之而来的诸多bug,这此遇到的是Vitis例程lwip_echo_server无法配置RTL8211F的问题。

生成DSP以及platform后,直接生成lwip_echo_server模板,测试出现以下问题:

a4e1920baf754d7595740e3e3828bcb8.png

类似的问题在Vivado 2018版本也遇到过,不过那个问题是由于设置了自动协商速度,由于lwip本身的bug所导致,当时设置成固定速度就解决了bug,于是尝试这个方法。

先设置固定连接速度100Mbps:

9d334921f7ef4acca6f98cb55377acec.png

测试发现phy芯片在不停的重连:

ece9d46c7ed24100bf28b6350ac0f510.png

查找原因

首先这个硬件平台在之前的Vivado 2018版本时是可以正常使用lwip_echo_server,因此可以确定不是平台硬件问题,之前通过不使用自动协商临时解决了问题,现在看来只能找到问题的原因了,可以看到出现问题时自动协商速度已经完成了,然后是在phy setup时出现的问题,于是打开获取协商速度的代码:xemacpsif_physpeed.c  准备从这里开始排查

在函数get_Realtek_phy_speed看到了获取速度的代码

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;

	xil_printf("Start PHY autonegotiation \r\n");

	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_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);
		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,IEEE_SPECIFIC_STATUS_REG,
					&status_speed);
	if (status_speed & 0x400) {
		temp_speed = status_speed & IEEE_SPEED_MASK;

		if (temp_speed == IEEE_SPEED_1000)
			return 1000;
		else if(temp_speed == IEEE_SPEED_100)
			return 100;
		else
			return 10;
	}

	return XST_FAILURE;
}

上面串口已经给出了 autonegotiation complete 打印,先给出代码里用到的宏的值:

#define IEEE_STATUS_REG_OFFSET                     1
#define IEEE_SPECIFIC_STATUS_REG                   17

#define IEEE_STAT_AUTONEGOTIATE_COMPLETE           0x0020

#define IEEE_SPEED_MASK                            0xC000
#define IEEE_SPEED_1000                            0x8000
#define IEEE_SPEED_100                             0x4000

检查一下数据手册,至少在读取自动协商状态的代码

3882163b51014e4682a3eabef853ce4e.png

	XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
    //读取寄存PHY芯片器寄存器1数据 

4e0c62db0b0d41c1bfb0387eda8d4f83.png

    //轮询读取此寄存器第5位,此位是速度协商状态位,与数据手册一致   
    while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
		sleep(1);
		timeout_counter++;
		if (timeout_counter == 5) {
			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,IEEE_SPECIFIC_STATUS_REG,
					&status_speed);
	if (status_speed & 0x400) {
		temp_speed = status_speed & IEEE_SPEED_MASK;

		if (temp_speed == IEEE_SPEED_1000)
			return 1000;
		else if(temp_speed == IEEE_SPEED_100)
			return 100;
		else
			return 10;
	}

这里是读取了17号寄存器,也就是0X11寄存器的数据,然后通过且上0x400来获取第10位的数据,再通过且上0xC000来获取14、15位的数据,但是RTL8211F的数据手册里

adec2125dee94e97923f7b7a3a90b105.png

此寄存器时设置网口LED的,这错了十万八千里,这个寄存器的地址应该在0x1A

f2ac391b47194628996580426d185044.png

而且获取连接状态的位在第2位,获取速度的位在第4位和第5位,因此猜测问题就处在这里。

猜想验证

按照这个临时改了一下

	XEmacPs_PhyRead(xemacpsp, phy_addr,0x1a,
					&status_speed);
	if (status_speed & 0x4) {
		temp_speed = status_speed & 0x30;

		if (temp_speed == 0x20)
			return 1000;
		else if(temp_speed == 0x10)
			return 100;
		else
			return 10;
	}

于是问题就被解决了

b92bfe34d20a4eb490e433e52a9bb837.png

正当我疑惑为啥会出现get_Realtek_phy_speed不支持Realtek芯片时,偶然查到了RTL8211竟然分为商业级和工业级,商业级可以看RTL8211E,找到数据手册直接看0x11寄存器,如我所料

f70eeb84c6ad49ffb844367b339b3a6b.png

正是程序里默认的配置,所以lwip213支持了商业级RTL8211,但是还是不支持RTL8211F,这两种芯片可以通过查询PHY_IDENTIFIER_2_REG(0X03)寄存器的Revision Number来判别

 RTL8211F的Revision Number是0110 ,PHY_IDENTIFIER_2_REG是0xC916

b67ba6bc93194cb2adbfc18d6651fd16.png

RTL8211E的Revision Number是0101 ,PHY_IDENTIFIER_2_REG是0xC915

502c45323884499d8ac6f8c651084707.png

解决方案

为了兼容这两种芯片,于是把get_Realtek_phy_speed做以下更改:

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 phy_identity;
	u32_t RetStatus;

    u32_t RTL_SPECIFIC_STATUS_REG;
    u32_t RTL_LINK_STATUS_MASK;
    u32_t RTL_SPEED_MASK;
    u32_t RTL_SPEED_1000;
    u32_t RTL_SPEED_100;
    
    //此处判断是RTL8211F或RTL8211E,根据型号重定义寄存器地址和掩码
    XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_2_REG,
					&phy_identity);
    if (phy_identity == 0XC916) {
	    xil_printf("Start PHY:RTL8211F autonegotiation\r\n");
        RTL_SPECIFIC_STATUS_REG = 0X1A;
        RTL_LINK_STATUS_MASK    = 0x04;
        RTL_SPEED_MASK          = 0x30;
        RTL_SPEED_1000          = 0x20;
        RTL_SPEED_100           = 0x10;
    }
    else if (phy_identity == 0XC915) {
	    xil_printf("Start PHY:RTL8211E autonegotiation\r\n");
        RTL_SPECIFIC_STATUS_REG = 0X0011;
        RTL_LINK_STATUS_MASK    = 0x0400;
        RTL_SPEED_MASK          = 0xC000;
        RTL_SPEED_1000          = 0x8000;
        RTL_SPEED_100           = 0x4000;
    }

	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_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);
		timeout_counter++;
		if (timeout_counter == 5) {
			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,RTL_SPECIFIC_STATUS_REG,
					&status_speed);
	if (status_speed & RTL_LINK_STATUS_MASK) {
		temp_speed = status_speed & RTL_SPEED_MASK;

		if (temp_speed == RTL_SPEED_1000)
			return 1000;
		else if(temp_speed == RTL_SPEED_100)
			return 100;
		else
			return 10;
	}

	return XST_FAILURE;
}

即可

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值