at the moment I'm writing a Zero Copy NetworkInterface for LPC1758 using the LPCOpen Platform and I got some questions.
I just got a running version using 20 statically allocated 1560B NetworkBuffers with 4 RX/TX DMA Descriptors. TX cleanup is done within the ISR, while RX defers to a handler/task. This task should also check the PHY status every 15s.
I saw there is a FreeRTOS_NetworkDown() function, but how do I set the network back up, once a cable gets connected (and restart dhcp, etc.)?
Is it possible to do the RX within the ISR? I saw there is pxNetworkBufferGetFromISR, but what about xSendEventStructToIPTask and eConsiderFrameForProcessing? Latter is not that important, as it can be done by the MAC.
The LPC1758 has 32kb + 2x16kb SRAM, where I use the last two for the 20 Network Buffers.
What would be a perfomant yet memory conservative configuration? Are 10 Buffers enough, or should the MTU be reduced?
And regarding these defines
//define ipconfigTCPRXBUFFERLENGTH ( 4 * ipconfigTCPMSS )
//define ipconfigTCPTXBUFFERLENGTH ( 4 * ipconfigTCPMSS )
am I right in my assumption, that for each TCP socket new buffers get allocated? Isn't this redundant to the NetworkBuffers? Won't I end up with no memory left for my actual application?
Thanks a lot,
In order to save RAM usage, you can either decrease
ipconfigNETWORK_MTU, or define a smaller MSS directly:
/* In stead of the default value of MSS: */
#define ipconfigTCPMSS ( ipconfigNETWORKMTU - ipSIZEOFIPv4HEADER - ipSIZEOFTCPHEADER )
/* use a smaller size, hard-coded as e.g.: */
#define ipconfigTCP_MSS ( 512 )
ipconfigTCP_MSS will only have effect on the usage of RAM if you use
As you use
BufferAllocation_1.c, it is better to decrease the size of the MTU. So you will declare e.g. 20 statically allocated 640 byte NetworkBuffers.
TX cleanup is done within the ISR, while RX defers to a handler/task
I would rather defer all work to the task. Doing a clean-up within an ISR is more error-prone, and it leaves your CPU in an interrupt state for longer periods of time.
Earlier I did compare both approaches and only found a minor difference in performance. The time that passes between
ulTaskNotifyTake() is very short.
An exception to the above approach would be ultra-fast signal processing, and situations where deterministic and real-time aspects prevail.
When you only have 20 NetworkBuffers, it becomes important to decide as early as possible whether packets have your unit as a destiny. I have seen a system misbehave because loads of unsolicited UDP-broadcast packets were received. You might test them immediately after reception. This function can be used to test for UDP port numbers:
if( ipconfigETHERNETDRIVERFILTERS_PACKETS == 1 )
/* This define makes it possible for network-card drivers to inspect
* UDP message and see if there is any UDP socket bound to a given port
BaseType_t xPortHasUDPSocket( uint16_t usPortNr )
This task should also check the PHY status every 15s.
You could change this rule to: "check the PHY status 15s after reception of the last packet". As long as you receive Ethernet packets, the Link Status will be OK.
As long as the LS is low, you might want to check the PHY status every second to get a quick response.
I saw there is a FreeRTOS_NetworkDown() function, but how do I set
the network back up, once a cable gets connected (and restart dhcp, etc.)?
Here I'm in doubt about the answer.
In my applications / network interfaces, I will never call
FreeRTOS_NetworkDown() at all. When LS goes down, the driver must stop transmitting packets, and that's all.
Open TCP sockets will continue to do their work and eventually time-out or return an error. If the LS becomes high again, open TCP connections will continue where they were.
The above approach will get you into trouble if your device is battery-operated and moves to a different LAN with a different DHCP server.
xNetworkInterfaceInitialise() will be called repeatedly until it returns a non-zero value.
#define ipconfigTCPRXBUFFERLENGTH ( 4 * ipconfigTCPMSS )
#define ipconfigTCPTXBUFFERLENGTH ( 4 * ipconfigTCPMSS )
am I right in my assumption, that for each TCP socket new buffers get allocated?
Each TCP socket has 2 circular stream buffers, one for reception and one for transmission. Each buffer is created when needed, and it will continue to exist until
closesocket() is called.
The advantage is that guarantees about buffer-space can be given in both directions: a connected TCP socket will never throw an error 'out-of-memory'. TCP connections will be more stable.
The disadvantage is that an-idle-but-connected socket still holds buffers in RAM.
There is a socket option
FREERTOS_SO_WIN_PROPERTIES that lets you determine all buffer- and window-sizes within a single call.