← Blog

Teensy 4.1 and Zephyr USB networking: ten times faster from the same chip

In the Pico post a Raspberry Pi Pico at 125 MHz, after some work on code placement, answered more UDP echoes over USB than a stock Teensy 4.1 at 600 MHz. That should not happen. So I did the same investigation on the Teensy.

Short answer: the Teensy has the same problem as the Pico. Zephyr runs all code from the external QSPI flash through the Cortex-M7’s 32 KB instruction cache, and one echo through the USB and network stacks uses about 32 KB of code: as much as the whole cache. The chip has 128 KB of fast instruction memory (ITCM) that Zephyr leaves empty. With the hot code there, plus -O2 and three configuration changes, the Teensy answers 22,359 UDP echoes per second instead of 2,257. A plain list of 32 KB of function names, which is portable between builds, already gives 15,900.

Read the full report for the method, all images, the profiles and the limits. To reproduce it, use the benchmark sample in zephyr-codeplace: with the same placement it gives 22,586 UDP echoes per second against 2,238 for the stock build (2 passes).

First question: is it the memory?

Before any profiling I built three variants: whole network and USB libraries in ITCM, instruction cache off, and data cache off. Libraries in ITCM made the echo 2.8× faster at once; cache off made it 16× slower. So the stock board spends most of its time waiting for code from flash.

A profiler without a debug port

The Teensy has no SWD or JTAG, and I did not want a different board: another flash chip changes exactly what I measure. So the profiler runs on the board: a timer interrupt above Zephyr’s interrupt lock level records where the processor was, about 10,000 times per second. Its code sits in ITCM and its buffer in data TCM, so it does not touch the caches or the flash; with it built in, the echo time does not change.

Peak UDP echo rate for each firmware image
Peak UDP echo rate per image, mean ± SD of 3 passes (2 for the last bar).

After the move, the code itself counts

Once the hot code is in ITCM, the profile changes character: the remaining time is computation, not waiting. Then ordinary tuning starts to pay: -O2 (+12 %), no MPU stack guard (+7 %), no time slicing (+6 %), data in DTCM (+3 %), and CDC-NCM instead of CDC-ECM. Removing the network RX and TX threads lowered the latency but cut the throughput by a third and made the board collapse under overload; I would not do that.

The largest single cost left is the kernel mutex: about 30 lock and unlock pairs per echo, mostly read-only IPv4 address checks under the interface lock. Removing that lock (unsafe, as a measurement only) gives another 11 %.

Limits

One board, one Zephyr version, a small echo application, 32-byte datagrams (1000-byte requests with 256-byte replies: 1,926 → 14,422 per second). The ITCM is free in this test; a real application must share it. The turnaround time of the fast images varies between runs, so I use throughput for decisions. The tools, the on-target profiler and a reproducible benchmark sample are in zephyr-codeplace (introduction).

Evidence: measured on a Teensy 4.1 (i.MX RT1062, 600 MHz, USB high speed), Zephyr main of 31 October 2026, 1 November 2026. Peak rates are the mean of 3 independent passes; the spread is below 1 %.


Made with a notepad.