zoukankan      html  css  js  c++  java
  • 移植LWIP(ENC28J60)

    这里写图片描述
    上图就是整个移植的基本思路,非常清晰的三个层次。其实想想,本质上就是收发数据,只是LWIP协议通过对数据的封装可以实现网络传输。从图中我们就可以看到这里首先需要ENC28J60的驱动,这个驱动需要实现数据的收发,驱动可以在网上找一个。其次就是要移植并修改LWIP协议了。

    移植
    1.下载LWIP1.4.1和contrib-1.4.1,可以到网上找一个下载,本质上LWIP1.4.1就是LWIP协议的全部,当时我们需要contrib-1.4.1才能完成整个移植。
    2.将LWIP1.4.1拷贝到keil新建的工程下面,LWIP下的src是源文件,
    这里写图片描述
    在keil工程中添加几个组,LWIP-API,LWIP-CORE,LWIP-CORE-IPV4,LWIP-NETIF,LWIP-ARCH。分别将lwip1.4.1下的src中的api全部文件添加到LWIP-API,中,将core中的文件添加到LWIP-CORE中,将core下的ipv4下的文件全部添加到LWIP-CORE-IPV4,将netif中的文件添加到LWIP-NETIF中。到这里lwip的移植就结束了。
    这里写图片描述
    下面就是将H文件添加在keil中了。
    这里写图片描述
    3.在lwip的同一目录下,新建ARCH,NET,netconfig文件。在contrib-1.4.1contrib-1.4.1portswin32目录下找到sys_arch.c,在contrib-1.4.1contrib-1.4.1portswin32include找到lwipopts.h和arch文件夹下的文件,将这些文件都拷贝到keil工程中新建的ARCH目录下。在netconfig目录下新建netconfig.c和netconfig.h文件,在NET目录下新建udp_app.c和udp_app.h文件。
    4.好了,移植了这么多的文件也是够乱了,现在来解释一下。ARCH中的cc.h文件里是一些数据类型的定义,为了保证平台的无关性,协议栈只使用了自己定义的数据类型,此外cc中还定义了一些调试信息输出的宏。lwipopts.h定义了内核的预编译的宏,有些文件或服务不需要使用,可以改变这个文件中的宏定义取消编译。这个文件是内核的参数配置文件,非常的重要。sys_arch.c文件只有一个sys_now()函数是有用的,其余的都可以注释掉,这里也要修改一下sys_now()函数。其余的文件都不需要修改。

    u32_t sys_now()
    {
      return LocaTime;
    }
    

    接着我们需要将ENC28J60的接收发送函数与LWIP协议的底层数据接发接口对接起来。这里对接文件是lwip-1.4.1src etif下的ethernetif文件,这个文件定义了五个函数,

    static void low_level_init(struct netif *netif)
    static err_t low_level_output(struct netif *netif, struct pbuf *p)
    static struct pbuf* low_level_input(struct netif *netif)
    static void ethernetif_input(struct netif *netif)
    err_t ethernetif_init(struct netif *netif)

    low_level_init函数初始化mac地址,

    static void
    low_level_init(struct netif *netif)
    {
      /* set MAC hardware address length */
      netif->hwaddr_len = ETHARP_HWADDR_LEN;
    
      /* set MAC hardware address */
        netif->hwaddr[0] = macaddress[0];
        netif->hwaddr[1] = macaddress[1];
        netif->hwaddr[2] = macaddress[2];
        netif->hwaddr[3] = macaddress[3];
        netif->hwaddr[4] = macaddress[4];
        netif->hwaddr[5] = macaddress[5];
      /* maximum transfer unit */
      netif->mtu = netifMTU;
    
      /* device capabilities */
      /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
      netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
    
      /* Do whatever else is needed to initialize interface. */  
        enc28j60Init(netif->hwaddr);
    }

    我们将ENC28J60的初始化放在这里。
    low_level_output函数是传递数据到内核里,我们将enc28j60PacketSend放在里面

    static err_t
    low_level_output(struct netif *netif, struct pbuf *p)
    {
      struct pbuf *q;
        unsigned int i = 0;  
    
    #if ETH_PAD_SIZE
      pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
    #endif
    
      for(q = p; q != NULL; q = q->next) {
        /* Send the data from the pbuf to the interface, one pbuf at a
           time. The size of the data in each pbuf is kept in the ->len
           variable. */
            memcpy(&Tx_Data_Buf[i], (u8_t*)q->payload, q->len); 
                    i = i + q->len;
      }
    
        enc28j60PacketSend(i,Tx_Data_Buf); //·¢ËÍÊý¾Ý°ü
    
    #if ETH_PAD_SIZE
      pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
    #endif
    
      LINK_STATS_INC(link.xmit);
    
      return ERR_OK;

    low_level_input函数接受内核数据,我们将enc28j60PacketReceive放到里面

    static struct pbuf *
    low_level_input(struct netif *netif)
    {
      struct pbuf *p, *q;
      u16_t len;
        unsigned int i =0;
      /* Obtain the size of the packet and put it into the "len"
         variable. */
      len = enc28j60PacketReceive(1520 *4,  Data_Buf);  
        if(len == 0) return 0;
    
    #if ETH_PAD_SIZE
      len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
    #endif
    
      /* We allocate a pbuf chain of pbufs from the pool. */
      p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    
      if (p != NULL) {
    
    #if ETH_PAD_SIZE
        pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
    #endif
    
        /* We iterate over the pbuf chain until we have read the entire
         * packet into the pbuf. */
        for(q = p; q != NULL; q = q->next) {
          /* Read enough bytes to fill this pbuf in the chain. The
           * available data in the pbuf is given by the q->len
           * variable.
           * This does not necessarily have to be a memcpy, you can also preallocate
           * pbufs for a DMA-enabled MAC and after receiving truncate it to the
           * actually received size. In this case, ensure the tot_len member of the
           * pbuf is the sum of the chained pbuf len members.
           */
                    memcpy((u8_t*)q->payload, (u8_t*)&Data_Buf[i], q->len);
    
                    i = i + q->len;
        }
    
    #if ETH_PAD_SIZE
        pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
    #endif
    
        LINK_STATS_INC(link.recv);
      } else {
        //drop packet();
        LINK_STATS_INC(link.memerr);
        LINK_STATS_INC(link.drop);
      }
    
      return p;  
    }
    

    其余的就不需要我们了,这里直接移植的ethernetif文件默认是不编译的,我们将#if 0给取消掉。
    新建的netconfig文件就是配置网络参数了,比如ip地址,mac地址,还有最重要的LwIP_Periodic_Handle函数,处理内核的定时函数,如何TCP定时,ARP定时。定时采用systick进行定时,每20ms中断一次,执行一次LwIP_Periodic_Handle。
    基本上lwip的移植就结束了。

  • 相关阅读:
    C++中派生类与基类的同名成员调用机制
    一元运算符重载
    二元运算符重载
    const修饰符在不同位置带来的效应
    C++中指针与引用的区别
    基本的查找算法
    排序算法
    指针是怎么回事
    面试总结(1)
    价值观作业
  • 原文地址:https://www.cnblogs.com/zhangbing12304/p/10666267.html
Copyright © 2011-2022 走看看