Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

Is blocking of an ISR by Semaphore possible?

Posted by Tonau on March 31, 2009
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!


RE: Is blocking of an ISR by Semaphore possib

Posted by MEdwards on March 31, 2009
Definately do not do that!

Task code:
taskENTER_CRITICAL();
a = time_variable;
b = actual_taimer_register_count;
taskEXIT_CRITICAL();

ISR code:
time_variable++;



RE: Is blocking of an ISR by Semaphore possible?

Posted by Willem on March 31, 2009
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.

RE: Is blocking of an ISR by Semaphore possible?

Posted by incrediball on March 31, 2009
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.

RE: Is blocking of an ISR by Semaphore possib

Posted by Richard on April 1, 2009
Message to incrediball - thanks for the very informative answers you have been giving. Its great for the whole community.

Regards.

RE: Is blocking of an ISR by Semaphore possible?

Posted by Tonau on April 1, 2009
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!

RE: Is blocking of an ISR by Semaphore possible?

Posted by Tonau on April 1, 2009
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!

RE: Is blocking of an ISR by Semaphore possible?

Posted by David Brown on April 6, 2009
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.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists