yanvasilij wrote on Wednesday, February 01, 2017:
Hello,
I’m trying to create Zero-Copy driver for my stm32f429. As describe here I should to declare handler (standard RTOS task) where DMA descriptor with incoming frame (that references the Ethernet buffer containing the received data) are swapped with free FreeRTOS+TCP descriptor. But in my MCU DMA descriptor have only 3 parameters:
/* DMA Descriptors. */
typedef struct {
volatile u32 Stat;
u32 Ctrl;
u32 Addr;
u32 Next;
} RX_Desc;
So I can’t just swap two pointers. So I am trying to bind DMA descriptors with buffers in Pre-created FreeRTOS+TCP descriptors:
static void rx_descr_init (void)
{
u32 i,next;
realisedDesc = xQueueCreate(3, sizeof(int));
RxBufIndex = 0;
for (i = 0, next = 0; i < NUM_RX_BUF; i++) {
if (++next == NUM_RX_BUF) next = 0;
/* this descriptors bind to DMA */
activeFrRtsDesc[i] = pxGetNetworkBufferWithDescriptor(
ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
/* this free descriptors are for swapping when frame come */
freeFrtsDesc[i] = pxGetNetworkBufferWithDescriptor(
ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
/* Binding DMA and FreeRTOS descriptors */
Rx_Desc[i].Stat = DMA_RX_OWN;
Rx_Desc[i].Ctrl = DMA_RX_RCH | ETH_BUF_SIZE;
Rx_Desc[i].Addr = (u32)&activeFrRtsDesc[i]->pucEthernetBuffer;
Rx_Desc[i].Next = (u32)&Rx_Desc[next];
}
ETH->DMARDLAR = (u32)&Rx_Desc[0];
}
When Ethernet interrupt occurs I swap activeFrRtsDesc and freeFrtsDesc:
void ETH_IRQHandler( void )
{
u32 i = RxBufIndex;
do
{
if (Rx_Desc[i].Stat & DMA_RX_ERROR_MASK)
{
}
else if ((Rx_Desc[i].Stat & DMA_RX_SEG_MASK) != DMA_RX_SEG_MASK)
{
}
else
{
/* save data len */
activeFrRtsDesc[i]->xDataLength =
((Rx_Desc[i].Stat >> 16) & 0x3FFF) - 4;
/* swap activeFrRtsDesc and freeFrtsDesc */
NetworkBufferDescriptor_t * tmp;
tmp = activeFrRtsDesc[i];
activeFrRtsDesc[i] = freeFrtsDesc[i];
Rx_Desc[i].Addr = (u32)&activeFrRtsDesc[i]->pucEthernetBuffer;
freeFrtsDesc[i] = tmp;
/* activate freeRtos task that frees realised descriprors */
xQueueSendFromISR(realisedDesc, &i, NULL);
}
Rx_Desc[i].Stat = DMA_RX_OWN;
if (++i == NUM_RX_BUF) i = 0;
}while ( (Rx_Desc[i].Stat & DMA_RX_OWN) == 0);
RxBufIndex = i;
if (ETH->DMASR & INT_RBUIE)
{
/* Rx DMA suspended, resume DMA reception. */
ETH->DMASR = INT_RBUIE;
ETH->DMARPDR = 0;
ETH->DMASR |= INT_RBUIE;
}
/* Clear the interrupt pending bits. */
ETH->DMASR = INT_NISE | INT_RIE;
}
In prvEMACHandlerTask I proceed and free realised FreeRTOS+TCP descriptors:
static void prvEMACHandlerTask( void *pvParameters )
{
IPStackEvent_t xRxEvent;
int realisedBuffer;
emacInit();
for( ;; )
{
if (xQueueReceive( realisedDesc, &realisedBuffer, portMAX_DELAY) == pdFALSE)
continue;
/* processing realised descriptor */
if( eConsiderFrameForProcessing( freeFrtsDesc[realisedBuffer]->pucEthernetBuffer )
== eProcessBuffer )
{
/* The event about to be sent to the TCP/IP is an Rx event. */
xRxEvent.eEventType = eNetworkRxEvent;
/* pvData is used to point to the network buffer descriptor that
now references the received data. */
xRxEvent.pvData = ( void * ) freeFrtsDesc[realisedBuffer];
/* Send the data to the TCP/IP stack. */
if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
{
/* The buffer could not be sent to the IP task so the buffer
must be released. */
vReleaseNetworkBufferAndDescriptor( freeFrtsDesc[realisedBuffer] );
/* Make a call to the standard trace macro to log the
occurrence. */
iptraceETHERNET_RX_EVENT_LOST();
}
else
{
/* The message was successfully sent to the TCP/IP stack.
Call the standard trace macro to log the occurrence. */
iptraceNETWORK_INTERFACE_RECEIVE();
}
}
else
{
/* The Ethernet frame can be dropped, but the Ethernet buffer
must be released. */
vReleaseNetworkBufferAndDescriptor( freeFrtsDesc[realisedBuffer] );
}
/* alloc new descriptor for future */
freeFrtsDesc[realisedBuffer] = pxGetNetworkBufferWithDescriptor(ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
}
}
Does it correct? I get hardfault on eConsiderFrameForProcessing(). What am I doing wrong?
Regards,
Vasilij