Function didn't get past xSemaphoreTake ... sometimes

jon20015 wrote on Thursday, January 22, 2015:

Hi,

I just started my first freeRTOS project, but I have some behavior I can’t solve. In my task I alternately call a read and a write function. Both should wait/block until an special interrupt occurs. On first call I create a binary semaphore (one per function, read as an example):

:::c
    if (NULL == ReadSyncObj) {
        if (NULL == (ReadSyncObj = xSemaphoreCreateBinary())) {
            return (RES_NOTRDY);
        }
        xSemaphoreTake(ReadSyncObj, 10 );
    }

The interrupt handler is shared for both:

:::c
static void _ISRHandler() {
    status = GetIntStatus();

    xHigherPTaskWokenRead  = pdFALSE;
    xHigherPTaskWokenWrite = pdFALSE;

    if (status & READ_READY) {
        ClearInterrupt(READ_READY);
        (void)xSemaphoreGiveFromISR(ReadSyncObj, &xHigherPTaskWokenRead);
        portYIELD_FROM_ISR(xHigherPTaskWokenRead);
        return;
    }

    if (status & WRITE_READY) {
        ClearInterrupt(WRITE_READY);
        (void)xSemaphoreGiveFromISR(WriteSyncObj, &xHigherPTaskWokenWrite);
        portYIELD_FROM_ISR(xHigherPTaskWokenWrite);
        return;
    }
}

In the read and write functions I have the transfer started and the I take the semaphore:

:::c
    startReadOperation();

    //fprintf(stdout, "r1\r\n");

    (void)xSemaphoreTake(ReadSyncObj, portMAX_DELAY);

    //fprintf(stdout, "r2\r\n");

My problem is, that I can’t get past the xSemaphoreTake very often and never leave the idle task again. This behavior never occurrs if the fprintf functions are used, everything is working fine then.

My task has a priority of one and should meet the

:::c
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( 1 << 5 )

requirement.

I am grateful for any suggestion
Jon

davedoors wrote on Thursday, January 22, 2015:

Nothing obviously wrong. Do you have configASSERT() defined?

Is it possible both READ_READY and WRITE_READY get set at the same time in your interrupt handler? If so it would be better to remove the return calls. You can then use the same HigherPriorityTaskWoken variable in both xSemaphoreGiveFromISR() calls and only call portYIELD_FROM_ISR() once at the end of the function.

If you are stuck on xSemaphoreTake() I guess the interrupt just has not executed. Is that the case? It is best not to use portMAX_DELAY in this case because your program will hang if the interrupt does not execute. Better to use a finite delay then clean up if xSemaphoreTake() times out without taking the semaphore.

In the latest FreeRTOS you can use a task notification instead of a semaphore http://www.freertos.org/RTOS_Task_Notification_As_Binary_Semaphore.html

jon20015 wrote on Friday, January 23, 2015:

Hi Dave,

thanks for your response!

Nothing obviously wrong. Do you have configASSERT() defined?

No, it is not defined.

Is it possible both READ_READY and WRITE_READY get set at the same time in your interrupt handler? If so it would be better to remove the return calls. You can then use the same HigherPriorityTaskWoken variable in both xSemaphoreGiveFromISR() calls and only call portYIELD_FROM_ISR() once at the end of the function.

They should never appear at the same time. But who knows? :wink:

If you are stuck on xSemaphoreTake() I guess the interrupt just has not executed. Is that the case? It is best not to use portMAX_DELAY in this case because your program will hang if the interrupt does not execute. Better to use a finite delay then clean up if xSemaphoreTake() times out without taking the semaphore.

I believe, that’s not the case. If I delay the execution with “fprintf” everything is fine. It feels like some kind of timing problem, the interrupt might happen while xSemaphoreTake is in progress. Could that be a problem?

In the latest FreeRTOS you can use a task notification instead of a semaphore http://www.freertos.org/RTOS_Task_Notification_As_Binary_Semaphore.html

Unfortunately I can’t update my freeRTOS (8.0.1) at the moment.

Thanks again
Jon

rtel wrote on Friday, January 23, 2015:

Semaphores are designed to be accessible from interrupts and tasks
simultaneously - but that will only work if you interrupt priorities are
set correctly, so that is the first thing to double check.

Please defined configASSERT()
(http://www.freertos.org/a00110.html#configASSERT) as a first step. In
V8.0.1 that should trap and incorrect priority - let us know if that is
hit or not.

Regards.

jon20015 wrote on Friday, January 23, 2015:

Had to find a solution working with ccs, but it’s up now.
Unfortunately I have no clue about the assembler part and what’s going on. I get an assertion at “configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );” with ucCurrentPriority = 0x00 and ucMaxSysCallPriority = 32.

freeRTOSConfig.h:

:::c
#ifdef ccs
   void vAssertCalled(const char *pcFile, unsigned long ulLine );
    #define configASSERT(expr) if ( (expr) == 0)   {                                                    \
                                                        vAssertCalled( __FILE__ , __LINE__ ); \
                                                   }
#endif

port.c:

:::c
#if( configASSERT_DEFINED == 1 )

extern unsigned long ipsrFunc(void);
    __asm("    .sect \".text:ipsrFunc\"\n"
          "    .clink\n"
          "    .thumbfunc ipsrFunc\n"
          "    .thumb\n"
          "    .global ipsrFunc\n"
          "ipsrFunc:\n"
          "    mrs     r0, ipsr\n"
          "    bx lr\n");

	void vPortValidateInterruptPriority( void )
	{
	uint32_t ulCurrentInterrupt;
	uint8_t ucCurrentPriority;

		/* Obtain the number of the currently executing interrupt. */
        #if defined(ccs)
            ulCurrentInterrupt = ipsrFunc();
        #else
            /* Obtain the number of the currently executing interrupt. */
                __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );
        #endif

		/* Is the interrupt number a user defined interrupt? */
		if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
		{

rtel wrote on Friday, January 23, 2015:

There isn’t an official CCS port so I can tell you if your use of
ipsrFunc() is correct or not, but if it is then it looks as if interrupt
priorities are indeed your problem.

As different Cortex-M devices have a different number of priority bits
the first thing to do is ensure the hardware is described correctly in
the FreeRTOSConfig.h file. You can see an example between the lines 53
and 176 in this file:

http://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Demo/CORTEX_M4F_ATSAM4E_Atmel_Studio/src/config/FreeRTOSConfig.h

Next ensure you have read http://www.freertos.org/RTOS-Cortex-M3-M4.html

  • especially the bits about ensuring you don’t leave an interrupt
    priority at its default value.

Regards.

jon20015 wrote on Friday, January 23, 2015:

Sorry for the following noob question, but how do I actually set the interrupt priority?

rtel wrote on Friday, January 23, 2015:

If you system is using CMSIS compatible libraries then there is a
function NVIC_SetPriority(). If you are using propriatory libraries
supplied by your chip or compiler vendor then check whatever
documentation they supplied. You can of course reference the Cortex-M
hardware manual, then peek and poke the priority registers yourself, but
I would not recommend that.

All the demos supplied by FreeRTOS will set a priority somewhere, so
that provides another reference.

Regards.

jon20015 wrote on Friday, January 23, 2015:

Ok thanks. I thought there has to be some kind of vPortSetInterruptPriority I have to modify/find/use.

jon20015 wrote on Friday, January 23, 2015:

I’ve managed to set the priority level of my interrupt handler and the assert is gone. Unfortunately the original problem still exists.

jon20015 wrote on Tuesday, January 27, 2015:

Sorry, I have forgotten to mention my current interrupt priority

:::c
#define INT_PRIORITY_LVL_1      0x20

on Cortex M4. Any ideas are welcome.