26941|18

918

帖子

0

TA的资源

纯净的硅(中级)

楼主
 

lwIP配置文件opt.h和lwipopts.h初步分析 [复制链接]

         其实对于在Stellaris上应用lwIP最难的部分是如何去配置协议栈,使我们设计出来的web服务器或者串口转以太网及TFTP等等应用能够在lwIP协议栈的基础之上,既要保持稳定、快速地运行,又要占用最少的内存,正所谓:又要马儿跑,又要马儿不吃草。能跑是第一步,这一步呢,StellarisWare的例程基本上把这一步做得非常完美,丰富的公开源码的例程是一个很好的借鉴,很多例程稍稍修改就能弄到自己的设计当中去,比如在enet_Lwip这个例程中我们只需要通过makefsfilefile转化一下,或者直接把我们设计的网页index.htm(注意使用.html后缀有可能是访问不到的,具体原因以后分析)放到SD卡的根目录下就能跑了,但是我们还必须要考虑第二步,你虽然是照猫画虎的跑起来来了,但是忽略了一个很重要的问题,那就是enet_lwIP例程的lwip的配置是按照这个例程量体裁衣的,这个例程的网页是TI的介绍,你实际设计的网页肯定与它的例程不同,如果是动态网页就更应该注意了。这就是为什么有的人没有把例程分析清楚,就直接从中间卸掉一块放到自己的工程里边去之后,会出现的一大堆莫名奇妙的问题,什么打开网页的速度很慢啊?什么丢包啊,什么死机啦,什么跑到无限循环里边去了,总之很多。。。那主要你没有去修改过配置文件,没有为你的工程去量体裁衣。
就算第二步你侥幸躲过去了,也能够稳定的运行,就像借一双别人的鞋,虽然自己穿着大了点,但是呢,也能跑得很快,很稳当,不过有点浪费材料了。所以第三步我们要考虑的问题是,如何去配置lwip,使它去适合不同大小的脚,这就是本贴的主题lwIP的配置问题。尤其是内存的配置,配置多了浪费,配置少了跑不了或者不稳定。研究如何占用内存少,正式我们学习和采用lwip中最关键的问题。否则你可以直接去使用TCPnet,可配置的不太多,可以把主要的精力放到应用层上面去。
          有点罗嗦,在论坛上一个字一个字的敲出来的。
          在这里先说一下这两个配置lwip协议栈文件opt.h和lwipopts.h的关系:
         opt.h是lwip“出厂”时原装的配置文件,它的作者是瑞士科学院的Adam等人,而lwipopts.h的作者是stellarisWare的工程师,它集合了opt.h中常常需要改动的部分和针对Stellaris所特有的配置选项添加进来了。这两个文件里边都配置的选项,以后者为准,不是共有的选项以它们各自的配置为准。
         在这里先说一下lwip的内存管理机制,我们以enet_lwip这个例程为例。
         在使用lwip的时候,我们可以使用两种形式的内存,一种是heap,一种是pool。heap就像是一整块蛋糕,我们需要多少就切多少,但是切了之后不能吃,只能看,因为看完之后,你还要放回去让别人看,因为当整块蛋糕很少的时候,有很多人等着都要切了看,这样很多次的切了之后又放回去,必然要产生一些很小的蛋糕块,这就是内存的碎片,到最后都是切得很细的蛋糕块,假如这个时候你想切块大点的蛋糕来看看,不好意思,你找遍了整个拼凑起来的蛋糕块,没有发现你想要的那么大的,结果你只好放弃了,所以最后内存申请回频频失败。
因为我们是嵌入式系统,我们的RAM再大也不能和PC机的天文数字相比,我们不能使用PC机所使用的蛋糕刀具来切蛋糕,必须使用更小型的道具,占用CODE更小,这一点Adam等相对于标准C而实现了几个小的内存分配、重分配和释放函数,它们都以mem_为前缀,已和原来的标准库函数相区别。当然如果你偏要使用大的刀,只需要
#define MEM_LIBC_MALLOC 1 。
        这几个工具不管你是heap型模式切蛋糕还是pool模式切蛋糕,都可以用它们来完成,它们只是刀,至于怎么切蛋糕,这里不是它们该考虑的事情。
       上面介绍了heap型的切蛋糕的方法,在简单说一下pool型切蛋糕的方法。
       为了能让更多的人把蛋糕切回去看并且不至于还回来的蛋糕都是非常地小。Adam非常努力地在lwip切蛋糕上问题上采用一种Pool型的切法,找来一块蛋糕,把它切成n等分,每一份都是相同的固定大小,一份不够的可以拿两份,一份用起来太多的人你也最少拿一份(虽然浪费了,但是你也必须这么做),这种切法有两个好处,一是:现在你不能再随便的按自己的要求大小去切蛋糕了,大小是固定的,这样你申请了蛋糕之后不需要去切了,已经切好了,你可以很快地拿到一份大小固定的蛋糕,这非常适合于在接受数据帧的底层使用,当大量的数据来的时候,我们一下子需要很多的内存,这种方式下,我们很快就可以拿到足量的内存,不至于应接不暇;二是:在切成多少份,每份多大上需要我们根据最常接受到的数据帧的大小来费点脑筋,切得太小了,内存的利用率就下降了,切得太大了,我们就会严重地浪费内存,如果总共可切的内存还不大的话,那肯定是要因为后面来的数据无蛋糕可切而要丢包的,这就像是现在的房地产,少数富人拥有好几套大房子空着不住人,而另一方面,多数穷人却因为租不起房子而只好离开大城市,但是当前穷人对于城市所作的贡献并不见得比富人小。
        这两种切法都不是完美的,也不可能有完美的,但是有它们最适合的地方。我上面的比喻是为了更形象地理解,当然在细节上可能会有不同,不过,大体上就是这么个意思,细节我们可以去深入地分析。
Pool型一般用于从链路层就收一个帧,目的是快速、少碎片、浪费一点没关系、只要我能满足大多数人迅速地有房可住即可。
heap型一般用于缓存应用层生成的数据,大小自己定,相切多少切多少,随心所欲,尽管以后可能没得切,但我只在乎现在,也许以后就有新的方法解决呢,就像煤炭和石油,该用还得用,说不定以后会有新能源取代它们,杞人忧天干嘛。
      实际上,在enet_lwip这个例程里它就是这么实现的。
      如何配置heap的大小呢,
#define MEM_SIZE                        (12 * 1024)
所以说当你有大量的数据要发送的时候,你最好把这个值设置得大一些。否则你会因为切不到heap中的内存而无法发送或只能延迟发送。
最好是把上面这个数设置成4字节对齐的。
      如何配置pool的大小呢,
#define PBUF_POOL_SIZE                  16
#define PBUF_POOL_BUFSIZE               256
第一个是我们要切的分数,第二个是每一份的大小。
那么实际上我们切到的每一份内存的大小要比我们定义的大16个字节。我们可以根据应用去调整这几个值,这两部分的大小就占到了lwip协议栈所占内存的大部分,也就是说他们会影响到ZI段的大小。
未完待续。。。

        

[ 本帖最后由 academic 于 2010-11-15 13:13 编辑 ]

最新回复

想办法把内存使用信息打印出来,分析看一下是不是有未释放的内存分配。  详情 回复 发表于 2017-7-13 12:23

赞赏

1

查看全部赞赏

 
点赞 关注(1)

回复
举报

918

帖子

0

TA的资源

纯净的硅(中级)

沙发
 

回复 楼主 academic 的帖子

如果要使发送的应用程序也采用pool的方式而不是heap,则要:
#define MEM_USE_POOLS  1
define  MEM_USE_CUSTOM_POOLS  1
并且还要在工程所在目录下创建文件
lwippools.h,里包括:
LWIP_MALLOC_MEMPOOL_START
LWIP_MALLOC_MEMPOOL(20, 256)
LWIP_MALLOC_MEMPOOL(10, 512)
LWIP_MALLOC_MEMPOOL(5, 1512)
LWIP_MALLOC_MEMPOOL_END
这样协议栈所涉及到的内存都用POOL方式来管理了,这种方法在StellarisWare例程中一般没有采用。
如果使用POOL,以下关于内存的两个函数是不会被调用的:
mem_init();这个函数主要是对堆内存的初始化,并返回指针。
mem_realloc(mem, size);这个函数对已分配的对内存块进行收缩。
 
 

回复

155

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

非常受益,谢谢
 
个人签名http://www.tdhj.cn
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

4
 

回复 板凳 bjmonsoon 的帖子

// // NOTE: This file has been derived from the lwIP/src/include/lwip/opt.h header file.

// 注:此文件起源于opt.h //

For additional details, refer to the original "opt.h" file, and lwIP // documentation.

// 详情参考opt.h。

//*****************************************************************************

#ifndef __LWIPOPTS_H__

 #define __LWIPOPTS_H__

 //***************************************************************************** // // ---------- Stellaris / lwIP Port Options ---------- // //*****************************************************************************

 

#define HOST_TMR_INTERVAL 100                                     // 主机定时器间隔,注意不是lwip协议栈本身的定时器间隔,可用来检查IP地址的获取情况或者周期性地调用一些函数。

 

//#define DHCP_EXPIRE_TIMER_MSECS (10 * 1000)          //DHCP 获取超时的毫秒数。这个实际在例程中没看到有用到。DHCP获取IP超时,一般就会采用AUTOIP的方式自给IP。

 

//#define INCLUDE_HTTPD_SSI                                           //在HTTPD中如果有含有SSI标签的网页存在,则开启它,否则如果是普通的html网页,不需要开启。

//#define INCLUDE_HTTPD_CGI                                          //如果需要CGI的处理,则需要开启。

//#define DYNAMIC_HTTP_HEADERS

//如果要动态的添加HTTP首部则开启,在使用makefsfile 带参数-h时,就去掉了http首部,如果不能正常浏览到网页可尝试开启。一般不需要开启,样可以节省Flash的空间,因为如果不是使用SD卡,而是使用内部文件系统的时候,所有的网页数据都放在了RO段。

 

 //***************************************************************************** // // ---------- Platform specific locking ---------- // //*****************************************************************************

#define SYS_LIGHTWEIGHT_PROT 1                                   // default is 0 针对Stellaris必须1,主要是因为在分配内存的时候,要确保总中断关闭。防止内存分配失败。

 

#define NO_SYS 1                                                                 // default is 0 如果为使用RTOS,就置1.

 //#define MEMCPY(dst,src,len) memcpy(dst,src,len)            // 该宏用来定义我们是否需要C语言标准库函数memcpy(),如果有更有效的函数,该宏可以忽略.不使用C标准库

 //#define SMEMCPY(dst,src,len) memcpy(dst,src,len)         //同上

 

 

//***************************************************************************** // // ---------- Memory options ---------- // //*****************************************************************************//

#define MEM_LIBC_MALLOC 0                                                     //如果为1,就表示我们使用c库的 malloc/free/realloc,否则使用lwip自带的函数,注意加了前缀的。

#define MEM_ALIGNMENT 4                                                         //Stellaris该值必须为4,设置CPU的对齐方式

#define MEM_SIZE (12 * 1024)                                                      // default is 1600 该值在ZI中占了很大的份额。这就是堆内存的大小,如果应用程序有大量数据在发送是要被复制,那么该值就应该尽量大一点。由此可见,发送缓冲区从这里边分配。

//#define MEMP_OVERFLOW_CHECK 0                                      //是否开启内存POOL溢出检查,即是否使能堆内存溢出检查.

//#define MEMP_SANITY_CHECK 0                                              //设置为1表示在每次调用函数memp_free()后,进行一次正常的检查,以确保链表队列没有循环

//#define MEM_USE_POOLS 0                                                     //是否使用POOL型内存来作为发送缓冲,而不是heap型,如果开启的话,可能还要创建头文件lwippool.h

 //#define MEMP_USE_CUSTOM_POOLS 0                                //内存Pool是否使用固定大小的POOL,开启这个前提是要开启上面的。

 //***************************************************************************** // // ---------- Internal Memory Pool Sizes ---------- // //*****************************************************************************

#define MEMP_NUM_PBUF 20                                                     //来自memp的PBUF_ROM和PBUF_REF类型的数目,如果应用程有大量的数据来自ROM或者静态mem的数据要发送,此值要设大一些。

//#define MEMP_NUM_RAW_PCB 4                                             //原始连接(就是应用程不经过传输层直接到IP层获取数据)PCB的数目,该项依赖lwip_raw项的开启。

//#define MEMP_NUM_UDP_PCB 4                                              //UDP的PCB数目,每一活动的UDP “连接” 需要一个PCB。

#define MEMP_NUM_TCP_PCB 3                                                // 同时建立激活的TCP连接的数目(要求参数LWIP_TCP使能).默认为5 我改成1之后和原来的8没有什么区别。

#define MEMP_NUM_TCP_PCB_LISTEN 1                                  // 能够监听的TCP连接数目(要求参数LWIP_TCP使能).默认为8我改成了1之后对本例程也是无影响的。

#define MEMP_NUM_TCP_SEG 20                                             //最多同时在队列的TCP_SEG的数目.

//#define MEMP_NUM_REASSDATA 5                                        // 最多同时在队列等待重装的IP包数目,是整个IP包,不是IP分片。

//#define MEMP_NUM_ARP_QUEUE 30 //

//#define MEMP_NUM_IGMP_GROUP 8 //

//#define MEMP_NUM_SYS_TIMEOUT 3                                   // 能够同时激活的timeout的个数(要求NO_SYS==0)。默认为3

//#define MEMP_NUM_NETBUF 2                                             // netbufs结构的数目,仅当使用sequential API的时候需要。默认为2

//#define MEMP_NUM_NETCONN 4                                         // netconns结构的数目,仅当使用sequential API的时候需要。默认为4

//#define MEMP_NUM_TCPIP_MSG_API 8 // tcpip_msg结构的数目,它用于callback/timeout API的通信(仅当使用tcpip.c的时候需要 )。默认为8

//#define MEMP_NUM_TCPIP_MSG_INPKT 8 // 接收包时tcpip_msg结构体的数目。

//***************************************************************************** // // ---------- ARP options ---------- // //*****************************************************************************

 

 

//#define LWIP_ARP 1                                                             //开启ARP

//#define ARP_TABLE_SIZE 10                                              //ARP表项的大小。激活的MAC-IP地址对存储区的数目

//#define ARP_QUEUEING 1                                                  //设置为1表示在硬件地址解析期间,将发送数据包放入到队列中

//#define ETHARP_TRUST_IP_MAC 1

[ 本帖最后由 academic 于 2010-11-26 15:51 编辑 ]

lwipopts.zip

5.41 KB, 下载次数: 423

 
 
 

回复

155

帖子

0

TA的资源

一粒金砂(中级)

5
 

谢谢

谢谢
 
个人签名http://www.tdhj.cn
 
 

回复

7

帖子

0

TA的资源

一粒金砂(初级)

6
 
非常感谢!
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

7
 
非常感谢!
 
 
 

回复

105

帖子

0

TA的资源

一粒金砂(中级)

8
 
楼主真厉害啊!!!!!!!
 
 
 

回复

102

帖子

0

TA的资源

一粒金砂(中级)

9
 

疑问!

#define NO_SYS 1           // default is 0 如果为使用RTOS,就置1.

这个理解是不是有问题呢?
应该:
NO_SYS 1 就是NO RTOS
NO_SYS 0 就有RTOS.
 
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

10
 

回复 9楼 hebin939 的帖子

你说得对,是个失误。非常感谢哦。
 
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

11
 

回复 9楼 hebin939 的帖子

你说得对,是个失误。非常感谢哦。
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

12
 

我做的网页数据存放在stm32 的flash里面,有17k,可是我每次访问该网页时,都只能开到部分内容,请问大侠是什么原因呢?而且查看已访问到的网页源文件也发现只有部分数据。。。。

 
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

13
 

回复 12楼 wenshan231 的帖子

会不是Html中文件的路径有问题?
 
 
 

回复

78

帖子

0

TA的资源

一粒金砂(高级)

14
 
谢谢了,楼主辛苦了。
 
 
 

回复

70

帖子

0

TA的资源

纯净的硅(高级)

15
 

请问我使用uCOS2+Lwip,怎样才能同时支持两个以上的TCP连接。应该修改哪个参数呢?

有做过的请解答一下啊,谢谢啦。

 
 
 

回复

49

帖子

0

TA的资源

一粒金砂(中级)

16
 
做个标记慢慢看
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

17
 

回复 4楼 academic 的帖子

谢谢!很给力!!!
 
 
 

回复

4

帖子

0

TA的资源

一粒金砂(初级)

18
 
楼主,这几天调试STM32f107+lwip客户端测试出现了内存分配失败的问题,不知道是不是内存分配不够,但是测试12小时左右才会出现。不知道楼主有没有遇到过此问题?

点评

想办法把内存使用信息打印出来,分析看一下是不是有未释放的内存分配。  详情 回复 发表于 2017-7-13 12:23
 
 
 

回复

1803

帖子

0

TA的资源

五彩晶圆(高级)

19
 
fangshu 发表于 2017-6-26 17:17
楼主,这几天调试STM32f107+lwip客户端测试出现了内存分配失败的问题,不知道是不是内存分配不够,但是测试 ...

想办法把内存使用信息打印出来,分析看一下是不是有未释放的内存分配。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表