HardFault when using Queues in Interrupt

gizm0r wrote on Friday, December 31, 2010:

Hi,

I’m running the recent version of FreeRTOS on my Cortex M3 (LPC1768).

It runs fine, but if I want to send anything to a queue from an interrupt it crashed (jumps to HardFault).
I tried “xSemaphoreGiveFromISR” and “xQueueSendToBackFromISR”, but both of them will crash at the memcpy command.

I used the functions the same way as in the samples, so I don’t see what’s wrong there? Is there anything I need to setup in the config for it to run?
The usage of the queues from normal tasks works without any problems.

I hope anyone can help me with this problem.

Bye
Gizmor

rtel wrote on Friday, December 31, 2010:

Have you taken into account point 3 on the following page?

Regards.

gizm0r wrote on Friday, December 31, 2010:

Thanks for your response!
Yes, I already found this, but I’m not fully understandig how to use it :slight_smile:

In FreeRTOSConfig.h there are the following settings (from the included lpc1768 demo):

#define configPRIO_BITS       5        /* 32 priority levels */
/* The lowest priority. */
#define configKERNEL_INTERRUPT_PRIORITY 	( 31 << (8 - configPRIO_BITS) ) //248
/* Priority 5, or 160 as only the top three bits are implemented. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( 5 << (8 - configPRIO_BITS) ) //40

I tried to set different priorities to my Interrupt (UART2). But it doesn’t change anything if I set it to 0 (highest), to 31(lowest) or to anything between.

rtel wrote on Friday, December 31, 2010:

How are you setting the interrupt priority?  Directly, or using a function.

Do you have the stack overflow checking switched on?

Can you post your entire ISR code?

Is the UART enabled?  – does it work ok without the call to the queue function?

Regards.

gizm0r wrote on Friday, December 31, 2010:

I use the CMSIS Macro => NVIC_SetPriority(UART2_IRQn, 10);

static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M  System Interrupts */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}

So, this should be correct.

The folloging code is the part of my interrupt function where a char is received. The received char is printed out (debug_printf) correctly in the debug terminal (over jtag). So yes, without the Queue, everything works as expected.

/*** UART2 Receive Data Available interrupt (RDA) ***/
void UART2_ISR_ReceiveChar(void) {
	static portBASE_TYPE xHigherPriorityTaskWoken;
	unsigned char ReceivedChar = LPC_UART2->RBR; //Read received Char from register
	UART2_ReceiveBuffer[UART2_ReceiveBufferPosW] = ReceivedChar;
	
	if(UART2_ReceiveBufferPosW == UART2_BUFSIZE-1) {
		UART2_ReceiveBufferPosW = 0;
	} else {
		UART2_ReceiveBufferPosW++;
	}
	debug_printf("ISRRec: %c\n", ReceivedChar);
    xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR( UART2_ReceiveCntQueue, &xHigherPriorityTaskWoken );
    if( xHigherPriorityTaskWoken == pdTRUE ) {
		vPortYieldFromISR();
	} 
}

configCHECK_FOR_STACK_OVERFLOW is 0.

rtel wrote on Friday, December 31, 2010:

A couple of things that stick out:

1) Definitely don’t call debug_printf() from an ISR!  Does the queue work when that line is removed?

2) Set configCHECK_FOR_STACK_OVERFLOW to 2, and define a stack overflow hook function.  Just something like the following will be ok for a start.

void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
{
	( void ) pxTask;
	( void ) pcTaskName;
	
	for( ;; );
}

Regards.

gizm0r wrote on Friday, December 31, 2010:

> 1) Definitely don’t call debug_printf() from an ISR! Does the queue work when that line is removed?

No, doesn’t change anything. Even if I put only the xSemaphoreGiveFromISR in the ISR and remove everything else it doesn’t work.

> 2) Set configCHECK_FOR_STACK_OVERFLOW to 2, and define a stack overflow hook function. Just something like the following will be ok for a start.

Ok, put this in, but it keeps jumping to the hardfault. vApplicationStackOverflowHook isn’t executed.

rtel wrote on Friday, December 31, 2010:

Running out of ideas here…

Is the queue valid?  Was it created, and when it was created did you check that the xQueueCreate() return value was a valid handle (not null)?

Regards.

frbuisson wrote on Wednesday, January 19, 2011:

Hi
I have the same problem with a PIC32 target, and it occurs when I raise the item number of the Queue.
When I have 4 Items, the general_exception become after a little time
when I have 8 items,  the general_exception become in 1 second.
I test the configCHECK_FOR_STACK_OVERFLOW to 2 and i don’t go in the vApplicationStackOverflowHook function.

this is my test code  :

void vU3AInterruptHandler( void )
{
/* Declared static to minimise stack use. */
static portCHAR cByte;
static portBASE_TYPE Resultat;
static portBASE_TYPE xHigherPriorityTaskWoken;
static xComPortHandle pxPort=&UART3A_ComPort;
	xHigherPriorityTaskWoken = pdFALSE;
	Resultat  = pdTRUE;
	/* Are any Rx interrupts pending? */
	if( INTGetFlag(INT_U3ARX) )
	{
		while(( UARTReceivedDataIsAvailable( pxPort -> eUARTId ))&&(Resultat == pdTRUE))
		{
			/* Retrieve the received character and place it in the queue of
			received characters. */
			cByte =UARTGetDataByte(pxPort -> eUARTId);
			Resultat = xQueueSendFromISR( pxPort ->xRxCharsBuffer , &cByte, &xHigherPriorityTaskWoken ); // Here the memcpy() in the prvCopyDataToQueue() function in queue.c make a general exception ( 0x00000007 =  EXCEP_DBE = bus error (load/store))
		}
		INTClearFlag( INT_U3ARX );
	}
	/* Are any Tx interrupts pending? */
	if( INTGetFlag(INT_U3ATX) )
	{
		while( UARTTransmitterIsReady(pxPort -> eUARTId))
		{
			if( xQueueReceiveFromISR( pxPort -> xTxCharsBuffer, &cByte, &xHigherPriorityTaskWoken ) == pdTRUE )
			{
				/* Send the next character queued for Tx. */
				UARTSendDataByte( pxPort -> eUARTId, cByte );
			}
			else
			{
				/* Queue empty, nothing to send. */
				pxPort -> xTxHasEnded = pdTRUE;
				break;
			}
		}
		INTClearFlag(INT_U3ATX);
		if (pxPort -> xTxHasEnded == pdTRUE) // si c'est fini
			INTEnable(INT_U3ATX, INT_DISABLED);
	}
	/* If sending or receiving necessitates a context switch, then switch now. */
//	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}

Gizm0r, do you find a solution?
Thanks

cyanicx wrote on Friday, January 21, 2011:

hi,

i got exactley the same problem…

the core registers of the 1768 says  fault    CFSR  0x400  and that leads to INVPC   (invalid program counter)

I think we are might not allowed to jump back into the isr ?

further hints i found :

when using the nvic set priority function ?  whats the matter with negative values ?

**
 * @brief  Set the priority for an interrupt
 *
 * @param  IRQn      The number of the interrupt for set priority
 * @param  priority  The priority to set
 *
 * Set the priority for the specified interrupt. The interrupt
 * number can be positive to specify an external (device specific)
 * interrupt, or negative to specify an internal (core) interrupt.
 *
 * Note: The priority cannot be set for every core interrupt.
 */
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}

and another question :  in   portmacro.h  of freertos  I found

#define portSET_INTERRUPT_MASK_FROM_ISR() **0;**portSET_INTERRUPT_MASK()  // test
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x

whats the matter with the 0;  ?

rtel wrote on Friday, January 21, 2011:

when using the nvic set priority function ?  whats the matter with negative values ?

This is ARM provided code, nothing to do with FreeRTOS, but the answer to your question is “nothing is the matter with negative values”.  Read the Cortex-M technical reference manual and the CMSIS manual.

and another question :  in   portmacro.h  of freertos  I found

#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK()  // test
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x

whats the matter with the 0;  ?

Again, the answer is “nothing is the matter with 0”.  If you try removing it you will find your code won’t compile.  It is there to tailor a generic macro to a specific chip in the most efficient manner possible while maintaining common kernel core code across all architectures.

These crashes while using queue functions in interrupts in Cortex-M3 ports are nearly always due to the mistakes made configuring the interrupt controller, due in part to the strange nature of setting interrupt priorities (priority 0 being the highest, not the lowest, and the fact that the most significant bits are used not the least).  it is understandable why people get it wrong.  People often say “I have read your FAQ, followed it and it still crashes”, but when you drill deeper you find that is not the case.  Case in point: https://sourceforge.net/projects/freertos/forums/forum/382005/topic/4059693 .

I would go as far as to say, I have never come across a case where the issue is caused by either just a standard everyday bug in the application C code, or a misconfiguration of the interrupt controller and/or the kernel configuration constants that relate to the interrupt controller.

I’m not saying there are no issues in the kernel code, nothing can ever give that guarantee, but I would say I am yet to have anybody provide evidence of a problem.

Regards.

rtel wrote on Friday, January 21, 2011:

I have never come across a case where the issue is caused

…should say “I have never come across a case where the issue is not caused”

Regards.

frbuisson wrote on Friday, January 21, 2011:

I resolve the problem by raising the stack size of my all my tasks (I give them 600 bytes).
Now, when I use the vTaskList() function, many tasks use about 500-550 bytes for their own stack.
It seems the vApplicationStackOverflowHook function didn’t work for me with configCHECK_FOR_STACK_OVERFLOW equal to 1 or 2.
I’m not sure the stack size is the only reason because I’ve done many corrections of my code.
Regards
I hope my answer will be useful.

gizm0r wrote on Saturday, January 22, 2011:

Gizm0r, do you find a solution? Thanks

For me the problem was an not correctly initialized queue variable.
Now everything works for me.