Example Code

Semaphore Reference Design for LabVIEW FPGA

Code and Documents

Attachment

Overview


When developing applications using LabVIEW FPGA it becomes necessary to use shared resources such as a local and global variables, non-reentrant VIs, etc. in multiple locations on the diagram. To prevent accessing the same resource from multiple locations simultaneously you need to add code to lock the resource and prevent simultaneous access. For most shared resources in LabVIEW FPGA this is handled automatically and the code is added during the code generation process. in some cases it may become necessary to add this layer of protection on top of the functions and VIs provided by LabVIEW. This example shows the implementation of a semaphore in LabVIEW FPGA to manage shared resources.

Unzip the file into an empty directory and open the FPGA Semaphore project.

Feedback and Questions

Please provide feedback, comments and question on this content in this DevZone discussion forum.

Overview

The FPGA Semaphore IP example provides a simple reusable FPGA VI to implement a semaphore within your LabVIEW FPGA application. It is intended to be used in situations where you are accessing a shared resource from multiple location of your diagram and need to manual block other accesses while one access is in progress. 

The Semaphore consists of a single VI  - FPGA Semaphore (IP).vi - with three functions.

Figure 1: FPGA Semaphore (IP) connector pane

Before using the semaphore the first time in your diagram you must call the Reset function to prime the process.

When you want to use a shared resource you call the Acquire function. You can pass in a Timeout value to specify how long you want to wait for the semaphore if necessary. If the semaphore is available and the acquisition was successful, the Timed Out? return value will be False. If it is True then the semaphore is not available.

When you are done with the semaphore call the VI with the Release function specified.

Implementation

The semaphore is implemented in LabVIEW FPGA based on a VI-scoped single element FIFO. The VI itself is set to be non-reentrant so that every instance of the VI on the diagram uses the same implementation and the same VI-scoped FIFO.

In the semaphore VI a single element FIFO called Semaphore is configured. When there is an element in the FIFO the semaphore is considered to be available. When the FIFO is empty the semaphore is in use and not available to any other processes. 

To initialize or reset the semaphore a value is written into the FIFO. 

Figure 2: Semaphore Reset

When the semaphore is acquired by a process, the VI attempts to read a value from the FIFO. If there is a value in the FIFO then the semaphore is available and the acquisition is successful. At this point the FIFO will be empty and any other process attempting to acquire the semaphore will not be successful.

Figure 3: Semaphore Acquire

When the process is done with the semaphore it will release it at which point the VI writes a value back into the FIFO, making the semaphore available to other processes.

Figure 4: Semaphore Release

Using Multiple Semaphores

The semaphore VI is implemented as a non-reentrant VI and every instance of it placed on the diagram accesses the same code on the FPGA. If you want to use more than one distinct semaphore in your LabVIEW FPGA code you must save a copy of the FPGA Semaphore (IP).vi under a different name and use the copy for every instance of your second semaphore. Make additional copies of the VI for additional semaphores. It is suggested that you change the VI icon of each copy to ensure that you are using the correct semaphore in each location of your diagrams. 

Example

The example provided with the FPGA Semaphore IP illustrates how the semaphore is used to protect access to a shared FIFO (Data) from multiple processes (producer loops). In the example two processes are periodically attempting to write a block of data into a VI-scoped FIFO.

Figure 5: Partial diagram of the semaphore example showing one of two producer loops.

When the example starts the semaphore is initialized using the Reset function. In each of the producer loops the use of the shared FIFO is requested using the Semaphore Acquire function. If the acquisition is successful the loop continues on to pass a block of data to the FIFO and then releases the semaphore. If the acquisition is not successful it will repeat the call to the Acquire function until it is successful.

In a separate loop the FIFO is read out and displayed on a front panel indicator. Looking at the values displayed you can see that each block is written to the FIFO in its entirety before the next block from the other producer loop is started.

Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.

Contributors