07-27-2015 01:41 PM
Hi I'm fairly new to Labview and still getting used to the dataflow programming model. I'm trying to use LV as a control panel for some software and hardware running on an FPGA for a prototype I'm creating. The communication with the FPGA is done through UART and seems to work fine. I have the problem however that my control buttons become unresponsive in some specific occasions. I think the best way to go here is that I explain what my program should do (and what I think it should be doing), post my VI, explain when it blocks and hopefully someone can help me isolate the problem.
As I've said LV is supposed to be the control panel, through this panel the user can change some settings and start/stop the measurement. The controls are send to the FPGA (a ZYBO board for the interested) which applies the commands and sends the measurements back.
I based my VI on the simple state machine template and build the rest from there. I tried not to use too much variables as I've read that this breaks the dataflow model but sometimes I couldn't find any other way.
This is how the VI should work: after initialisation it should be in the wait for event state, waiting for a changing value from the start/stop button or the exit button. Every second a timeout event occurs and LV checks with the FPGA (and sends the commands to the FPGA). If the start button is pressed the FPGA starts measuring, in every packet it sends back the FPGA will say how much measurements there are remaining and send 60bytes of data to LV. Most of the time the UART communication is the bottleneck and the number of measurements will start growing. During this time however I'm still able to change the values of the commands I send to the FPGA (like I want). If I press the start/stop button again I send the stop command to the FPGA which means that it will stop measuring but still send data to LV. I think that the VI loops through the same states as when it is measuring (communication -> button control -> Handle Data -> communication). During this time however the GUI does not seem to respond to my button presses, it wont let me change the commands I'm sending or even use the exit button. This unresponsiveness remains while I'm receiving data. Once the number of remaining measurements hits 0 (the "nom" variable in the VI) it goes back to the "wait for event" state and at that time my previous button presses are executed. (So let's say I have pressed the stop button andthere are still some measurements to be sent, if at that moment I press the exit button it won't respond but once the communication is done it will register the exit button press and quit the VI.)
I tried to avoid working with timers since the communication is the bottleneck for the moment, this is the reason why I don't go back to the "wait for event" state once the measurements have started.
I hope my explanation was clear, otherwise I'm happy to clarify some more (or rephrase if needed). A recap of my problem:
During the time that I am measuring and receiving data I loop through the same states as when I stopped measuring and am simply receiving data ("communication -> button control -> handle data -> communication"). When I'm measuring the GUI is still responsive and when I stopped measuring it is not. I hope someone can help me find the problem and hopefully propose a solution.
Thanks in advance!
p.s. As I've said i'm fairly new to LV programming so if you see some other "nono's" you can also tell me in order to improve myself.
Solved! Go to Solution.
07-27-2015 01:48 PM - edited 07-27-2015 01:59 PM
This is the nature of the beast when it comes to State Machines. This is why if you're doing time-intensive operations, you are going to need a parallel loop in order to accept user input. Look in to the Queued Message Handler architecture that ships with LabVIEW. This is essentially an event structure in a loop that sends messages to another loop via a queue. The receiving (slave) loop then acts on those messages and takes as long as it wants without interrupting the user inputs.
In other news, it looks like you utilized the simple state machine pretty well and grasped how to set up states and stuff. Here are a few tips none-the-less:
Cheers
--------, Unofficial Forum Rules and Guidelines ,--------
'--- >The shortest distance between two nodes is a straight wire> ---'
07-27-2015 01:58 PM
You definately want some loops to run in parallel. I tend to have a loop that does nothing but instrument communications. Depending on the instrument, I may even have 2 loops: one for sending commands to the instrument and a second for recieving the data. I use queues to send commands to these loops (send data, stop, etc).
07-27-2015 03:55 PM
Thank you for the push in the right direction. If I understand correctly the QMH is a kind of parallel state machine which is useful when you want to do two (or more) different actions at a different rate? In any case it seems that this would solve my problem. So the fact that the GUI still responds in the measuring case and not in the receiving state is simple (bad) luck and probably due to some background optimization? I admit that I haven't looked at the error handling yet and I haven't figured out yet how I should do this.
I'll try to change my VI using the QMH template and I'll update my post in case this solves it.
07-27-2015 04:05 PM - edited 07-27-2015 04:11 PM
Okay, so really you messed up your user interface functionality by trying to make the loop run continuously. You couldn't let it go back to the event structure state because then it would stop looping until the user did something. But that means you created this other state called Button Control that reads the controls and then keeps looping. Like I said above, you want all of your controls in the event structure, store their values if you need them in a shift register, and then do specific actions if the user presses a button.
Your application currently has two different states where it reads the controls and that's where you're seeing your different behaviors.
Cheers
--------, Unofficial Forum Rules and Guidelines ,--------
'--- >The shortest distance between two nodes is a straight wire> ---'
07-29-2015 08:24 AM
Thank you for the QMH tip. I've added my new VI for future people with the same problem. The only thing I don't really understand is the need for the refnum's and why they are needed in the initialisation, it doesn't seem to do much there (i.e. the program still runs correctly without the refnum's in the initialize state).
07-29-2015 08:54 AM
You may need to use the refnums later, that is why they are stored in the shift register cluster. For example at different states of you program you may want to disable a button, change label, etc... In this way it is easy to access the required refnum via unbundling from the cluster, in any case where you need it...
07-29-2015 09:30 AM
@Avdz wrote:
Thank you for the QMH tip. I've added my new VI for future people with the same problem. The only thing I don't really understand is the need for the refnum's and why they are needed in the initialisation, it doesn't seem to do much there (i.e. the program still runs correctly without the refnum's in the initialize state).
Great job with the QMH, for a simple application like this it looks like you have just what you need. I think marking the QMH as the solution matches your post title perfectly too, because a lot of people come here with questions when their state machines lock up.
One thing to note is that your acquisition is completely timed by the Timeout case in your top loop. This is fine since you don't have many other events that push the timeout back often and if you don't mind if the application waits an extra second to update when the user does something. If you ever need to have a loop with even timing, you can add a third parallel loop that just does the acquisition when required.
Cheers
--------, Unofficial Forum Rules and Guidelines ,--------
'--- >The shortest distance between two nodes is a straight wire> ---'
07-29-2015 12:35 PM
@James.M wrote:
One thing to note is that your acquisition is completely timed by the Timeout case in your top loop. This is fine since you don't have many other events that push the timeout back often and if you don't mind if the application waits an extra second to update when the user does something. If you ever need to have a loop with even timing, you can add a third parallel loop that just does the acquisition when required.
This is only the case when no measurements are being sent to the VI. When the user changes a setting a data packet is directly send. When the hardware has measurements to send the message loop will continue looping through the "Comm" case and continue communicating until there is no more data to be send. The only problem with this solution is that I haven't found a way to ensure a stop command is send when the exit button is pressed; or in other words ensuring that the hardware will stop measuring when the user quits the application. But for the moment it is not too big a problem.
07-29-2015 12:50 PM - edited 07-29-2015 12:51 PM
Oh, I didn't realize you had it looping back to Comm over and over. This will actually eventually turn in to the queue overflowing if there is data continuously. Picture this scenario:
What you want is actually what I said above, where the application waits for the producer (event handling) loop to tell it when to check for data. You've somewhat gone around the functionality of the timeout event.
Cheers
--------, Unofficial Forum Rules and Guidelines ,--------
'--- >The shortest distance between two nodes is a straight wire> ---'