Failures in an MSP430 Application using FreeRTOS

billy4893 wrote on Wednesday, September 18, 2013:


I have an application using FreeRTOS in an MSP430F5438A that is configured with Code Memory large, data memory model restricted,
and data near as globals.

I am seeing two failures in the application:

  1. The vApplicationStackOverflowHook is called with pcTaskName IDLE. So supposedly the IDLE task is having an overflow
  2. At times the MSP430 will end up no where, basically no longer executing the FreeRTOS, with the program counter pointing to 0x4 or some other very high location that is basically illegal

A brief description of my application:
I have a total of 8 user created tasks. These tasks basically process UART, I2C and a few other things. The majority of them
are blocking on queues (one or two are using vTaskDelay to wait a certain amount of time). These queues are being filled from ISRs that
trigger on data from UART and I2C if certain conditions are met. The ISRs don’t call any other functions except xQueueSendFromISR so as to keep the ISRs short.

Here is the main stuff from FreeRTOSConfig.h

#define configUSE_PREEMPTION			0
#define configUSE_IDLE_HOOK				1
#define configUSE_TICK_HOOK				0
#define configCPU_CLOCK_HZ				( 25000000UL )
#define configLFXT_CLOCK_HZ       		( 32768L )
#define configTICK_RATE_HZ				( ( portTickType ) 1000 )
#define configMAX_PRIORITIES			( ( unsigned portBASE_TYPE ) 10 )
#define configTOTAL_HEAP_SIZE			( ( size_t ) ( 12 * 1024 ) )
#define configMAX_TASK_NAME_LEN			( 10 )
#define configUSE_TRACE_FACILITY		0
#define configUSE_16_BIT_TICKS			1
#define configIDLE_SHOULD_YIELD			1
#define configUSE_MUTEXES				1
#define configQUEUE_REGISTRY_SIZE		1
#define configUSE_RECURSIVE_MUTEXES		1
#define configUSE_MALLOC_FAILED_HOOK	1

	#define configMINIMAL_STACK_SIZE		( ( unsigned short ) 80 )
	#define configMINIMAL_STACK_SIZE		( ( unsigned short ) 480 )

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 		0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Software timer definitions. */
#define configUSE_TIMERS				1
#define configTIMER_TASK_PRIORITY		( 3 )
#define configTIMER_QUEUE_LENGTH		10

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet		1
#define INCLUDE_uxTaskPriorityGet		1
#define INCLUDE_vTaskDelete				1
#define INCLUDE_vTaskCleanUpResources	0
#define INCLUDE_vTaskSuspend			1
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay				1
#define INCLUDE_uxTaskGetStackHighWaterMark 1

I first thought that I actually had some ISRs triggering and causing a stack overflow in the IDLE task, but I am not sure this is
the actual cause. I say this because when the failure occurs, the pxCurrentTCB shows that the top of the stack is above the pxStack variable, and the pxStack points to an area of memory with more than 25 bytes of the 0x5A filler, so in fact the conditions for stack overflow don’t seem to be present, and yet I still get an overflow.

In any case, I increased the IDLE task’s stack size by increasing configMINIMAL_STACK_SIZE to 480 as you can see above, although my tasks are not deriving their stack size from this variable otherwise I wouldn’t be able to fit everything. My tasks don’t seem to need more stack.
I’ve added uxEnforaHighWaterMark checks in all my tasks and I never see them drop below 200 or so. I realize its not checking it all the time since I check this after the queue is read. In fact, I created a table with pointers to all the tasks when they’re created and looked at their TCBs.I don’t see any stack overflow conditions.

One suspicious occurrence I see is that I sometimes see the Stack Pointer of the CPU to point at a location above the top of the stack of one task,
but below the pxTask of the next task. This is seen at least in failure #2 above, but maybe also in failure #1.

Any help would be appreciated and if there is a detail missing please let me know.

rtel wrote on Wednesday, September 18, 2013:

There is nothing that stands out as being wrong. I would make the comment that sending individual characters on a queue in this manner is not very efficient. If you have a low baud rate it will be ok, but it might struggle at higher baud rates. Although the demo applications do this it is only to demonstrate using API functions from an interrupt - real applications are better off using a circular buffer or DMA, then a single semaphore to wake a task when a complete message is ready to process.

Which compiler are you using?

Out of interest, as the stack overflow seems to be incorrect, have you tried running the application with configCHECK_FOR_STACK_OVERFLOW set to 0? I’m just wondering if there might possibly be a problem with the overflow checks when the large data model is used - I know overflow detection cannot be used on segmented memory architectures such as x86. Having said that, I have checked the official demos and they seem to be using overflow detection.


billy4893 wrote on Wednesday, September 18, 2013:

Hi Richard,

Thanks for the quick response. The queue is not to send the characters individually. It simply indicates when a TX or RX operation is done. The characters are sent in the ISR automatically and this data is placed on a buffer which the ISR reads. Once the count is done, the task is informed that it is sent, or that a message was received. The same with I2C.

I am using Code Composer Studio Version: with compiler V4.1.5.

I’ll try disabling it and see whether that makes a difference.

rtel wrote on Wednesday, September 18, 2013:

The comment about the efficient use of queues was just an aside - even if the queues could not keep up with your baud rate it should not cause a crash in the way you are describing.