Well I think I finally have this sorted! The previous post is what sorted it for me. On this platform, and the way FreeRTOS uses the buffers, I don’t see how a complete zero-copy driver can work. I need one copy from the peripheral ram into the static buffers. This, I beleive, applies equally to
BufferAllocation_2.c
on this platform.
For anyone else trodding down this path, attached is the NetworkInterface.c that is working with the LPC1788.
The main points of interest are below:
In
prvEMACHandlerTask()
“`cpp
if( xDataLength > 0U )
{
// Obtain a network buffer to pass this data into the
// stack. No storage allocation is required as the network buffer is already allocated.
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );
if( pxNetworkBuffer != NULL )
{
/* begin custom read code */
// get a temporary structure for reading from the MAC
EMAC_PACKETBUF_Type pRXBuff;
// it's buffer pointer goes to the same buffer we just got from above
pRXBuff.pbDataBuf = (uint32_t *)pxNetworkBuffer->pucEthernetBuffer;
// tell it how much data it's going to store
pRXBuff.ulDataLen = xDataLength;
pxNetworkBuffer->xDataLength = xDataLength;
// ** copy the data from the peripheral buffer to our static buffer
// almost a zero copy driver...
EMAC_ReadPacketBuffer( &pRXBuff );
/* end custom read code */
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
/* Data was received and stored. Send a message to the IP task to let it know. */
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
iptraceETHERNET_RX_EVENT_LOST();
}
}
else
{
iptraceETHERNET_RX_EVENT_LOST();
}
iptraceNETWORK_INTERFACE_RECEIVE();
}
…
// check for TX buffers to release
if( txFreeCount )
{
while( txFreeCount )
{
txFreeCount–;
vClearTXBuffer();
}
}
“`
I then took the
vClearTXBuffer()
out of the ISR so it can clear the buffer AND the descriptor:
“`cpp
// release the buffer after the DMA transmitted it.
static void vClearTXBuffer( void )
{
NetworkBufferDescriptor
t *pxBuffer = trackNetworkBuffers[ trackTail++ ];
if( trackTail >= ipconfigNUMNETWORK
BUFFERDESCRIPTORS )
{
trackTail = 0;
}
if( xTCPWindowLoggingLevel > 2 )
{
FreeRTOS_debug_printf( ( "Clearing buff %#xn", pxBuffer ) );
}
configASSERT( pxBuffer != NULL );
vReleaseNetworkBufferAndDescriptor( pxBuffer );
}
“`
The TX_DONE IRQ handler was simplified
cpp
if( ( ulInterruptCause & EMAC_INT_TX_DONE ) != 0UL )
{
// keep track of how many buffers have been sent
txFreeCount++;
}
And finally
xNetworkInterfaceOutput()
“`cpp
/* Will the data fit in the Tx buffer?
/
if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /RB The size needs to come from FreeRTOSIPConfig.h.
/
{
/ format the data for the Tx DMA. */
TXBuffer.ulDataLen = pxNetworkBuffer->xDataLength;
TXBuffer.pbDataBuf = (uint32_t *)pxNetworkBuffer->pucEthernetBuffer;
/* track the DMA buffer pointer for release later (in the ISR) */
trackNetworkBuffers[ trackHead++ ] = pxNetworkBuffer;
if( trackHead >= ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS )
{
trackHead = 0;
}
if( xTCPWindowLoggingLevel > 2 )
{
FreeRTOS_debug_printf( ( "Sending buff %#xn", pxNetworkBuffer ) );
}
/* copy the buffer to the Tx DMA descriptor. */
EMAC_WritePacketBuffer( &TXBuffer );
EMAC_UpdateTxProduceIndex();
/* Do not release it until it has been sent. */
xReleaseAfterSend = pdFALSE;
iptraceNETWORK_INTERFACE_TRANSMIT();
/* The Tx has been initiated. */
xReturn = pdPASS;
}
“`
Maybe this can get rolled into the supplied NetworkInterface.c file for LPC17xx? It is very incomplete.