Memcpy within a task stops application

Hi,

My setup:
LPC1769
FreeRTOS 10.3.2
IAR Workbench

I have an issue with memcpy within one of my tasks. After I searched in the forum, I noticed there are some other complaints. It is mostly if memcpy is used within an interrupt.

I am not using it inside an interrupt. It is probably something else.

Here is some piece of code where I have memcpy;

  int32_t uart1_readline(void)
  {
  	char c = '\0';
  	char i = 0;
  	while(c != LF)
  	{
  		if(uart1_fifo.num_bytes > 0){
  			c = uart1_getc();
  			memcpy(&uart1_fifo.line[i], c, 1);
  			i++;
  		}
  	}
  	c = '\0';
  	memcpy(&uart1_fifo.line[i], c, 1);
  	return i;
  }

Once it hits the memcpy line , application stops.

Those is a relevant post in the forum here

Not sure though if it is exactly the thing.

Any pointers greatly appreciated.

Sener

Not sure why you need memcpy here. Isn’t simple assignment enough?

uart1_fifo.line[i] = c;

There is no bound checking for the uart1_fifo.line buffer. Are you overflowing it?

Thanks.

@aggarg,

That makes us two. It was a copy and paste code from an example code in FreeRTOS.
I gave a try your advise and changed it touart1_fifo.line[i] = c;
Now it stuck at that line. So, apparently, memcpy was not the issue.

How come then assigning a value to a member of a struct be an issue?

Declaration of the struct:

typedef struct
{
volatile uint32_t i_first;
volatile uint32_t i_last;
volatile uint8_t rx_ovf;
volatile uint8_t fifo_full;
volatile uint32_t num_bytes;
volatile uint8_t rx_not_empty;
volatile uint8_t rx_status;
volatile uint32_t error_count;
volatile uint32_t fifo_size;
volatile uint32_t line_size;
char * rx_fifo;
char * line;
}UART_RING_BUFFER;

this is the definition:

UART_RING_BUFFER uart1_fifo;

and initialization before use:

  	uart1_fifo.i_first 			= 0;			
  	uart1_fifo.i_last 			= 0;				
  	uart1_fifo.rx_ovf 			= 0;
  	uart1_fifo.fifo_full 		= 0;
  	uart1_fifo.num_bytes 		= 0;
  	uart1_fifo.rx_not_empty 	= 0;
  	uart1_fifo.error_count		= 0;
  	uart1_fifo.fifo_size		= UART1_RX_FIFO_SIZE;
  	uart1_fifo.rx_fifo 			= (char *) malloc(uart1_fifo.fifo_size);	
  	uart1_fifo.line_size 		= UART1_LINE_SIZE;
  	uart1_fifo.line				= (char * ) malloc(uart1_fifo.line_size);

I think found the issue. Now it works as I wanted.

I had those definitions.

  #define UART1_RX_FIFO_SIZE			1024
  #define UART1_LINE_SIZE				512

When I decreased to 1 quarter of the allocated memory using those definitions, it has started to work.

  #define UART1_RX_FIFO_SIZE			256
  #define UART1_LINE_SIZE				128

Although it works and I don’t need much more memory, I like to know what we should do to run it in higher memory allocations.

I am not sure which memory is used there. Is it in stack or in heap?

I have that definition in FreeRTOSConfig.h

#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 19 * 1024 ) )

You should really limit the loop to i < uart1_fifo.line_size until finding a match of end-of-line (LF) (or not) and shouldn‘t you decrement uart1_fifo.num_bytes somewhere ?

I am not sure which memory is used there. Is it in stack or in heap?

Since you are using malloc, it is coming from heap. Looking at the symptoms, it seems that the malloc was failing previously. You should check the return value of malloc to ensure that it was successful.

Which heap are you using? If you are using heap_4.c, can you replace these malloc calls with pvPortMalloc so that the memory comes from the one configured using configTOTAL_HEAP_SIZE ?

Thanks,
Gaurav

@aggarg, I was using heap_2.c. I have replaced it with your suggestion heap_4.c.
and replaced malloc with pvPortMalloc.

Initially, It seemed to work even with the original high memory allocation. But, after exact 10 lines of data received, uart has stopped receiving any more (I didn’t debug it yet for finding the reason). Therefore, once again, while I am still using pvPortMalloc, I lowered the memory size to 1 quarter of 1024. It has then allowed me to enter many lines. I tested more than 100 lines one after each other. It didn’t cause any issue.

You may consier using static buffers too:

char line_buffer[ UART1_LINE_SIZE ];
char fifo_buffer[ UART1_RX_FIFO_SIZE ];

uart1_fifo.fifo_size	= UART1_RX_FIFO_SIZE;
uart1_fifo.rx_fifo 		= &( fifo_buffer[0] );	
uart1_fifo.line_size 	= UART1_LINE_SIZE;
uart1_fifo.line			= &( line_buffer[0] );

Also, you need to ensure that you are not overflowing the line buffer:

 int32_t uart1_readline(void)
  {
  	char c = '\0';
  	char i = 0;
  	while(c != LF)
  	{
  		if(uart1_fifo.num_bytes > 0){
			/* -1 is done to ensure there is space for NULL terminator. */
			if( i < UART1_LINE_SIZE - 1 )
  			{
				c = uart1_getc();
				uart1_fifo.line[i] = c;
				i++;
			}
			else
			{
				/* Line buffer is full, so break. */
				break;
			}
  		}
  	}

  	c = '\0';
  	uart1_fifo.line[i] = c;
  
	return i;
  }

Thanks.

Thanks a lot Gaurav, I appreciated. It did the trick. It is now also working with my default memory size.

If sum-up the things I implemented;

  1. Switched to direct assignment rather than using memcpy
    (I have still a hunch, the compiler might decide to use memcpy internally)
  2. Replaced heap_2.c with heap_4.c
  3. Replaced malloc with pvPortMalloc
  4. Static buffers used