xilinx zynq的lwip的官方例程解析

20181025  vivado2016.4  sdk

花了两天时间看的,总算是看懂了一点,不过主要看的是以太网怎样接收数据和发送数据的,其他的还不是很懂,将看懂的记录下,给需要的人一点参考。

这个官方例子应该是通过以太网中断接收数据,并且回传接收的数据。这里timer中断的作用还没看明白。

不用看懂所有代码,只需要看有注释的地方。没几句,看着很简单,但是自己去看程序的时候就没那么顺利。拿来主义是最简单的,自己看这些,太花时间。以前拿来的太多,还是多还点吧。

main函数之前都是库的调用和通用配置就不讲了

int main()
{
	struct ip_addr ipaddr, netmask, gw;

	/* the mac address of the board. this should be unique per board */
	unsigned char mac_ethernet_address[] =
	{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };

	echo_netif = &server_netif;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
	ProgramSi5324();
	ProgramSfpPhy();
#endif
#endif

/* Define this board specific macro in order perform PHY reset on ZCU102 */
#ifdef XPS_BOARD_ZCU102
	IicPhyReset();
#endif

	init_platform();//timer中断初始化

init_platform()函数原型  在platform_zynq.c中

main函数
#if LWIP_DHCP==1
    ipaddr.addr = 0;
	gw.addr = 0;
	netmask.addr = 0;
#else
	/* initliaze IP addresses to be used */
	IP4_ADDR(&ipaddr,  192, 168,   1, 10);
	IP4_ADDR(&netmask, 255, 255, 255,  0);
	IP4_ADDR(&gw,      192, 168,   1,  1);
#endif	
	print_app_header();

	lwip_init();

  	/* Add network interface to the netif_list, and set it as default */
//最重要,以太网中断函数在这里指定
	if (!xemac_add(echo_netif, &ipaddr, &netmask,//引用xemacpsif_init()函数,引用以太网的中断函数
						&gw, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}

选中xemac_add函数鼠标右击选择Open Declaration,可以查看xemac_add

/*
 * xemac_add: this is a wrapper around lwIP's netif_add function.
 * The objective is to provide portability between the different Xilinx MAC's
 * This function can be used to add both xps_ethernetlite and xps_ll_temac
 * based interfaces  xemacpsif_init
 */
struct netif *
xemac_add(struct netif *netif,
	struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw,
	unsigned char *mac_ethernet_address,
	unsigned mac_baseaddr)
{
	int i;

	/* set mac address */
	netif->hwaddr_len = 6;
	for (i = 0; i < 6; i++)
		netif->hwaddr[i] = mac_ethernet_address[i];

	/* initialize based on MAC type */
		switch (find_mac_type(mac_baseaddr)) {
			case xemac_type_xps_emaclite:
#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
				return netif_add(netif, ipaddr, netmask, gw,
					(void*)mac_baseaddr,
					xemacliteif_init,
#if NO_SYS
					ethernet_input
#else
					tcpip_input
#endif
					);
#else
				return NULL;
#endif
			case xemac_type_axi_ethernet:
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
				return netif_add(netif, ipaddr, netmask, gw,
					(void*)mac_baseaddr,
					xaxiemacif_init,
#if NO_SYS
					ethernet_input
#else
					tcpip_input
#endif
					);
#else
				return NULL;
#endif
#if defined (__arm__) || defined (__aarch64__)
			case xemac_type_emacps://执行的是这个case
				xil_printf("xemacpsif_init11\n\r");
#ifdef XLWIP_CONFIG_INCLUDE_GEM
				xil_printf("xemacpsif_init22\n\r");
				return netif_add(netif, ipaddr, netmask, gw,
						(void*)(UINTPTR)mac_baseaddr,
						xemacpsif_init,//以太网中断初始化在这个函数里
#if NO_SYS
						ethernet_input
#else
						tcpip_input
#endif

						);
#endif
#endif
			default:
				xil_printf("unable to determine type of EMAC with baseaddress 0x%08x\r\n",
						mac_baseaddr);
				return NULL;
	}
}

选中xemacpsif_init函数鼠标右击选择Open Declaration,可以查看xemacpsif_init

/*
 * xemacpsif_init():
 *
 * Should be called at the beginning of the program to set up the
 * network interface. It calls the function low_level_init() to do the
 * actual setup of the hardware.
 *应该在程序开始时调用来设置网络接口。 它调用函数low_level_init()来进行硬件的实际设置。
 */

err_t xemacpsif_init(struct netif *netif)
{
#if LWIP_SNMP  //LWIP_SNMP=0
	/* ifType ethernetCsmacd(6) @see RFC1213 */
	netif->link_type = 6;
	/* your link speed here */
	netif->link_speed = ;
	netif->ts = 0;
	netif->ifinoctets = 0;
	netif->ifinucastpkts = 0;
	netif->ifinnucastpkts = 0;
	netif->ifindiscards = 0;
	netif->ifoutoctets = 0;
	netif->ifoutucastpkts = 0;
	netif->ifoutnucastpkts = 0;
	netif->ifoutdiscards = 0;
#endif

	netif->name[0] = IFNAME0;
	netif->name[1] = IFNAME1;
	netif->output = xemacpsif_output;
	netif->linkoutput = low_level_output;

	low_level_init(netif);//主要是这个函数,以太网中断函数
	return ERR_OK;
}

选中low_level_init函数鼠标右击选择Open Declaration,可以查看low_level_init

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 */
	netif->mtu = XEMACPS_MTU - XEMACPS_HDR_SIZE;

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

	netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
											NETIF_FLAG_LINK_UP;

#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__);
	}

	/* 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);

	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;
}

选中setup_isr函数鼠标右击选择Open Declaration,可以查看setup_isr

void setup_isr (struct xemac_s *xemac)
{
	xemacpsif_s   *xemacpsif;

	xemacpsif = (xemacpsif_s *)(xemac->state);
	/*
	 * Setup callbacks
	 */
	XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
				     (void *) emacps_send_handler,//以太网发送中断连接这个函数句柄,当产生以太网发送中断时调用emacps_send_handler函数
				     (void *) xemac);

	XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
				    (void *) emacps_recv_handler,//以太网接收中断连接这个函数句柄,当产生以太网接收中断时调用emacps_recv_handler函数
				    (void *) xemac);

	XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
				    (void *) emacps_error_handler,//错误中断
				    (void *) xemac);
}

选中emacps_send_handler函数鼠标右击选择Open Declaration,可以查看emacps_send_handler

void emacps_send_handler(void *arg)
{
	struct xemac_s *xemac;
	xil_printf("发送1111wzq\n\r");
	xemacpsif_s   *xemacpsif;
	XEmacPs_BdRing *txringptr;
	u32_t regval;
#ifdef OS_IS_FREERTOS
	xInsideISR++;
#endif
	xemac = (struct xemac_s *)(arg);
	xemacpsif = (xemacpsif_s *)(xemac->state);
	txringptr = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
	regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);
	XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,XEMACPS_TXSR_OFFSET, regval);

	/* If Transmit done interrupt is asserted, process completed BD's */
	process_sent_bds(xemacpsif, txringptr);
#ifdef OS_IS_FREERTOS
	xInsideISR--;
#endif
}
void emacps_recv_handler(void *arg)
{
	struct pbuf *p;
	XEmacPs_Bd *rxbdset, *curbdptr;
	struct xemac_s *xemac;
	xemacpsif_s *xemacpsif;
	XEmacPs_BdRing *rxring;
	volatile s32_t bd_processed;
	s32_t rx_bytes, k;
	u32_t bdindex;
	u32_t regval;
	u32_t index;
	u32_t gigeversion;
	xil_printf("接收1111wzq\n\r");
	xemac = (struct xemac_s *)(arg);
	xemacpsif = (xemacpsif_s *)(xemac->state);
	rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);

#ifdef OS_IS_FREERTOS
	xInsideISR++;
#endif

	gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
	index = get_base_index_rxpbufsstorage (xemacpsif);
	/*
	 * If Reception done interrupt is asserted, call RX call back function
	 * to handle the processed BDs and then raise the according flag.
	 */
	regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);
	XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET, regval);
	if (gigeversion <= 2) {
			resetrx_on_no_rxdata(xemacpsif);
	}

	while(1) {

		bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
		if (bd_processed <= 0) {
			break;
		}

		for (k = 0, curbdptr=rxbdset; k < bd_processed; k++) {

			bdindex = XEMACPS_BD_TO_INDEX(rxring, curbdptr);
			p = (struct pbuf *)rx_pbufs_storage[index + bdindex];

			/*
			 * Adjust the buffer size to the actual number of bytes received.
			 */
			rx_bytes = XEmacPs_BdGetLength(curbdptr);
			pbuf_realloc(p, rx_bytes);

			/* store it in the receive queue,
			 * where it'll be processed by a different handler
			 */
			if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) {
#if LINK_STATS
				lwip_stats.link.memerr++;
				lwip_stats.link.drop++;
#endif
				pbuf_free(p);
			}
			curbdptr = XEmacPs_BdRingNext( rxring, curbdptr);
		}
		/* free up the BD's */
		XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
		setup_rx_bds(xemacpsif, rxring);
#if !NO_SYS
		sys_sem_signal(&xemac->sem_rx_data_available);
#endif
	}

#ifdef OS_IS_FREERTOS
	xInsideISR--;
#endif
	return;
}
main函数
/* receive and process packets  recv_handler*/
	while (1) {
		if (TcpFastTmrFlag) {
			//xil_printf("11\r\n");
			tcp_fasttmr();//不是很懂什么意思,250ms执行一次
			TcpFastTmrFlag = 0;
		}
		if (TcpSlowTmrFlag) {
			//xil_printf("22\r\n");
			tcp_slowtmr();//不是很懂什么意思,500ms执行一次
			TcpSlowTmrFlag = 0;
		}
		//xil_printf("33\r\n");
		xemacif_input(echo_netif);//将MAC 队列里的packets 传输到你的LwIP/IP stack 里
		transfer_data();
	}

 

  • 12
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值