Problem with heap_4 in FreeRTOS-TCP

Hello,
I’m trying to use TCP stack on ARM Cortex-M3 based MCU (MAC driver is a separate SPI chip) and recently I have accounted a problem.
Application is running some time after starting FreeRTOS_IPInit(). It recieves packets and even can transmit them (at least application manage to send ARP announcment). But then it’s getting infinite loop inside this function:

  pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( xBytesReceived, 0);

I read forum looking for similar problems and found that I can use “configASSERT( x )” to to find where a problem can be.
So this lead me to file’s “heap_4.c” function “void * pvPortMalloc( size_t xWantedSize )”, line 206:

  pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

Clearly I got some problem with memory managment, but there’s no tasks using memory allocation, exept FreeRTOS-TCP kernel and one I created to recieve frames.

Can someone help me with this one?

Is this the assert you get stuck in? https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/V10.4.6/portable/MemMang/heap_4.c#L207

Do you handle cases where you run out of heap space? Do you have a malloc failed hook defined?

Is this the assert you get stuck in? _ttps://github.com/FreeRTOS/FreeRTOS-Kernel/blob/V10.4.6/portable/MemMang/heap_4.c#L207

Yes, that’s right.
Malloc failed hook defined but with assert enabled application never reach it.
If I disable assert then application fall into infinite loop here
_ttps://github.com/FreeRTOS/FreeRTOS-Kernel/blob/V10.4.6/portable/MemMang/heap_4.c#L399
Or sometimes in Malloc failed hook.
P.S. there’s almost no tasks in my application now, and surelly enough memory to hold more frames, I can see it in debbuger.
P.P.S. Sorry for links, new user)

Can you try increasing the heap size? The heap size is controlled using configTOTAL_HEAP_SIZE macro in your FreeRTOSConfig.h file.

I’ll definitely try that tomorrow, but it’s already 2/3 of MCU RAM.

#define configMINIMAL_STACK_SIZE ( ( uint16_t ) 256 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 20 * 1024 ) )
#define configSUPPORT_DYNAMIC_ALLOCATION 1

I heard this can happen due to data corruption.
There’re two places where dynamic allocation used
First is ethernet buff receive routine (don’t look that it’s not a deferred interrupt and not dma, I just want make it work first)

void ethRxThread(void *arg)
{
	NetworkBufferDescriptor_t *pxBufferDescriptor = NULL;
	size_t xBytesReceived = 0;
	IPStackEvent_t xRxEvent;
	uint8_t FSC[4] = {0};
	uint8_t packet_cnt = 0;

	for( ;; )
	{
		packet_cnt = (u32_LAN9352_readReg(MDR_SSP1, RX_FIFO_INF) & 0x00FF0000) >> 16;						// See how many Ethernet frames were received
		if((packet_cnt > 0) && (packet_cnt < 0xFF))
		{
			for(uint8_t i = 0; i < packet_cnt; i++)
			{
				xBytesReceived = ((u32_LAN9352_readReg(MDR_SSP1, RX_STATUS_FIFO) & 0x3FFF0000) >> 16) - 4;		// See how much data a single frame contain (minus FSC)
				pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( xBytesReceived, pdMS_TO_TICKS(0) );		// Allocate a network buffer descriptor
				if( pxBufferDescriptor != NULL )
				{
					portENTER_CRITICAL();
					u8_LAN9352_recieveBuf(MDR_SSP1, RX_FIFO, pxBufferDescriptor->pucEthernetBuffer, xBytesReceived);
					u8_LAN9352_recieveBuf(MDR_SSP1, RX_FIFO, FSC, sizeof(FSC));
					portEXIT_CRITICAL();
					pxBufferDescriptor->xDataLength = xBytesReceived;

					xRxEvent.eEventType = eNetworkRxEvent;
					xRxEvent.pvData = (void *) pxBufferDescriptor;    /// put pointer to the received data in the event

					/// send the event to the TCP/IP stack
					if (xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE)
					{
						/// error, buff couldn't be sent to the IP task, release it and log
						vReleaseNetworkBufferAndDescriptor(pxBufferDescriptor);
						iptraceETHERNET_RX_EVENT_LOST();
					}
					else
					{
						iptraceNETWORK_INTERFACE_RECEIVE(); /// log receive success
					}
				}
				else
				{
					 iptraceETHERNET_RX_EVENT_LOST();
				}
			}
		}
		vTaskDelay(pdMS_TO_TICKS(10));
	}
}

And second is NetworkInterface.c

BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
                                    BaseType_t xReleaseAfterSend )
{
	uint32_t command_a, command_b = 0;
	command_a = COM_A_FIST | COM_A_LAST | (pxNetworkBuffer->xDataLength);
	command_b = 0xAAAA0000 | (pxNetworkBuffer->xDataLength);

	portENTER_CRITICAL();
	u8_LAN9352_writeEthFrame(MDR_SSP1, command_a, command_b, 0, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength);
	portEXIT_CRITICAL();
	iptraceNETWORK_INTERFACE_TRANSMIT();
    if( xReleaseAfterSend != pdFALSE )
    {
    	vReleaseNetworkBufferAndDescriptor(pxNetworkBuffer);
    }
	return pdTRUE;
}

Have you checked for stack overflows?

I use
#define configCHECK_FOR_STACK_OVERFLOW 1
But application almost never fall into it.
I checked pxCurrentTask structure for “ethRxThread” when it got stacked

изображение

Stack is almoust empty.

In Memory debug I can see that application has free space left for frames when it fall into infinite loop. In fact in almost every run it uses only one buffer at 0x20002532. Very rare it happens to use two or three buffers.
изображение

I guess smth derails memory allocation function at some point.

Well, seems it has smth to do with

#define ipconfigETHERNET_MINIMUM_PACKET_BYTES    ( 200 )

When I removed this config parameter everyting now works nicely.