前言 LwIP 在 lwipopts.h 和 opt.h 头文件中提供了多个配置选项。用户可以根据不同的性能需求和不同应用的内存限制对协议栈用到的内存配置进行调节。Opt.h 头文件中包括协议使能和设置,内存设置,调试选项等等。而 Lwipopts.h 头文件中集合了opt.h 中一些常常需要改动的部分。一般情况下用户对 lwipopts.h 头文件进行修改就可以了。不管是对 lwipopts.h 还是 opt.h进行修改,都必须保证是在已经对你所改动的内容足够的了解的情况下进行,所做的改动是正确的,否则有可能导致协议栈不能正常工作,或者效率低下。- G3 k& A# V4 v* f, {. a# q. h 4 ~) i. A8 T, ?6 {6 l LwIP 的内存管理机制 在进行内存配置之前,我们有必要先了解 LwIP 的内存管理机制。 6 c$ W: g$ E) ?! d# I& `9 S6 }0 i Lwip 动态内存管理# C) d: K/ }: ]0 k( M/ I LwIP 中可以使用两种动态内存分配的方法:Heap 和 Pool 的方式。 Heap 的方式,每次都根据你实际需要的大小分配一块内存出来用,用完以后再还回去。3 ?2 {7 O- |+ C+ ^* S Pool 的方式则是,预先将内存等分成若干份,每次分配时都拿出其中的一块或几块来。假设每等份是 256bytes,而你需要300bytes 的内存空间,Pool 的方式就会给你分配两个 256bytes 的内存块(一共 512bytes)。虽然有点浪费,但这种方式分配内存速度很快,非常适合在接收数据时使用。. u$ i, {+ f8 e4 F+ Q8 u/ Q" v6 `8 s/ p 对于 Heap 的方式,程序默认是使用 LwIP 提供的 mem_malloc/mem_free 进行内存的分配和释放。这种方式下,程序需要预先分配一段内存空间用来做 heap 分配,这段预留的空间大小通过 MEM_SIZE 定义。8 l V6 C0 g0 e, B 你也可以通过 C 标准库里的 malloc/free 函数进行内存的分配和释放。需要定义宏 MEM_LIBC_MALLOC。 . L. A& M$ G1 C9 b Pbuf 类型 前面说的 Heap 和 Pool 都是 LwIP 动态分配内存的方式。而 LwIP 采用了 pbuf 的形式管理内存中的信息,pbuf 结构既支持动态内存分配保存信息包内容,也支持让信息包数据驻留在静态存储区。pbufs 可以在一个链表中链接在一起,被称作一个pbuf 链,这样一个信息包可以跨越几个 pbufs。 LwIP 有三种类型的 pbuf: PBUF_RAM, PBUF_ROM,PBUF_POOL。这三种类型拥有不同的使用目的。0 P9 d( A) _. j0 _ PBUF_RAM 类型的 pbuf 用于应用程序发送的数据被动态生成的情况。在这种情况下,pbuf 系统不仅为应用数据分配内存,还要给为这些数据预置的包头分配内存。包头大小在编译时是可配置的。MEM_SIZE 定义定义了这类 pbuf 的可用空间大小。 PBUF_ROM 类型的 pbuf 用于应用程序要发送的数据放置在应用程序管理的存储区的情况。. P( U) x P9 n+ |5 P) n; o/ Y$ o9 H PBUF_POOL 主要用于网络设备驱动层,因为分配一个 pbuf 的操作可以快速完成,所以非常适合用于中断处理。: Z9 k |1 I1 k+ M" j& x8 j 2 t& | w7 H& }% W [ w 内存配置选项 1. 接收数据缓存的大小 网络接口接收到数据包,通过以太网专用 DMA 放到专门的缓冲区。然后在 low_level_input 函数中,被拷贝到 PBUF_POOL中,再将指向该 PBUF_POOL 的指针传递给 LwIP 协议栈做进一步的处理。这里用于拷贝接收到的数据的 PBUF_POOL 的大小由下面这两个配置选项决定:PBUF_POOL_SIZE 和 PBUF_POOL_BUFSIZE。 PBUF_POOL_SIZE:定义可用的 PBUF_POOL 的个数 PBUF_POOL_BUFSIZE:定义每个 PBUF_POOL 的大小4 x9 l6 r; s; \8 {; [ PBUF_POOL_SIZE * PBUF_POOL_BUFSIZE 的值就是接收数据内存总的大小 用户需要根据接收的数据包的平均大小来设置这两个值。PBUF_POOL_BUFSIZE 设置的太小,可能每个数据包都要多个pbuf 来保存;设置太大,很少的数据也会占用一个较大的 pbuf 造成浪费。" a: s$ ?7 t% ]2 H, u 2.发送数据缓存的大小; j$ Y4 {- S7 l* a5 L2 B* \7 H# w. m LwIP 通过 Heap 的方式可分配的总内存空间大小由 MEM_SIZE 定义,如果应用程序需要发送大量数据,而且这些数据需要拷贝到 LwIP 协议栈中,那么这个值尽量设置大些。* G7 b. f* s0 A8 B8 s 3.连接6 k, l2 I& o' `7 W LwIP 协议栈中通过 PCB(Protocol Control Blocks)的方式管理各个连接。创建新的 PCB 时,也是通过 memory pool 的方式进行内存分配。 MEMP_NUM_UDP_PCB:定义可以创建的 UDP 连接个数( t$ A# h9 Q3 D/ t) Y( N% u" y MEMP_NUM_TCP_PCB:定义可以创建的 TCP 连接个数 MEMP_NUM_TCP_PCB_LISTEN:可以创建 listening TCP 连接的个数. e7 ^$ D, Z7 f( a0 Y MEMP_NUM_NETCONN:使用 netconn 和 socket 编程时,该值的大小会影响可以同时创建的连接的个数2 x! O# h. Z2 g MEMP_NUM_NETBUF:使用 netconn 和 socket 编程时,该值设置太小,可能导致接收数据时分配内存失败,从而不能同时为几个连接的数据收发服务。 $ j; t% b7 m8 B 4. TCP 选项 TCP_MSS :该值规定了 TCP 数据包数据部分的最大长度9 e' V7 e8 [& {5 z! B TCP_SND_BUF:一个 TCP 连接的发送缓存空间大小。改变这个值只影响一个 TCP 连接可用的发送缓存空间大小。总的发送缓存空间是不会变的(由 MEM_SIZE 决定)。如果同时活动的 TCP 连接个数很多,这个值不宜设置的太大。 TCP_SND_QUEUELEN:TCP 发送队列中最多的 pbuf 个数 TCP_WND:TCP 接收窗口大小* w$ V2 o1 E0 Y& V/ }! Z 0 U9 V* r4 p0 s ! n$ Q0 w' w# b7 s: S 配置正确性检查, g* d% R7 H7 ~/ g3 W6 ?( ?# E LwIP 中的很多配置并不是孤立的,在 lwipopts.h 和 opt.h 的某些配置选项前面都有说明需要满足的条件。在修改这些参数时需要特别注意。另外 LwIP 还提供了“sanity checks”,在编译时(LwIPv1.4.1,之前的版本是在 lwip_sanity_check 函数中进行检查)对 lwipopts.h 和 opt.h 中的一些关键的配置进行检查,如果发现错误就会通过 error 信息进行提示。该功能可以通过宏LWIP_DISABLE_MEMP_SANITY_CHECKS 关闭,建议在调试时打开。 另外一个可以在配置 LwIP 众多选项时给你提供帮助的工具就是 CubeMX。CubeMX 里的 LwIP 配置页面对每个选项都做了详细解释,包括建议的最大/最小值。见下图:7 E" v1 H# a, i+ s 2 n- E( D. E$ v* s$ d 8 b1 y9 S7 Q; g* @ |
STM32固件库分享,超全系列整理
STM32的CAN FD位定时设置注意事项
基于STM32将移植 SBSFU 到 STM32G070过程分享
基于STM32G030 RAM不够用经验分享
STM32G070在OLED上移植U8G2单色GUI
【经验分享】STM32 IAP+Ymodem功能实现(参考官方代码)
【经验分享】STM32的SPI问题
【经验分享】STM32 的加密实现
STM32G070—使用platformio+arduino
STM32G0-Platformio平台下使用libopencm3库