Skip to content

ports: Increase the STM32N6/MIMXRT TCP receive window. - #19629

Open
kwagyeman wants to merge 2 commits into
micropython:masterfrom
kwagyeman:kwabena/net_lwip_buffers
Open

ports: Increase the STM32N6/MIMXRT TCP receive window.#19629
kwagyeman wants to merge 2 commits into
micropython:masterfrom
kwagyeman:kwabena/net_lwip_buffers

Conversation

@kwagyeman

Copy link
Copy Markdown
Contributor

Summary

Two per-port lwIP sizing fixes found while benchmarking TCP/UDP on WiFi
hardware:

  1. stm32 (STM32N6): double the TCP receive window to 32*MSS. TCP
    receive is bounded by window/RTT. At the ~5-6ms round-trip time of the
    OPENMV_N6's CYW43439 WiFi link, the existing 16*MSS window works out to
    ~31Mbit/s — exactly what the board measures, well below what the link
    carries (~43Mbit/s UDP on the same air). The larger window is covered
    by the existing PBUF_POOL, so there is no additional static memory
    cost. The send buffer is unchanged.
  2. mimxrt: use full-size TCP segments and windows. The port used the
    smallest lwipopts_common.h tier: MSS=800, a 6400-byte window and an
    8000-byte heap. That caps TCP at single-digit Mbit/s on WiFi RTTs and
    costs per-packet efficiency everywhere. Switch to MSS=1460 with a 7MSS
    receive window, 6
    MSS send buffer and a 13K heap — sized so the heap
    comfortably exceeds the send buffer, keeping lwIP's ERR_MEM retry path
    cold. All values are #ifndef-guarded so boards can override them, and
    only boards with a network interface build lwIP on this port (all of
    which have ample OCRAM).

Measured (Python socket benchmarks, 2.4GHz WiFi, same board/AP/position
per pair, multiple runs):

Board Test before after
OPENMV_N6 (CYW43439) TCP RX ~31 Mbit/s 35–39 Mbit/s
OPENMV_N6 TCP TX / UDP unchanged
OpenMV RT1060 (CYW4343W) TCP TX 6.4 Mbit/s 22.2 Mbit/s (3.5x)
OpenMV RT1060 TCP RX 15.9 Mbit/s 24 Mbit/s (1.5x)
OpenMV RT1060 UDP unchanged

100M ethernet on the RT10xx still runs at line rate (91/91 Mbit/s TCP),
and the N6's gigabit ethernet is unaffected (its sub-millisecond RTT was
never window-limited).

Testing

Runtime tested with TCP/UDP benchmarks in both directions on an OpenMV N6
(CYW43439 WiFi + RGMII ethernet) and an OpenMV RT1060 (CYW4343W WiFi +
100M ethernet), numbers above.

Build-tested: OPENMV_N6, TEENSY41, MIMXRT1060_EVK.

Trade-offs and Alternatives

The mimxrt change grows lwIP's static footprint by roughly 20K on
network-enabled boards (heap + full-size pbuf pool). Boards that want the
old sizes can override any value before the guarded block. The stm32
change is N6-scoped and costs nothing beyond window accounting.

Generative AI

I used generative AI tools when creating this PR, but a human has checked
the code and is responsible for the code and the description above.

TCP receive throughput is bounded by window/RTT.  At the ~5-6ms
round-trip time of the OPENMV_N6's CYW43439 WiFi link, the 16*MSS
window works out to ~31Mbit/s -- and that is exactly what the board
measures, well below what the link otherwise carries (~43Mbit/s UDP on
the same air).  Double the receive window to 32*MSS: it is covered by
the existing PBUF_POOL (32 buffers), so there is no additional static
memory cost, and the send buffer is unchanged.

Measured on an OpenMV N6 (Python socket benchmark, 2.4GHz, same
board/AP/position): TCP receive over WiFi improves from ~31Mbit/s to
35-39Mbit/s; TCP transmit and UDP are unchanged, and ethernet on the
same board is unaffected (its sub-millisecond RTT was never
window-limited).

Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
The port used the smallest lwipopts_common.h memory tier: MSS=800,
an 8*MSS=6400 byte window and an 8000 byte heap.  On WiFi round-trip
times that window caps TCP at window/RTT, and the sub-MTU MSS costs
per-packet efficiency on every link.  Measured on an OpenMV RT1060
(CYW4343W WiFi): TCP was limited to 6.4Mbit/s transmit / 15.9Mbit/s
receive.

Switch to MSS=1460 with a 7*MSS receive window, 6*MSS send buffer and a
13K heap (sized so the heap comfortably exceeds the send buffer, keeping
lwIP's ERR_MEM retry path cold).  With this configuration the same
benchmark measures 22.2Mbit/s transmit / 24Mbit/s receive (3.5x / 1.5x),
with UDP unaffected.  100M ethernet on the same silicon still runs at
line rate.

All values are guarded so a board can override them, and only boards
with a network interface build lwIP on this port.

Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
@kwagyeman kwagyeman moved this to In progress in OpenMV Features Aug 16, 2026
@kwagyeman kwagyeman changed the title Kwabena/net lwip buffers ports: Increase the STM32N6/MIMXRT TCP receive window. Aug 16, 2026
@github-actions

Copy link
Copy Markdown

Code size report:

Reference:  shared/runtime/pyexec: Don't execute empty line in event driven REPL. [2e3304a]
Comparison: mimxrt/lwip_inc: Use full-size TCP segments and windows. [merge of 10cf2e0]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
      esp32:    +0 +0.000% ESP32_GENERIC
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@Mrpli

Mrpli commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

3 participants