本文转自公众号欢迎关注
基于DWC_ether_qos的以太网驱动开发-无OS环境移植LWIP (qq.com)
https://mp.weixin.qq.com/s/u1Bv6s_oh7jZ3sjS3nxbEA
一.前言
前面我们实现了数据的收发,现在我们就可以移植协议栈了。LWIP是一个适合嵌入式平台的著名的轻量级协议栈,我们这一篇就来无OS环境移植LWIP,下一篇再基于RTOS移植LWIP。
二.源码
LWIP官网如下
https://savannah.nongnu.org/projects/lwip/
下载源码git clone https://git.savannah.nongnu.org/git/lwip.git
LWIP的代码可移植性非常好src下的源码完全可移植不需要任何修改,移植参考contribports下的模板即可,已经有了unix,freertos,win32的移植可参考。
三.NONEOS移植
3.1添加文件
将src复制到自己的工程路径
然后添加一个port文件夹和src并列,无OS移植就添加一个noneos子目录。
.
其中port如下,相关的文件可以从其他port下复制过来修改。
ports/
添加源文件
将src文件夹复制到自己的工程,添加源码
src/api下所有c
src/core下所有c
src/core/ipv4下所有c
src/core/ipv6下所有c
src/netif/ethernet.c,netif下还有其他很多接口实现,用到可以使用对应的,我们这里只需要使用ethernet.c
头文件路径
将目录src/include,ports/noneos/include添加到头文件包含路径。
3.2 移植文件
修改修改的文件
Ports下文件是需要修改的
ports/
lwipopts.h
配置文件,使用宏对LWIP进行配置。
Cc.h
必须位于arch目录下
Perf.h/perf.c
portethif.h/portethif.c
sys_arch.c
错误码
lwipopts.h中定义#define LWIP_PROVIDE_ERRNO 1则
src/include/lwip/errno.h中定义错误编码和变量errno。
(我们这里使用该方式)
否则cc.h中需要include 或者自己实现错误码宏定义和errno变量。
src/include/lwip/errno.h中可知,如果已经有了对应的头文件则
可以定义LWIP_ERRNO_STDINCLUDE则自动#include
否则错误头文件由LWIP_ERRNO_INCLUDE定义。
随机数产生接口
如果有stdint.h则直接使用库函数,否则自行实现
Cc.h中
#include
extern unsigned int lwip_port_rand(void);
#define LWIP_RAND() (lwip_port_rand())
portethif.c中实现
#include
uint32_t lwip_port_rand(void)
{
return (uint32_t)rand();
}
断言
不使用断言,Cc.h中定义
#define LWIP_NOASSERT 1
如果定义了LWIP_NOASSERT则LWIP_ASSERT为空
如果使用断言,没有定义LWIP_NOASSERT
则src/lib/lwip/lwip/src/include/lwip/debug.h中
#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) {
LWIP_PLATFORM_ASSERT(message); }} while(0)
此时需要实现LWIP_PLATFORM_ASSERT宏,
如果没有定义LWIP_PLATFORM_ASSERT宏则默认使用printf
则src/lib/lwip/lwip/src/include/lwip/arch.h中
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion "%s" failed at line %d in %sn",
x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
atoi
Stdlib.h中有实现,如果没有该库可以如下源码实现
/*----------------------------------------------*/
lwip/ports/noneos/sys_arch.c下实现
u32_t sys_now(void)返回mS的全局时间。
存储管理
lwip/ports/noneos/include/lwipopts.h中配置
堆管理
LWIP_RAM_HEAP_POINTER定义堆地址,必须要空间足够大。
未定义则mem.c中定义大数组ram_heap
MEM_ALIGNMENT设置堆对齐
MEM_SIZE设置堆字节大小
lwip_init->mem_init时初始化,代码位于mem.c
内存池
pbuf.c调用memp.的接口
lwip_init->memp_init时初始化,代码位于memp.c
lwip/priv/memp_priv.h中定义各个组件需要的内存池
lwip/ports/noneos/include/lwipopts.h中MEMP_NUM_xxx定义大小。
性能测试接口
lwipopts.h中如果配置LWIP_PERF宏则
arch/perf.h需要实现两个宏
PERF_START
PERF_STOP
在perf.c/perf.h中具体实现
否则这两个宏自动置空。
一个参考实现如下
Perf.h
#ifndef LWIP_ARCH_PERF_H
perf.c
#include
可以看到指定接口执行时间打印如下
系统层接口
无OS时不需要实现相关接口
src/lib/lwip/ports/noneos/include/lwipopts.h中
#define NO_SYS 1
NO_SYS=1时不能使用socket相关接口
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
以太网收发接口相关
实现以下几个函数即可
实现初始化函数lwip_port_eth_init
在netif_add(&netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &lwip_port_eth_init, ðernet_input);时调用执行lwip_port_eth_init
实现low_level_output,在执行lwip_port_eth_init时绑定到回调函数
netif->linkoutput = low_level_output;
收到一包数据时调用
lwip_port_eth_input
Portethif.h
#ifndef LWIP_TAPIF_H
Portethif.c
#include
四.测试
以下忽略了平台相关的操作,比如以太网驱动初始化等,仅保留lwip相关内容。
#include "lwip/netif.h"
收到包时调用
lwip_port_eth_input(&netif, p_data, len);
初始化与主循环
/* 在PHY初始化后,尤其是RXC输出之后才调用,因为GMAC复位需要RXC */
使用网口调试工具,发送数据收到后原样返回。
五.总结
LWIP代码移植性非常好,无OS支持也非常好,移植只需要实现平台相关的配置和宏,实现网口收发接口即可。
审核编辑 黄宇
-
以太网
+关注
关注
40文章
5371浏览量
171024 -
LwIP
+关注
关注
2文章
85浏览量
27075 -
驱动开发
+关注
关注
0文章
130浏览量
12061
发布评论请先 登录
相关推荐
评论