Networking — FreeRTOS-Plus-TCP¶
Verification note for this module: FreeRTOS-Plus-TCP requires a network interface driver bound to real or emulated hardware (a MAC/PHY, or a WinPCap/libpcap-backed interface for its own Windows/Linux simulation targets) — there is no network stack wired into the POSIX-port build used elsewhere in this course, and setting one up was out of scope for this pass. Content here is a careful review of the FreeRTOS-Plus-TCP API and its own published architecture documentation, not code executed on this machine.
Why a separate TCP/IP stack, and why it looks like more FreeRTOS¶
FreeRTOS-Plus-TCP is Amazon/the FreeRTOS project's own lwIP-alternative
TCP/IP stack, built from the ground up around FreeRTOS primitives rather
than ported from a different RTOS's networking code. This shows up directly
in its API: the stack's internal state machine runs as its own task
(the IP task, prvIPTask), and application code interacts with sockets
using an API deliberately shaped like BSD sockets but implemented entirely
on top of FreeRTOS queues and semaphores underneath — consistent with every
other subsystem this course has covered rather than a foreign layer bolted
on top.
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
static const uint8_t ucIPAddress[4] = {192, 168, 1, 50};
static const uint8_t ucNetMask[4] = {255, 255, 255, 0};
static const uint8_t ucGatewayAddress[4] = {192, 168, 1, 1};
static const uint8_t ucDNSServerAddress[4] = {8, 8, 8, 8};
static const uint8_t ucMACAddress[6] = {0x00,0x11,0x22,0x33,0x44,0x55};
void vStartNetworking(void) {
FreeRTOS_IPInit(ucIPAddress, ucNetMask, ucGatewayAddress,
ucDNSServerAddress, ucMACAddress);
// network driver's own task/interrupt path calls xSendEventStructToIPTask()
// to hand received frames to the IP task from here on
}
The IP task: everything serialized through one place¶
A deliberate architectural choice: all stack state (routing, socket
buffers, ARP cache) is only ever touched by the single IP task, and every
other task's socket call (FreeRTOS_send, FreeRTOS_recv, FreeRTOS_connect)
is translated into a message sent to the IP task's own queue, processed
serially. This is precisely Level 2 Module 8's gatekeeper pattern, applied
at network-stack scale — no stack-internal mutex forest to get wrong, because
only one task ever mutates stack state:
Socket_t xSocket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM,
FREERTOS_IPPROTO_TCP);
struct freertos_sockaddr xRemote = {
.sin_family = FREERTOS_AF_INET,
.sin_port = FreeRTOS_htons(80),
.sin_addr = FreeRTOS_inet_addr("192.168.1.1"),
};
FreeRTOS_connect(xSocket, &xRemote, sizeof(xRemote));
FreeRTOS_send(xSocket, "GET / HTTP/1.0\r\n\r\n", 19, 0);
char buf[512];
BaseType_t received = FreeRTOS_recv(xSocket, buf, sizeof(buf), 0);
Application code never touches IP-task-owned state directly — every one of these calls blocks the calling task (if configured to) while the IP task does the real work, exactly mirroring how a gatekeeper task's queue decouples callers from the resource owner.
Zero-copy buffers and driver integration¶
NetworkBufferDescriptor_t structures are the stack's currency for received
and to-be-sent Ethernet frames — designed so a driver's receive-interrupt
handler can hand a buffer straight to the IP task without an extra memcpy,
and so the IP task can hand a transmit buffer straight to the driver's send
path the same way. This buffer-passing-by-reference design is why
ipconfigZERO_COPY_TX_DRIVER/ipconfigZERO_COPY_RX_DRIVER exist as explicit
configuration knobs — whether a given MAC driver can genuinely avoid the
copy depends on whether its DMA descriptors can point directly at
FreeRTOS-Plus-TCP's own buffer pool memory.
TCP window, retransmission, and the RTOS timing connection¶
FreeRTOS-Plus-TCP implements its own TCP state machine (windowing,
retransmission timers, ipconfigTCP_WINDOW_SIZE for RAM/throughput
trade-offs) rather than delegating to any OS network stack — which means
every one of this course's earlier lessons about task priorities and ISR
latency (Module 7) applies directly to network performance: if the IP task
runs at too low a priority relative to application tasks that hog the CPU,
TCP retransmission timers and ACK generation can be delayed enough to tank
throughput, exactly the same mechanism as any other priority-starvation
scenario covered earlier in this course, just manifesting as "the network is
slow" instead of "a sensor reading is late."
How It Actually Works (the IP task as a single-threaded kernel-within-a-kernel)¶
FreeRTOS+TCP resolves the classic "shared mutable network state accessed
from many tasks" problem the same way the gatekeeper pattern does at
application level: essentially all protocol state (sockets, the ARP cache,
routing) is only ever touched by one task, the IP task, and every socket
call from application tasks (FreeRTOS_send, FreeRTOS_recv) is translated
into a message sent over an internal queue to that task rather than
manipulating shared state directly from the caller's own context — this is
why it "looks like more FreeRTOS" rather than a bolted-on library: it's
built from the exact same queue-and-task primitives as your application
code, just applied to protocol state instead of sensor data. Zero-copy
buffers exist because a memcpy of every packet between the network driver
and the IP task would be real, measurable overhead at typical Ethernet
rates — instead a buffer descriptor (a pointer plus length) moves through
the queue while the actual payload bytes stay put in DMA-accessible memory
that both the driver and the IP task can reach. The TCP-timing connection is
direct: retransmission timers and the window/congestion logic are themselves
implemented as callbacks off the same tick-driven timing infrastructure
covered in the software-timers module, which is why a starved or delayed IP
task shows up as real, measurable jitter in your TCP round-trip times.
Traps¶
- Setting the IP task's priority too low. Because all socket operations
route through it, a starved IP task doesn't just slow networking — it can
make application tasks blocked in
FreeRTOS_send/recvwait far longer than the network round-trip time alone would suggest, an easy misdiagnosis (blaming "the network" for what's actually a priority configuration problem). - Calling FreeRTOS-Plus-TCP socket functions from an ISR. Like every
other kernel API this course has covered, socket calls are task-context
only — a driver's receive ISR must hand frames off via the documented
xSendEventStructToIPTask/buffer-descriptor path, not call socket functions directly. - Undersizing
ipconfigTCP_WINDOW_SIZEor buffer counts on a RAM-constrained target and then being surprised by poor throughput — networking RAM budgets trade directly against every other subsystem's RAM needs (task stacks, queues) covered throughout this course, and need to be planned as part of the same overall budget, not as an afterthought. - Assuming zero-copy is automatic. It requires a driver written to hand
DMA descriptors directly into the stack's buffer pool — a driver that
internally copies into its own buffers first defeats the purpose even with
ipconfigZERO_COPY_*enabled. - Treating this module's coverage as sufficient for a real network security posture. FreeRTOS-Plus-TCP handles the transport; TLS (usually via mbedTLS integration) and the broader secure-firmware concerns of Level 4 Module 5 are separate, additional layers this module does not cover.
Cheat sheet¶
| Concept | Standard FreeRTOS pattern it mirrors | Purpose |
|---|---|---|
| IP task | Gatekeeper task (Level 2 Module 8) | Serializes all stack state access |
| Socket API calls | Queue send/receive to the gatekeeper | Decouples callers from stack internals |
NetworkBufferDescriptor_t |
Pass-by-reference buffer, like a stream buffer chunk | Avoids extra copies between driver and stack |
| IP task priority | Same priority-starvation rules as Module 7 | Network throughput is a scheduling problem too |
ipconfigTCP_WINDOW_SIZE |
Same RAM-budget trade-off as queue/stack sizing | Throughput vs. RAM |
Exercise¶
- Read the FreeRTOS-Plus-TCP source for
FreeRTOS_sendand trace exactly how it hands off to the IP task's queue — identify the specific point where a calling task's priority stops mattering and the IP task's priority takes over. - On a real target with FreeRTOS-Plus-TCP integrated, deliberately set the IP task's priority below several CPU-hogging application tasks and measure the throughput/latency impact — then correct the priority and confirm the improvement, directly connecting this module's warning to a measured result.
- Design a buffer/window-size budget for a target with 64KB total RAM running three FreeRTOS-Plus-TCP sockets simultaneously, alongside the task stacks and queues from a prior Level 2 project — show your full RAM accounting, not just the networking portion.