Semaphore Example

A semaphore can be used to count events, or to manage a fixed set of resources. In this example, consider the case of an interrupt handler which is triggered whenever an event occurs. In this example, we will again use the UART receive interrupt to act as the event trigger. The interrupt handler increments the semaphore value (i.e. the event count) by one. Then, periodically, an event processing task checks the semaphore value, and if it is non-zero, it will decrement the semaphore value by one.

 

For this contrived example, we will use a global variable to store the character received, so the event process task can access and display it just like in the previous terminal echo example. As the keyboard interface is significantly slower than the REXIS event handling, the possibility of lost characters occurring is minimal, although theoretically possible.

 

extern REXIS_SEMAPHORE *sema1;

int ch;

 

void UART2_RX_ISR(void)

      {

      ch = getchar();

      REXIS_SemaphoreSignalFromISR(sema1);

      }

 

void EventProcessTask(unsigned arg0)

      {

      while (REXIS_SemaphoreWait(sema1, 0))

            {

            putchar(ch);

            }

      }

 

REXIS_SemaphoreSignalFromISR increases the semaphore value by one within an ISR. A regular task can signal a semaphore via the function REXIS_SemaphoreSignal.

 

REXIS_SemaphoreWait decreases the semaphore value by one, unless its current value is zero, in which case the task blocks until the value becomes one or more (so again, it does not use any CPU time). The second argument to the function is the timeout value; i.e. how many milliseconds the task should wait for the semaphore value to be one or greater. A timeout value of zero means that the task will wait forever.

 

This example also demonstrates that there are multiple ways to solve a problem. The previous solution of using a mailbox is arguably more elegant than this example using a semaphore and a global variable to pass information. Nevertheless, there are cases where semaphore is the better solution to a problem.

 

Note: In EventProcessTask, the call to REXIS_SemaphoreWait inside the “while” condition eliminates the need for a separate outer “while (1)” forever loop. The function REXIS_SemaphoreWait always returns a non-zero number, so this optimization can be done without causing problems.