0
votes

Here is my problem:

I'm using FreeRTOS with the Cortex-M3 MCU. I have an ISR called EXTI15_10, which is trigger during a rising edge on the pins EXTI_Line10, EXTI_Line11..etc. Within the ISR I set the variable "status" to some specified value and before leaving the ISR I put the variable status in a queue and send it to my thread. That works fine.

The thread is periodically called and calls the function xQueuePeek() to get the item from the queue. Note xQueuePeek() gets the item from the queue without removing it from the queue. This works fine too, but I only receive the correct value once. That means, the interrupt is generated, status is set to a value and put in the queue, threads reads the correct value. But all the next interrupts set status correctly(I checked it before putting the item in the queue), but my thread reads always the old value. Do I have here a problem with compiler optimization and volatile? xQueueSendFromISR(), expects as second argument a const void * and not volatile void *. What I'm doing wrong here?

The ISR:

void EXTI15_10_IRQHandler()
{   
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    int status;

    if (EXTI_GetITStatus(EXTI_Line10))
        status = 100;
    else if (EXTI_GetITStatus(EXTI_Line11))
        status = 200
    else if (EXTI_GetITStatus(EXTI_Line12))
        status = 300;
    else if (EXTI_GetITStatus(EXTI_Line13))
        status = 400;
    else if (EXTI_GetITStatus(EXTI_Line14))
        status = 500;
    else if (EXTI_GetITStatus(EXTI_Line15))
        status = 600;

    // Clear the pending interrupt bits
    EXTI_ClearITPendingBit(EXTI_Lines15_10);

    xQueueSendFromISR(queue, &status, &xHigherPriorityTaskWoken);
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

The thread:

static void thread_xy()
{
    portTickType xLastExecutionTime;

    xLastExecutionTime = xTaskGetTickCount();
    int status_from_queue = 0;

    for (;;) {
        xLastExecutionTime = xTaskGetTickCount();
        vTaskDelayUntil(&xLastExecutionTime, CHECK_AND_ENABLE_LEDS_DELAY);

        if (queue != 0) {
            if (xQueuePeek(queue, &status_from_queue, portMAX_DELAY))
                // Received item from queue...
                print("Status from queue = %d\n", status_from_queue);
        }
    }
}
1
If you only ever peek and never remove then you'll only ever get the right value once. You also have a severe race, you cannot peek at the queue without disabling interrupts. - Hans Passant
Unless I have misunderstood, it should be reading the same status every time because it is reading the first item every time? Since you never actually remove anything from the queue, the xQueuePeek is always going to read the first item, so you will always get the first status? - Ben

1 Answers

2
votes

If you're only ever peeking at the queue then, yes, you'll always get the same value, simply because you're leaving it there. A queue is a first-in-first-out data structure but, in order to get at the second value in the queue, you generally have to remove the first.

Consider the following sequence:

initial state            queue = { }
interrupt adds 7         queue = { 7 }
application peeks (7)    queue = { 7 }
interrupt adds 42        queue = { 7, 42 }
application peeks (7)    queue = { 7, 42 }
interrupt adds 314159    queue = { 7, 42, 314159 }
application peeks (7)    queue = { 7, 42, 314159 }

If you want to extract a value from the queue and use it, you need to get it instead of peeking at it. Without that, the queue will also eventually fill up.

I should also mention that there may be a race condition here that may well cause you problems. If your application is halfway to modifying the queue (by getting a value out of it) when an interrupt arrives, you're going to end up in all sorts of troubles since the queue will not be in a consistent state.

You need a way to stop (or, better, delay) the interrupt while the queue may be in an inconsistent state. That may be as simple as disabling interrupts while your application is modifying it (or it may require far more complex code if, for example, you're on a multi-processor system).

Of course, the xQueuePeek() (and other associated) code may already do that since you have an xQueueSendFromISR() which seems to indicate that such protection would already be part of the queueing implementation. I'm just raising that as something to watch out for.