LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Race Condition?

Solved!
Go to solution

Hi all,

 

I'm using the LINX addon to do some Raspberry Pi tinkering and I have a LabVIEW problem related to it. I'm working on a project that reads multiple sensors across three parallel modules hat handle the various sensor data coming from through the ADC, which is an ADS1115 linked to the RPi 2 B+ via I2C.

 

Anyway, I have a VI that handles the data acquisition from the ADC:

GetSample.png

Multiple instances of this VI are scattered across the three modules.

 

There are two VIs within the VI pictured above: one that gets the raw voltage output from the ADC and one that converts and calibrates this signal into something usable, as follows:

Read and Convert.png

The problem I'm having is the reads are mixed so a read of one sensor (one ADC channel) will return data for another. There are three sensors in total, channel A3 is tied to GND via a 10k resistor and returns a few mV.

 

Individually the channels all work as they should: a test VI from which I manually choose the settings works very well and returns exactly the expected data. The problem arises when I have a lot of parallel reads in very quick succession. I have a feeling it's the top level VI being executed with the enum from another instance. If this is right, I need to isolate each execution and it's enum input to run. Re-entrancy settings or using an FGV aren't solutions as I still have my enum outside the VI. I read that using a DVR could help but I'm not sure how I would execute this so that the read uses the correct enum.

 

Regarding the ADS1115 specifically, there is an 11+ ms wait between writing the config register and reading the conversion register. This has solved signal mixing problems in the past but isn't handling this particular problem - this isn't an ADC-specific problem, I'm convinced this is a software problem.

 

I hope this makes sense, I've been trying to fix this for days now and need a fix ASAP.

Cheers in advance!

0 Kudos
Message 1 of 14
(3,702 Views)

Does anything stop you from implementing Semaphores? That way only one Read is being ran at a time.

Message 2 of 14
(3,686 Views)

Thanks for the quick response ShockHouse, I have never used Sempahores before, would the attached implementation work (ignoring the lack of semaphore references etc) or have I missed something?

 

0 Kudos
Message 3 of 14
(3,668 Views)

Yeah that is the basic idea. Get a reference to the Semaphore using the same name and it will wait on the Lock vi until its available. That way everything that happens after it is not parallel.

 

Now that I'm thinking about it.. If you are using the same SubVI on the lower level for Read you don't need Semaphores. If you go into the VI Properites and go to Execution, as long as its "Non-reentrant execution" it should only be allowing the vi to run one at a time (unless the Linx software ignores that).

0 Kudos
Message 4 of 14
(3,663 Views)

Thanks ShockHouse, changing the reentrancy settings doesn't solve the problem, unfortunately. At the top level, a non-reentrant VI still has an unpredictable enum input if it's trying to be accessed in multiple locations. At lower levels I have the read and convert VIs, each one of which could be non-reentrant but still with unpredictable inputs from the read and the enum. This is why I believed the problem was with the wrong enum being read going into the top level. This is also why I included the enum in the sequence structure inside the acquire and release semaphore, encapsulating everything.

 

I think it's going to work so I'm going to go ahead and try Semaphores and see where it gets me. Worst case scenario is it doesn't work but I have a nice reuse library to play with at another time 😄

0 Kudos
Message 5 of 14
(3,636 Views)

@RWPhil wrote:

Read and Convert.png

 


I'm not sure you "got it".  You want to make a single VI that has the Get Reading function in it, possibly with a Boolean that determines whether or not you follow it with "Convert Signal" (as both need to use the same Sensor Reference).  Whereever in your code you call this with a particular Sensor, this code should run and be the only code that runs involving the Sensor until all your sensor processing is done.  [If there are other Sensor-specific functions that need to have the "right" sensor, you may need to make this routine incorporate them, as well ...].

 

Now, if you want to do a read from anywhere in your code, you call this function.  If it is currently "busy" reading, say, TC2, it will "block" until the earlier call finishes and delivers its output.  Now it will be able to run and present its version of the Sensor to the Get Reading and optionally to Convert Signal without problems.  As these are (by your design) the only place these functions to access the Sensor for reading can be used, there can only be a single Caller at any time.

 

Or at least it should work that way (Famous Last Words) ...

 

Bob Schor

Message 6 of 14
(3,616 Views)

@ShockHouse wrote:

Does anything stop you from implementing Semaphores? That way only one Read is being ran at a time.


I highly recommend using an Action Engine over Semaphores.  They are simpler and faster.

 

An alternative would be to have a loop that constantly reads all of the channels and outputs via a Notifier, Queue, Global Variable, etc. the values.  Then you other loops just have to perform a read of those to get the new/latest value.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 7 of 14
(3,610 Views)

@Bob_Schor wrote:


Or at least it should work that way (Famous Last Words) ...

 

Bob Schor

Hi Bob, I completely understand what you're saying. Like you say, it's designed that way - a single VI to block all other callers. But, I am seeing data from the wrong sensor and/or wrong conversion at the output (I'll disable the conversion to find out is going wrong in the morning), so while it should work that way, it appears it isn't.

 

By my logic, if the VI is indeed reentrant and blocks in the expected manner, this leaves the wrong input (i.e. the sensor enum) as the source of the wrong data.

 

I am confused.


0 Kudos
Message 8 of 14
(3,565 Views)

Hi Crossrulz, I agree with you about the Action Engine but I have tried and failed (I referred to it as an FGV in my original post). In each state (action), decided by the sensor enum input, I placed a copy of the GetReading VI and the Convert VI. This didn't work - I saw the same behaviour as before - AE blocks but the enum seems to be wrong.

 

I really like the separate loop idea, though, and I already have the global variables set up to carry the values and I have conditional disable rules already in place as an alternative to the ADC collection for a simulation and UI.

 

For now, I'll try semaphores and report back - I have a feeling they're going to work as I can include the enum input as part of the blocking code, something the AE and the non-reentrant VI's don't accomplish.

0 Kudos
Message 9 of 14
(3,556 Views)
Solution
Accepted by topic author RWPhil

Hi all, thanks for your contributions so far. I have an update.

 

Firstly, semaphores didn't work. The problem wasn't to do with blocking and my ranting and raving about the enum was entirely unjustified.

 

In fact, I still don't know where the actual problem is but I have a magic delay fairy that has fixed it. Digging a little deeper into the read function, I noticed the data coming back from the ADC was constant for about 100-120 ms, then it moved onto the next channel data for 100 - 120 ms, despite reads occurring approx every 15 ms. This was entirely independent of the input config, which varied on every read! Eventually, a small signal would be read at the battery monitor when a larger one was expected and the shutdown sequence was initiated.

 

Very strange. Need to look into this much deeper but for now I think I'll add a module to handle the ADC acquisition anyway, so thanks for that suggestion, Crossrulz.

0 Kudos
Message 10 of 14
(3,504 Views)