使用官方的freertos+lwip的socket程序,一开始不接网线,程序打印如下信息

Start PHY autonegotiation 
Waiting for PHY to complete autonegotiation.

过一段时间后,程序继续打印如下信息

Auto negotiation error 
Phy setup error 
Assert due to phy setup failure 

然后插入网线,发现程序已无法进行TCP通信。
原因已查明,官方程序在检测热插拔一段时间后如果发现链路一直为断开状态,则lwip将退出主循环并报错。
所以只需要不断检测phy芯片的LINK寄存器,如果发现链路断开,则挂起lwip任务,如果发现链路通畅,此时继续lwip未竟任务即可。
查阅phy芯片手册,如下:
在这里插入图片描述
上图中寄存器地址1的第2个bit表示链路的连接情况,于是在lwip的xemacpsif.c 文件底层函数low_level_init()中做如下修改(第69-86行):

static err_t low_level_init(struct netif *netif)
{
	UINTPTR mac_address = (UINTPTR)(netif->state);
	struct xemac_s *xemac;
	xemacpsif_s *xemacpsif;
	u32 dmacrreg;

	s32_t status = XST_SUCCESS;

	NetIf = netif;
	xemacpsif = mem_malloc(sizeof *xemacpsif);
	if (xemacpsif == NULL) {
		LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
		return ERR_MEM;
	}

	xemac = mem_malloc(sizeof *xemac);
	if (xemac == NULL) {
		LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
		return ERR_MEM;
	}

	xemac->state = (void *)xemacpsif;
	xemac->topology_index = xtopology_find_index(mac_address);
	xemac->type = xemac_type_emacps;

	xemacpsif->send_q = NULL;
	xemacpsif->recv_q = pq_create_queue();
	if (!xemacpsif->recv_q)
		return ERR_MEM;

	/* maximum transfer unit */
#ifdef ZYNQMP_USE_JUMBO
	netif->mtu = XEMACPS_MTU_JUMBO - XEMACPS_HDR_SIZE;
#else
	netif->mtu = XEMACPS_MTU - XEMACPS_HDR_SIZE;
#endif

#if LWIP_IGMP
	netif->igmp_mac_filter = xemacpsif_mac_filter_update;
#endif

#if LWIP_IPV6 && LWIP_IPV6_MLD
 netif->mld_mac_filter = xemacpsif_mld6_mac_filter_update;
#endif

	netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
											NETIF_FLAG_LINK_UP;

#if LWIP_IPV6 && LWIP_IPV6_MLD
	netif->flags |= NETIF_FLAG_MLD6;
#endif

#if LWIP_IGMP
	netif->flags |= NETIF_FLAG_IGMP;
#endif

#if !NO_SYS
	sys_sem_new(&xemac->sem_rx_data_available, 0);
#endif
	/* obtain config of this emac */
	mac_config = (XEmacPs_Config *)xemacps_lookup_config((unsigned)(UINTPTR)netif->state);

	status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
						mac_config->BaseAddress);
	if (status != XST_SUCCESS) {
		xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
	}
	/*   ============== 从这里开始是增加的代码块,用于定时检测链路状态  ============== */
	while(1)
	{
	  unsigned short tmp;
	  //XEmacPs
	  XEmacPs_PhyRead(&xemacpsif->emacps, 1, 1, &tmp);
	  xil_printf("IEEE_STATUS_REG_OFFSET=%d\n",tmp);
	  if(tmp&(0X01<<2))
	  {
	    xil_printf("IEEE_STATUS_REG_OFFSET=%d\n",tmp);
	    break;
	  }
	  else
	  {
	    vTaskDelay(pdMS_TO_TICKS(2000));
	  }
	}
	/* ============== 增加的代码块到此为止 ==============  */
	/* initialize the mac */
	init_emacps(xemacpsif, netif);

	dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
														XEMACPS_DMACR_OFFSET);
	dmacrreg = dmacrreg | (0x00000010);
	XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
											XEMACPS_DMACR_OFFSET, dmacrreg);

#if defined(OS_IS_FREERTOS) && defined(__arm__) && !defined(ARMR5)
	/* Freertos tick is 10ms by default; set period to the same */
	xemac->xTimer = xTimerCreate("Timer", 10, pdTRUE, ( void * ) 1, vTimerCallback);
	if (xemac->xTimer == NULL) {
		xil_printf("In %s:Timer creation failed....\r\n", __func__);
	} else {
		if(xTimerStart(xemac->xTimer, 0) != pdPASS) {
			xil_printf("In %s:Timer start failed....\r\n", __func__);
		}
	}
#endif
	setup_isr(xemac);
	init_dma(xemac);
	start_emacps(xemacpsif);

	/* replace the state in netif (currently the emac baseaddress)
	 * with the mac instance pointer.
	 */
	netif->state = (void *)xemac;

	return ERR_OK;
}

编译后重新运行,该问题即可完全解决。

点击阅读全文
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐