上图就是整个移植的基本思路,非常清晰的三个层次。其实想想,本质上就是收发数据,只是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.1\contrib-1.4.1\ports\win32目录下找到sys_arch.c,在contrib-1.4.1\contrib-1.4.1\ports\win32\include找到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.1\src\netif下的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的移植就结束了。

移植LWIP(ENC28J60)的更多相关文章

  1. STM32F107移植LWIP

    STM32F107上移植LWIP2.0.3 因为最近需要在STM32F107上实现TCP/IP协议栈,所以网上查了一下,准备使用LWIP,虽然大多数用的是1.4.1版本但是官方说2系大版本修复了1.4 ...

  2. LwIP学习笔记——STM32 ENC28J60移植与入门

    0.前言     去年(2013年)的整理了LwIP相关代码,并在STM32上"裸奔"成功.一直没有时间深入整理,在这里借博文整理总结.LwIP的移植过程细节很多,博文也不可能一一 ...

  3. ALIENTEK 战舰ENC28J60 LWIP和UIP补充例程(LWIP WEB有惊喜)

    前面的话:自从接触网络模块,到现在有一阵子时间了,未来必定是网络的世界.学一些网络方面的知识是有必要的.我们ALINTEK 推出的ENC28J60网络模块块作为入门还是不错的.详细见此贴:http:/ ...

  4. LwIP移植和使用

    LwIP移植和使用 本手册基于lwip-1.4.x编写,本人没有移植过1.4.0之前的版本,更早的版本或许有差别.如果看官发现问题欢迎联系<QQ: 937431539  email: 93743 ...

  5. LWIP的移植笔记

    第一次发表博客,文章摘录于还不懂同学的专栏 lwIp的作者做了大量的工作以方便像我这种懒人移植该协议栈,基本上只需修改一个配置头文件和改写3个函数即可完成lwIP的移植.要改写的函数位于lwIP-1. ...

  6. zedboard - 轻量级以太网控制器LWIP

    ipconfig/all route print  显示本机所有的网络 网关是什么 那么网关到底是什么呢?网关实质上是一个网络通向其他网络的IP地址.比如有网络A和网络B,网络A的IP地址范围为&qu ...

  7. LWIP互联网资料汇总

    本文主要搜集了下互联网上关于LWIP的资料和教程 欢迎补充 第一部分:移植 LWIP在UCOS上移植 LWIP 在STM32上移植   http://www.docin.com/p-459242028 ...

  8. 我的RTOS 之六 -- Touch移植(s5pv210+threadx+ucgui+touch)

    非常久没有关注RTOS了,所以也一直没有更新.近期闲了,把GPIO I2C调通了.简单移植了Touch.在S5PV210上使用. 调试I2C时.废了非常多周折,最后借助示波器才发现一个小小的错误.折腾 ...

  9. 5、 LwIP协议栈规范翻译——操作系统仿真层

    为了使lwIP可移植,操作系统特定的函数调用和数据结构不直接在协议的代码中使用.相反,当需要这样的函数调用和数据结构时,直接使用操作系统仿真层. 操作系统仿真层为操作系统服务提供统一的接口,如定时器, ...

随机推荐

  1. FZU 1759 Super A^B mod C 指数循环节

    Problem 1759 Super A^B mod C Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description G ...

  2. angular一些常用的方法:

    angular.copy(); 用法:对Object对象的深度拷贝$scope.data = {name:'yanjinyun',age:'11'}; $scope.origData = angula ...

  3. java reflect反射---Java高级开发必须懂的

    理解反射对学习Java框架有很大的帮助,如Spring框架的核心就是使用Java反射实现的,而且对做一些Java底层的操作会很有帮助.  一.Class类的使用         1.万事万物皆对象,( ...

  4. SQLite在C#中的使用

    SQLite是一款轻型的数据库,在一些数据量不太大的程序中,它暂用的资源非常低.支持很多操作系统和许多语言,所以还是很方便的.在C#中,要用的话可以通过网站来下载或者在VS中通过NuGet来下载.这个 ...

  5. swagger 文件上传

    单个文件上传的写法: @RequestParam MultipartFile pictures 多个文件上传的写法: @RequestParam String token,@RequestPart(& ...

  6. 关于Java类

    一个.java文件中可以有很多类.不过注意以下几点: 1.public 权限的类只能有一个(也可以一个都没有,但最多只有1个) 2.这个.java文件的文件名必须是public类的类名(一般的情况下, ...

  7. Node.js权威指南学习记录

    学习nodeJS权威指南的学习记录 导航: 1.console模块 2.全局变量 3.Buffer对象 4.事件对象 5.网络请求 6.文件操作对象 一. COMMON.js的学习.(commonJS ...

  8. jQueryValidation插件API 学习

    一般格式: $('').viladata({ rules:{ username:{ required:true, maxlength:2, minlength:10, remote:{ url:&qu ...

  9. LeetCode OJ:Merge Two Sorted Lists(合并两个链表)

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing t ...

  10. LeetCode OJ:Palindrome Linked List(回文链表判断)

    Given a singly linked list, determine if it is a palindrome. Follow up:Could you do it in O(n) time ...