基于S3C2440的LWIP-1.3.0和DM9000在UCOS-II-2.8.6上的移植

时间:2020-12-16 17:41:50
基于S3C2440的LWIP-1.3.0和DM9000在UCOS-II-2.8.6上的移植

经常在Linux上跑,一时间跳到UCOS,感觉有点不习惯。首先是编译器,GCC是个不错的选择,但GDB调试太麻烦。ADS和仿真器结合是个十分不错的调试环境,于是,将代码就搬到ADS上,这下完全脱离Linux,整个开发过程都在Windows进行。其实是UCOS太简洁了,时钟、接口很多都需要自己开发…小弟对UCOS不是很熟,下面是移植过程的一些小结,希望对有需要的朋友带来些帮助。关于UCOS在S3C2440上的移植,可以参考《uCOS-II在S3C2440上的移植》一文。
1.
寻找最新代码,总结前辈经验,就是下载LWIP的源代码和Michael Anburaj基于S3C2410的移植版。
http://download.savannah.nongnu.org/releases/lwip/contrib-1.3.0.zip
http://geocities.com/michaelanburaj/downloads/lwip_ucos_1.11.zip
http://download.savannah.nongnu.org/releases/lwip/lwip-1.3.0.zip
2.
解压缩,整理工程代码。
LWIP-1.3.0独立一个目录,与mcu相关的移植移植文件放置在s3c2440/lwip目录。另外dm9000的驱动也防止在与mcu相关的目录s3c2440/dm9000。在app目录添加一个简单的http server文件httpserver-netconn.c(从contrib-1.3.0.zip中提取)。整理后的目录如下:
基于S3C2440的LWIP-1.3.0和DM9000在UCOS-II-2.8.6上的移植
3.
添加lwipopts.h
1.3.0版的LWIP将配置文件独立出来,对组件的配置十分方便。首先定义LWIP_PROVIDE_ERRNO,让LWIP自己提供错误号。然后是TCPIP_THREAD_STACKSIZE栈大小和TCPIP_MBOX_SIZE邮箱大小。接着是LWIP进程的优先级,主要有TCPIP_THREAD_PRIO(TCPIP任务,LWIP核心)和DM9000_THREAD_PRIO(网络芯片轮训任务,这里没采用中断方式接收)。
另外,还有些十分重要的三个参数:MEM_ALIGNMENT、ETH_PAD_SIZE和TCP_MSS。MEM_ALIGNMENT指定内存池分配的地址对齐字节,在S3C2440*问32位地址需4字节对齐。ETH_PAD_SIZE指定以网络包头部的填充大小,否则也会引起地址对齐问题。关于这部分,可以参考《LWIP-1.3.0在S3C2440平台UCOS-II-2.8.6系统上的移植过程DEBUG》一文。最后一个参数是TCP_MSS,指定网络包的分段大小,主要目的是将大包切小,变成一个个的小包。奇怪的是,小包除了效率低点,应该不会导致通讯失败的呀?经过部分测试,切割后的小包偶尔会丢失,这里没有深入追踪,欢迎朋友们帮忙分析一下。
包大了,顺便把LWIP的缓冲也设大一点,充分利用S3C2440配置的64M内存。
#define TCP_SND_BUF
2048
#define MEM_SIZE
2048
#define MEMP_NUM_PBUF
32
4.
添加网络接口
我的开发板上配置的网络芯片是DM9000,在U-BOOT上已工作得很好。所以,直接借U-BOOT的驱动过来,重新包装一下,OK。现在先来看看LWIP需要的网络接口,主要参考lwip-1.3.0\netif\ethernetif.c文件,分别是初始化接口ethernetif_init()、包发送接口low_level_output()和包接收接口ethernetif_input()。
其中ethernetif_init()负责网络的接口的初始化,如底层收发包函数、MAC地址和硬件初始化等,另外,网络的接收采用轮训方式,这里还需创建一个定时收包的任务sys_thread_new("DM9000IN", poll_input,…)。ethernetif_input ()就是轮训任务调用的收包函数,负责查询是否有以太包,有则将其传递到ethernet_input(p, netif),然后再分发到各个协议,如ARP,IP,PPP等。函数的关系图如下:
基于S3C2440的LWIP-1.3.0和DM9000在UCOS-II-2.8.6上的移植
low_level_output()就是负责将上层传来的网络包通过DM9000发送出去。
5.
重新包装DM9000驱动
上面提到的LWIP网络接口与DM9000的沟通需要以下几个函数(也分为初始化、接收和发送三类):
int dm9000_eth_init(struct netif *bd);
void dm9000_eth_send(volatile void *, int);
int dm9000_eth_send_done(int);
int dm9000_eth_rxlen(void);
int dm9000_eth_rx(U8 *rdptr, U16 RxLen);
int dm9000_drop_frame(U16 RxLen);
其中,只有发送和接收两个函数需要改动。LWIP上层传给low_level_output()的数据包,将根据MSS和MTU等值切割成一个个的小包,分别填充到链表pbuf里。