【JokerのZYNQ7020】PS_LWIP_POLL。

软件环境:vivado 2017.4        硬件平台:XC7Z020


说起zynq平台下PS端的lwip实现机制,有可能很多老哥跟我一样,具体并不十分清楚,我自己也是在很偶然的情况下看了一篇帖子才知道,居然利用的是PS端的dma收发中断。

结果好嘛,一回头再想找之前看的帖子,就找不到了,只能回来自己一点一点扒来试。过程太繁琐了,就不表了,就说一点,是不是用的dma中断,打个断点不就晓得啦。

不过今天,我还就偏要板一板,如果不用dma,仅使用poll轮询机制,能不能把lwip的收发实现了。先说下dma是怎么验出来的,大家也都可以试下。

首先需要在BSP里打开lwip的调试模式,方法是在图中红框的地方加上-g,不然在bsp里打不了中断。

然后进入路径bsp/ps7_cortexa9_0/libsrc/lwip141_v2_0/src/contrib/ports/xilinx/netif/xemacpsif_dma.c,mac接收中断服务函数里打个断点,下图可以看到,已经进来啦。

 具体过程大概可以理解为,ps端使用emacps作为网络mac,在dma初始化时,会一同初始化多个block descriptor,每个block descriptor 包含一个pbuf空间,在有接收到网络数据时,block descriptor会往自己的pbuf搬数据,当依次搬够一定量的数据后,dma接收中断触发,进入emacps_recv_handler接收中断服务函数,中断函数对pbuf所要包含的连接信息以及实际数据内容进行进一步封装,封装完毕后压入pbuf的指针队列,最后由后级xemacif_input(netif) 从pbuf缓冲队列中取出pbuf形式的数据包。

当然,我这里只是粗略的说一下大概的过程,实际lwip网络数据包的处理过程,会复杂的多的多的多。具体可以搜索相关内容,由于不是本篇重点,就不在这里做赘述了。

既然已经知道了默认的ps端lwip实现方式使用了dma,那么如何替换掉,仅只使用轮询方式呢,批话不多说,先撸代码。

建立基本的lwip工程后,直接使用下面代码替换工程中的main.c即可。

#include <stdio.h>

#include "xparameters.h"

#include "netif/xadapter.h"

#include "platform.h"
#include "platform_config.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif

#include "lwip/tcp.h"
#include "xil_cache.h"

#if LWIP_DHCP==1
#include "lwip/dhcp.h"
#endif

#include "xil_types.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xscutimer.h"

/* defined by each RAW mode application */
void print_app_header();
int start_application();
int transfer_data();
void tcp_fasttmr(void);
void tcp_slowtmr(void);

/* missing declaration in lwIP */
void lwip_init();

#if LWIP_DHCP==1
extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);
#endif

extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;

static struct netif server_netif;
struct netif *echo_netif;

void
print_ip(char *msg, struct ip_addr *ip) 
{
	print(msg);
	xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip), 
			ip4_addr3(ip), ip4_addr4(ip));
}

void
print_ip_settings(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw)
{

	print_ip("Board IP: ", ip);
	print_ip("Netmask : ", mask);
	print_ip("Gateway : ", gw);
}

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

#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
int IicPhyReset(void);
#endif
#endif

static  XScuGic Intc; //GIC
static  XScuTimer Timer;//timer

volatile int TcpTmrFlag = 0;

#define TIMER_LOAD_VALUE    XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8 //0.25S

static void TimerIntrHandler(void *CallBackRef)
{
    XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
    XScuTimer_ClearInterruptStatus(TimerInstancePtr);
	TcpTmrFlag = 1;
}

void poll_timer_init(void)
{
	int Status;
	XScuTimer_Config *XScuTimer_ConfigPtr;
	XScuGic_Config *SCUGIC_Config;

	//私有定时器初始化
	XScuTimer_ConfigPtr = XScuTimer_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
	XScuTimer_CfgInitialize(&Timer, XScuTimer_ConfigPtr,XScuTimer_ConfigPtr->BaseAddr);
	XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);
	XScuTimer_EnableAutoReload(&Timer);

	//中断配置
	SCUGIC_Config = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
	if (NULL == SCUGIC_Config) {
		xil_printf("Initialize the interrupt controller failed\n");
	}

	Status = XScuGic_CfgInitialize(&Intc, SCUGIC_Config,
				SCUGIC_Config->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		xil_printf("Initialize the interrupt controller failed\n");
	}

	//中断使能
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			(void *)&Intc);

	Xil_ExceptionEnable();

	//使能定时器中断
	XScuGic_Connect(&Intc, XPAR_SCUTIMER_INTR,
					(Xil_ExceptionHandler)TimerIntrHandler,
					(void *)&Timer);

	XScuGic_Enable(&Intc, XPAR_SCUTIMER_INTR);
	XScuTimer_EnableInterrupt(&Timer);
}

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();
	poll_timer_init();
	TcpTmrFlag = 0;

#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,   0, 21);
	IP4_ADDR(&netmask, 255, 255, 255,  0);
	IP4_ADDR(&gw,      192, 168,   0,  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,
						&gw, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}
	netif_set_default(echo_netif);

	/* now enable interrupts */
	//platform_enable_interrupts();

	/* specify that the network if is up */
	netif_set_up(echo_netif);

#if (LWIP_DHCP==1)
	/* Create a new DHCP client for this interface.
	 * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
	 * the predefined regular intervals after starting the client.
	 */
	dhcp_start(echo_netif);
	dhcp_timoutcntr = 24;

	while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
		xemacif_input(echo_netif);

	if (dhcp_timoutcntr <= 0) {
		if ((echo_netif->ip_addr.addr) == 0) {
			xil_printf("DHCP Timeout\r\n");
			xil_printf("Configuring default IP of 192.168.1.10\r\n");
			IP4_ADDR(&(echo_netif->ip_addr),  192, 168,   1, 10);
			IP4_ADDR(&(echo_netif->netmask), 255, 255, 255,  0);
			IP4_ADDR(&(echo_netif->gw),      192, 168,   1,  1);
		}
	}

	ipaddr.addr = echo_netif->ip_addr.addr;
	gw.addr = echo_netif->gw.addr;
	netmask.addr = echo_netif->netmask.addr;
#endif

	print_ip_settings(&ipaddr, &netmask, &gw);

	/* start the application (web server, rxtest, txtest, etc..) */
	start_application();

	/* receive and process packets */
	while (1) {
//		if (TcpFastTmrFlag) {
//			tcp_fasttmr();
//			TcpFastTmrFlag = 0;
//		}
//		if (TcpSlowTmrFlag) {
//			tcp_slowtmr();
//			TcpSlowTmrFlag = 0;
//		}
		if(TcpTmrFlag)
		{
			tcp_tmr();
			TcpTmrFlag = 0;
		}
		xemacif_input(echo_netif);
		transfer_data();
	}
  
	/* never reached */
	cleanup_platform();

	return 0;
}

至于其中的差别,有好事者可以直接使用compare比对软件,一比就晓得我改过哪些地方啦,当然,也可以继续听我道来。

首先屏蔽了init_platform();因为在此函数中,会对dma及中断向量进行初始化,但是,如果只想着只把其中dma部分屏蔽掉,反正我是没成功,因为牵扯的地方实在是太多了。

所以后来换了种思路,把init_platform()整个屏蔽掉,使用私有定时器poll_timer_init(),替换并完成原先定时器功能。

既然不使用中断,下面的platform_enable_interrupts();自然也要屏蔽掉。

while(1)里,别看屏蔽了上面,使用了tcp_tmr(),但编译完成以后点进去看,其实是一回事,tcp_tmr()里完成了快慢定时器的刷新。

最后最后叨叨一句,虽然看起来上面的内容很简单的样子,但是整个扒一遍,并用轮询替换中断,还是费了不少劲了 T T。

补上亲测可行的hello joker外加三个感叹号。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值