Is blocking of an ISR by Semaphore possible?

Hi @ All, I use a Counter to increment a variable every 10ms. This is done in an interrupt. In the task I want to read the variable and the actual value in the timer counter register. Both together are my timestamp I want to use. Now I want so make shure, that the variable isn’t changed by the ISR during the read of both, the variabel and the actual counter register value. Taskcode: xSemaphoreTake(…); a = time_variable; b = actual_timer_register_count; xSemaphoreGive(…); ISR code: xSemaphoreTake(…); time_variable++; xSemaphoreGiveFromISR(…); Will this work? Will the ISR block until the task gives the Semaphore? If this won’t work, do I need an extra task to increment the variable? This should be able to block. Thanks in advance! 

Is blocking of an ISR by Semaphore possible?

Definately do not do that! Task code: taskENTER_CRITICAL(); a = time_variable; b = actual_taimer_register_count; taskEXIT_CRITICAL(); ISR code: time_variable++;

Is blocking of an ISR by Semaphore possible?

I think it is better to suspend the interrupt timer, read out the variables, and then turn it back on. If you really care about precision (that is slighty lost when suspending timer and turning back on) you could add some time to the timer interrupt counter since you can calculate how long the suspend and resume will take.

Is blocking of an ISR by Semaphore possible?

ISRs do not block. They run from start to finish without interruption (unless you are using a port that allows interrupt priorities so an interrupt can be called during another interrupt). An interrupt cannot be executing and then block and allow another task to run, it does not work like that. So firstly, xSemaphoreTake in your ISR will not have the desired effect since the ISR cannot block. Secondly the ISR does not need to implement mutual exclusion for any shared data because nothing else can interrupt it. Thirdly xSemaphoreTake will crash the system since it is not an ISR capable function. If there would be such a version then it would have to return true when the semaphore is available at that instant to be taken and your interrupt would have to handle the situation when it was not able to. For example: if (xSemaphoreTakeFromISR(…) == pdTRUE) {    time_variable++;    xSemaphoreGiveFromISR(…);  } else {    // Semaphore already taken: deal with this problem later } This is obviously rubbish, so better to do what MEdwards said and use a critical section to make sure the interrupt doesn’t interrupt the task.

Is blocking of an ISR by Semaphore possible?

Message to incrediball – thanks for the very informative answers you have been giving.  Its great for the whole community. Regards.

Is blocking of an ISR by Semaphore possible?

Thank you very much for your fast and very good answers! I will do it with the taskENTER_CRITICAL(); and taskEXIT_CRITICAL();. Thanks a lot!

Is blocking of an ISR by Semaphore possible?

Thank you very much for your fast and very good answers! I will do it with the taskENTER_CRITICAL(); and taskEXIT_CRITICAL();. Thanks a lot!

Is blocking of an ISR by Semaphore possible?

I haven’t actually started using FreeRTOS yet – I’m currently wandering the forum to gauge the level of community interest and support.  However, I can still give some general advice. You might not need to use a semaphore or critical section at all here, depending on your task priorities, counter speeds, etc.  Consider the function: // Assumes time_variable and actual_timer_register_count // are both volatile uint16_t uint32_t getTimestamp(void) {   uint16_t a1, a2, b;   a1 = time_variable;   while (1) {     b = actual_timer_register_count;     a2 = time_variable;     if (a1 == a2) break;     a1 = a2;   }   return ((uint32_t) a2 << 16) | b; } There are a couple of points about this code.  First, it is theoretically unbounded if you can’t be sure that it will not be continuously pre-empted during the loop.  Secondly, it will only be correct if interrupts are enabled – if they are not, then a roll-over of the timer between reading time_variable and then reading actual_timer_register_count will be lost – you’ll get the old value of time_variable, followed by the rolled-over value of actual_timer_register_count. Note also that MEdward’s suggestion of using a critical section will suffer from the same flaw, as the incrementing of actual_timer_register_count is not stopped by the critical section. An alternative method if your are confident that your task will not be pre-empted for longer than half a counter period (you can use a critical section to be sure) is: // Assumes time_variable and actual_timer_register_count // are both volatile uint16_t uint32_t getTimestamp(void) {   uint16_t a, b1, b2;   b1 = actual_timer_register_count;   while (1) {     a = time_variable;     b2 = actual_timer_register_count;     if (b1 <= b2) break;     b1 = b2;   }   return ((uint32_t) a << 16) | b2; } These can be combined to give a single function that is safe from rollovers regardless of the state of interrupts, or how long it is pre-empted, and does not need any critical sections: uint32_t getTimestamp(void) {   uint16_t a1, a2, b1, b2;   a1 = time_variable;   b1 = actual_timer_register_count;   while (1) {     a2 = time_variable;     b2 = actual_timer_register_count;     if ((a1 == a2) && (b1 <= b2)) break;     a1 = a2;     b1 = b2;   }   return ((uint32_t) a2 << 16) | b2; } This will still suffer from the possibility that a pre-emption could occur between reading time_variable for a2 and reading actual_timer_register_count for b2 and last longer than a timer period.  However, the value returned will still be a valid timestamp for a point in time between the entry to and exit from the function – that’s all you can ask of a timestamp function.