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();
    }
 
————————————————
版权声明:本文为CSDN博主「wuzhouqingcy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wuzhouqingcy/article/details/83387020

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值