xSemaphoreTake gets blocked

dberenguer wrote on Monday, July 20, 2009:

I’ve created a simple semaphore mutex into one of the tasks in order to avoid silmultaneous access to a global variable. The code is identical to the one explained in the online tutorial:

xSemaphoreHandle xSemaphore = NULL;

void myTask(void *pvParameters)
{
   xSemaphore = xSemaphoreCreateMutex();
   …
}

void myfunction(void)
{

   if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
   {
      // Access to the global resource
     xSemaphoreGive(epSemaphore);
   }
   …
}

I’ve verified that the semaphore is correctly created. During the first accesses, it’s even “taken” and “released” without problems. However, after some successful accesses, myfunction gets blocked at xSemaphoreTake. Doing xBlockTime = 0 solves the problem but I’d like myfunction to wait at least some ticks before abandoning the semaphore. I’m thinking that maybe FreeRTOS doesn’t know what a tick is in my system so that it waits indefinitely. I’ve maybe missed some definition elsewhere…

I understand that my descriptions are quite vague but… has anyone an idea about what could be happening with my setup?

Thank you very much,

Daniel.

davedoors wrote on Monday, July 20, 2009:

First, put a break point in vTaskIncrementTick() in tasks.c. If the break point is triggered repeatedly then your tick interrupt is working ok.

Also do the usual things like checking for stack overflows, things like that.

dberenguer wrote on Monday, July 20, 2009:

Thanks Dave for your help.

vTaskIncrementTick() is called several times at the beginning of the execution. Then, it’s not called again, matching with the blockage at xSemaphoreTake in myfunction() . I’ve also verified that there is no stack overflow through the use of the vApplicationStackOverflowHook function.

Something curious IMO, If I add an instruction in vTaskIncrementTick() that prints a text message on my Dev Board’s OLED display, then vTaskIncrementTick gets called without problems all the time and my program works smoothly.  This is not a valid solution though but I wanted to explain this behavior, just in case this is a symptom about what’s happening.

My hardware platform is a Luminary LM3S8962 Eval board.

Thanks again!

Daniel.

dberenguer wrote on Monday, July 20, 2009:

I’ve found the source of the problem. I was using a timer interrupt in order to run ADC conversions on my Stellaris platform. The trigger of this interrupt was hanging the task I think. I now know that custom interrupts have to be avoided under FreeRTOS :slight_smile:

spacewrench wrote on Monday, July 20, 2009:

I’ve written several FreeRTOS programs that run on Luminary chips.  Interrupts work correctly, but you have to be careful about priority.  Specifically, in the NVIC, lower-numbered priorities are higher.  Also, there’s an intermediate priority level (configMAX_SYSCALL_INTERRUPT_PRIORITY) above which you can’t call FreeRTOS routines.  There’s a lot more information on the FreeRTOS website, but it’s slightly difficult to find.  (It would be nice if there was a FAQ about it, or a more-prominent link in a section talking about Cortex procs.)  Here’s where to start reading:

Near the bottom of the main frame, under the heading "RTOS Port specific configuration"

rtel wrote on Monday, July 20, 2009:

I’m not sure what you mean by “custom interrupts have to be avoided”.  Its fine to have any interrupts you want provided there are no resource conflicts.

Was your interrupt using the FreeRTOS API?  If so then ensure only API functions that end in FromISR were being used and that the interrupt priority was less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY (remembering that low number mean high priorities on the Cortex M3).

Regards.

dberenguer wrote on Monday, July 20, 2009:

Thanks both for your remarks. I’m quite new in FreeRTOS and have still a lot to learn… and I’m really happy to know that I can use interrupts together with RfeeRTOS.

My custom interrupt (the one currently triggering the ADC reads) has now the lowest priority (255) but it still makes the system crash. I’m now thinking that maybe the problem is in the timer used to trigger these ADC conversions periodically. I did verify that this timer was not used anywhere by the Os but maybe I should do a second check (I’m not the author of the FreeRTOS port)

More news tomorrow…

Daniel.

dberenguer wrote on Monday, July 20, 2009:

My application no longer uses a timer to trigger ADC conversions… and the problem persists.

dberenguer wrote on Monday, July 20, 2009:

I forgot to say that the interrupt is not calling any function from the FreeRTOS API. It just reads the ADC values.

edwards3 wrote on Monday, July 20, 2009:

Can you post the interrupt code?

dberenguer wrote on Tuesday, July 21, 2009:

Of course!

TaskIO.c runs in a separate task, all the routines regarding the IO management. setup_analog_inps() is the function that sets up the ADC sequencer (sequencer 0) and programs Timer1 to trigger the sequencer every 0.1 sec:

static void setup_analog_inps(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC);        // Enable ADC
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);    // Enable Timer 1

    ADCSequenceDisable(ADC_BASE, 1);                        // Disable ADC sequencer 1

    // Configure the ADC to sample when the timer expires
    // After sampling, the ADC will interrupt the processor
    ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_TIMER, 255);
    ADCSequenceStepConfigure(ADC_BASE, 0, 0,ADC_CTL_CH0 );
    ADCSequenceStepConfigure(ADC_BASE, 0, 1,ADC_CTL_CH1 );
    ADCSequenceStepConfigure(ADC_BASE, 0, 2,ADC_CTL_CH2 );
    ADCSequenceStepConfigure(ADC_BASE, 0, 3,ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END);

    ADCSequenceEnable(ADC_BASE, 0);

    ADCIntEnable(ADC_BASE, 0);
    IntEnable(INT_ADC0);

    // Configure Timer 1 to generate triggers to the ADC
    TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER);
    TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet()/10);        // Trigger every 0.1 secs
    TimerControlStall(TIMER1_BASE, TIMER_A, true);
    TimerControlTrigger(TIMER1_BASE, TIMER_A, true);
    TimerEnable(TIMER1_BASE, TIMER_A);
}

ADCIntHandler is a callback function called whenever the ADC Sequencer 0 reads new analog data (once every 0.1 sec)

void ADCIntHandler(void)
{
    unsigned long ulData[8];
    unsigned long ulmVolt;
    unsigned long ulValue;

    BYTE bState;
    int i;

    // Clear the ADC interrupt.
    ADCIntClear(ADC_BASE, 0);

    // Read the data from the ADC.
    ADCSequenceDataGet(ADC_BASE, 0, ulData);

    // For every analog input
    for(i=0 ; i<NBOF_INPANA ; i++)
    {
        // Get ADC value in voltage (mV) format
        ulmVolt = (ADC_VOLT_RANGE * 1000 * ulData[i]) / 1024;    // Milivolts
        // Apply factor and offset for each ADC endpoint
        ulValue = ulmVolt * aEndpoint[0].factor + aEndpoint[0].offset;
        // Set state
        if (ulValue < 10)
            bState = 0;
        else
            bState = 1;

        epUpdateValue(i, ‘a’, ulValue, bState);            // Update value in the array of binary endpoints
    }
}

Apart from here, there is no other place where a timer or interrupt is set.

Thanks again,

Daniel.