freeRTOS xQueueReceive gives HardFault in LPC1769.

dmh3006 wrote on Tuesday, June 16, 2015:

Hi.

I have a queue between 2 tasks in which one writes certain commands to it and the other reads it (one is an application, the other is the task responsible for the display).

The tasks App sends a command to the task Display. Everything works well and it does as desired. After this the task Display waits for 5 seconds for a new command, if none is received it switches the display off and waits indefinitely for a new command on the queue.

This last part is where my program crashes as it “immediately” (I can’t determine the exact time but as soon as I do a step over in debug it goes to the HardFault_Handler).

I check my main task App data structure and its values remain correct. I cast the xQueueHandle to xQUEUE * and its values are also correct (I’m only checking its length value and size of each item value).

The issue seems to be the xQueueReceived line after a command has been given.

However I’ve verified the code and I’m unable to find any fault whatsoever with it.

Both tasks are allocated 2KB of ram which do not even come close to fully using (the task App consumes the most ram and uses at most 640bytes) so I’ve ruled out stack overflow.

The task App has a priority of tskIDLE_PRIORITY and the task Display has a priority of tskIDLE_PRIORITY+2.

void taskDisplay(xQueueHandle queue)
{
    bool previousCommand = false;
	    uint16_t color;
	    portTickType time = configTICK_RATE_HZ * TIME_TO_DISPLAY_OFF;
	    DisplayCommand command;
	    signed portBASE_TYPE queueResult;
	    for (;;){
		queueResult = xQueueReceive(queue,(void *)&command,previousCommand ? time : portMAX_DELAY);
		if (queueResult == errQUEUE_EMPTY){
			Display_Backlight(false);
			previousCommand = false;
		} else {
			switch (command.command){
			case DISPLAY_ON:
				Display_WriteStr(command.DisplayOnData.lineTemps,font6x8,DISPLAY_ON_FIRST_LINE,FOREGROUND_COLOR,BACKGROUND_COLOR);
				Display_WriteStr(command.DisplayOnData.lineDate,font6x8,DISPLAY_ON_SECOND_LINE,FOREGROUND_COLOR,BACKGROUND_COLOR);
				Display_Backlight(true);
				previousCommand = true;
				break;
			case DISPLAY_WRITE_LINE:
				Display_ClearLine(command.DisplayWriteLineData.line,font6x8);
				Display_WriteStr(command.DisplayWriteLineData.lineText,font6x8,command.DisplayWriteLineData.line,FOREGROUND_COLOR,BACKGROUND_COLOR);
				Display_Backlight(true);
				strncpy(internalBuffer[command.DisplayWriteLineData.line-1],command.DisplayWriteLineData.lineText,NUM_CHAR_PER_LINE);
				previousCommand = false;
				break;
			case DISPLAY_HIGHLIGHT_LINE:
				color = command.DisplayHighlightLineData.highlight ? HIGHLIGHT_COLOR : BACKGROUND_COLOR;
				if (command.DisplayHighlightLineData.useInternalBuffer){
					Display_WriteStr(internalBuffer[command.DisplayHighlightLineData.line-1],font6x8,command.DisplayHighlightLineData.line,FOREGROUND_COLOR,color);
				} else {
					Display_WriteStr(command.DisplayHighlightLineData.lineText,font6x8,command.DisplayHighlightLineData.line,FOREGROUND_COLOR,color);
					strncpy(internalBuffer[command.DisplayHighlightLineData.line-1],command.DisplayHighlightLineData.lineText,NUM_CHAR_PER_LINE);
				}
				previousCommand = false;
				break;
			case DISPLAY_CLEAR:
				Display_Backlight(command.DisplayClearData.turnOffDisplay);
				if (command.DisplayClearData.firstLineToClear == 1 && command.DisplayClearData.lastLineToClear == 16){
					Display_Clear(BACKGROUND_COLOR);
				} else {
					for (int i = command.DisplayClearData.firstLineToClear; i <= command.DisplayClearData.lastLineToClear; i++){
						Display_ClearLine(i,font6x8);
					}
				}
				previousCommand = false;
				break;
			}
		}
	}
}

rtel wrote on Tuesday, June 16, 2015:

So the crash occurs after after the call to xQueueReceive() times out? When it times out the next function is executes is Display_Backlight( false ); - did you put a break point on that and step into that function to see if it completes correctly? After that it should call xQueueReceive() again with portMAX_DELAY, so you can continue stepping through the code and go into that function to see if everything is correct there too (check parameters, etc.).

Do you have configASSERT() defined?

The following page may also help: http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

When you created the queue - did you get the parameters in the call to xQueueCreate() the right way around - so every space in the queue can hold sizeof( DisplayCommand ) bytes?

dmh3006 wrote on Tuesday, June 16, 2015:

My apologies for my delay in answering.

No, the crash occurs after the xQueueReceive times out, it runs the DisplayBacklight(false) executes and when the xQueueReceive is called with the portMAX_DELAY time it crashes there.

The DisplayBacklight(false) executes and finishes correctly as the desired effect on the screen occurs and the function has been tested outside of the freeRTOS environment(it really just sends a command through the SPI interface and sets a GPIO pin to "0").

configASSERT() is not defined as I'm unsure how to define it since I see it in many freeRTOS functions.

I'm not allowed to write any kind of code proposed in the link until the teacher signs off on it (it's a crazy rule).

I've casted the xQueueHandle to a xQUEUE * and looked inside it and and the basic parameters seem to be right (the length of the queue and the size of each element). I've also made sure the queue is correct my verifying the heap space before and after the queue creation and the value of heap after the queue creation corresponds to the expected value (136 bytes for the queue structure and the 400 bytes for the actual buffer, 10 elements, each with a size of 40 bytes).

I've also checked that the following function, when it loads whats on the address given on the first assembly instruction, it's value is 0. (the ldr r0,[r0] instruction actually loads the 0 value to r0 which means the second time it runs that same instruction I have no idea what its actually putting in r0)

static void prvPortStartFirstTask( void )
{
__asm volatile(
" ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. /
/
Loads 0 to the r0 register --> / " ldr r0, [r0] \n"
" ldr r0, [r0] \n"
" msr msp, r0 \n" /
Set the msp back to the start of the stack. /
" cpsie i \n" /
Globally enable interrupts. /
" svc 0 \n" /
System call to start first task. */
" nop \n"
);
}

rtel wrote on Wednesday, June 17, 2015:

I would recommend defining configASSERT() before debugging any further, as it may catch the problem for you. It is best to start with the assert defined on any new project. In its simplest form you can just add:

#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

into FreeRTOSConfig.h. That will stop the code on a line that fails an assert, so when you pause the debugger, you will see which line failed.