Best practice to avoid ISR race conditions

Hello, I have an ISR to handle UART input. It pushes the data it receives into a buffer. On the other hand, I have t o parse that buffer and extract each meaningfull message (each message is wrapped with a rn in this case). I’m planning to parse the buffer and extract messages in a task but I need to make sure that during that parsing the buffer shouldn’t be modified. What would be the safest solution ? From the docs it looks like I cannot LOCK a mutex in ISR but only release it. On the other hand, using ENTER_CRITICAL might be a simple solution but I don’t think it is intended for this purpose. I’d love to hear best practices about the subject in the FreeRTOS world. Kind regards

Best practice to avoid ISR race conditions

Maybe this might be a possible solution ? void ISR(void) {     xQueueSendFromISR(…); /* Append a "lock" */     …     xQueueReceiveFromISR(…); /* Remove the "lock" */ } void task(void) {     if( xQueuePeek(…) ) return; /* Check if there’s any lock */     … }

Best practice to avoid ISR race conditions

I’ve also seen Richard Barry doing this; -—- taken from emac.c —– void FOO_ISR(void) {     xSemaphoreGiveFromISR();     DISABLE_FOO_INTERRUPTS();     portEND_SWITCHING_ISR; } void task(void) {     xSemaphoreTake();     // do stuff     ENABLE_FOO_INTERRUPT(); } -———- First of all, task never gives the semaphore back. Second, isn’t disabling an interrupt can cause data loss on the peripheral if the hardware buffer is full ? Now that I’ve looked into FreeRTOS source I’ve noticed that queue thread-safety is done by vPortEnterCritical. I thought it would be with an atomic assembly instruction. If Queue infrastructure uses vPortEnterCritical to ensure thread-safety I think I can safely use that as my lock without ever using Queues, since Queues looks like just a fancy way of vPortEnterCritical. What am I missing ? Kind regards

Best practice to avoid ISR race conditions

Merhaba :) When you have long chunks of data, like in ethernet, in order to get rid of extra copy you may use semaphore especially if dma is involved. On the other hand, if you have relatively small data source queues will provide better programming practice. In my uart interrupt, I send data to a queue and then process queue in a task. If you use portENTERCRITICAL you will lose data if you can not process character in a timely manner. But with the queues, you can wait as long as you want provided that your queue size is adequate for your data rate. Caglar

Best practice to avoid ISR race conditions

Just as a summary of posts in this thread – Note that between a task and an interrupt the mutual exclusion is normally in one direction only.  An interrupt can interrupt a task, but a task cannot interrupt an interrupt.  Therefore it is very rare to need to take a semaphore in an ISR. If you place received data in a circular buffer then the ISR can access the write pointer, and the task the read pointer, with little potential for a conflict.  You are only writing to the pointers from one place – the write pointer from the ISR and the read pointer from the task. Another method is to use an array of buffers.  The ISR can use one buffer, when it has filled it or a complete message has arrived, it then moves onto the next buffer leaving the task to process the first buffer without fear of a conflict.  The ISR and task are always working on different buffers.  This is how many DMA systems work, especially on Ethernet controllers. Regards.

Best practice to avoid ISR race conditions

Thank you very much for your prompt responses, but answer to my questions are still not clear to me. Cağlar: Queues also uses vPortEnterCritical to lock the queue, i.e. each time you append a char to the queue it will enter and exit critical region. This is not true if you use FromISR relatives though, they don’t disable interrupts since it is apparently assumed that they won’t be preempted which I don’t know if it is true. I’ve though of vPortEnterCritical to only lock and release a mutex (in traditional sense), so it would a little time and I’d just use that ensure the atomicity of the mutex operation. Richard Barry: My platform is cortex-m3. Can’t interrupts in this MCU be preempted by other interrupts ? Say if SYSTICK interrupt has occured, won’t it interrupt a perihperal interrupt and do a FreeRTOS stuff such as context switching. If we can assume that the UART ISR won’t be interrupt by anything else my problem is easy to fix. As you suggested I’d just use double buffering, and we are good to go. Is that the case ? Kind regards

Best practice to avoid ISR race conditions

> My platform is cortex-m3. Can’t interrupts in this MCU be > preempted by other interrupts ? Yes – full interrupt nesting is supported, however…. > Say if SYSTICK interrupt has > occured, won’t it interrupt a perihperal interrupt and do a > FreeRTOS stuff such as context switching. …. SYSTICK operates at the lowest priority so will never interrupt a peripheral ISR (assuming you have not changed the value of configKERNEL_INTERRUPT_PRIORITY from 255).  SYSTICK can itself be interrupted by a peripheral ISR but this is ok, the design will allow this safely. You can use queues from interrupts provided the interrupt priority is equal to or below portMAX_SYSCALL_INTERRUPT_PRIORITY – note that on Cortex M3 the lowest priority is the highest numeric value, so 255 has lower priority than 254.  Again this is safe as the kernel is designed to allow this. See http://www.freertos.org/a00110.html#kernel_priority. > If we can assume that the UART ISR won’t be interrupt by > anything else my problem is easy to fix. As you suggested I’d > just use double buffering, and we are good to go. Is that the case ? Hopefully I have answered that.  They wont get interrupted by the kernel but I cannot say whether any other interrupts using the same buffers will interrupt your UART interrupt because this depends how you have designed your system and set your interrupt priorities. Regards.

Best practice to avoid ISR race conditions

Hello Richard, Thank you very much for taking time to explain these. I really appreciate it. I have a question about your ethernet driver implementation in Luminary example. In the ethernet interrupt routine (vEMAC_ISR) you just give a semaphore and in the vMACHandleTask takes that semaphore and process the incoming data. During this processing you disable interrupts to ethernet port. Now, I know that this code works fine because I’m using it for a few months now but I wonder how come it never happens to cause hardware buffer overruns. i.e. what if the processing took long during that time interrupts are disabled. Wouldn’t that cause a buffer overrun and loss of data permenantly ? You rely on TCP to recover that ? Kind regards, Engin