How to call function every Nth seconds in IEC61131-3 structured text (TwinCAT3)? - plc

What I want to do in the code?
I want to create a function block that is made up out of 4 methods: start, stop, run, calculate. Start method will call a run method that has an while loop that periodically calls calculate method. The while loop inside the run method will end only if the stop method is called.
What I have tried already:
When I call the object.start() I want it to start a cycle that will go as long as I don't call the stop method.
timer(IN := triggerTimer, PT := T#0.1S);
trigger(CLK := timer.Q);
workingFlag := TRUE;
run();
The cycle will be in the run method. Cycle will consist of a while loop conditioned via workingFlag variable. When workingFlag is True the the while loop will constantly trigger a timer structure which will every 0.1S call the calculate method.
WHILE workingFlag = TRUE DO
triggerTimer := TRUE; //Start timer
IF trigger.Q THEN //If timer expired execute code below ...
calculate();
triggerTimer := FALSE; //Reset the timer
END_IF;
END_WHILE
Finally the stop method will just set the workingFlag to False and theoretically it would end the cycle in run method.
workingFlag := FALSE;
What is the problem?
After I call the object.start() my whole PC crashes. Therefor ... I think something is horribly wrong with my code (:
What I want to achieve with this?
The object will be a PID controller. And I want in the main program just call the start method when I want it to regulate and stop when I need it to shut down.
To this day I was calling manually the calculate method inside my main program with the timer that you can find in the run method above.
My problem with this approach was that when I had more PID's (or another functions I needed to call periodically) the code got messy really quick.
Therefor I wanted to create a function block that would have local timers and would be managing the periodical calling by itself.
So please any suggestions how to approach this problem?

Jouke already told you that WHILE is the reason. Here is your code example refactored. This is how it should be done if you want 100 milliseconds impulse work.
timer(IN := TRUE, PT := T#100MS);
IF timer.Q THEN
calculate();
timer(IN := FALSE); // reset timer
END_IF;
But remember that your main PLC cycle should not be longer than 100ms.
The object will be a PID controller. And I want in the main program just call the start method when I want it to regulate and stop when I need it to shut down.
Every PID function block has Enable input parameter. You can use that to start and stop PID.
Just set you Start variable to PID function block input, that is it.

It crashes because you instruct the PLC to run the while loop forever. The PLC software already runs cyclically (according to your PLCtask). It would be easier to put your code that is inside the while loop into a method (or in the body of the function block) that you call every cycle.
A PLC starts the code from top to bottom. Then 10ms (or other cycletime) later, it executes the same code again from top to bottom. So it's essentially a big while loop already. When running a while loop like in your example, the code enters the while loop, but never exits. Then a watchdog somewhere times out and TwinCAT crashes.

Related

UVM End of test Objection Mechanism and Phase Ready to End Implementation

I am exploring different ways to end a UVM test. One method that has come often from studying different blogs from Verification Academy and other sites is to use the Phase Ready to End. I have some questions regarding the implementation of this method.
I am using this method in scoreboard class, where my understanding is after my usual run phase is finished, it will call the phase ready to end method and implement it. The reason I am using it my scoreboard's run_phase finishes early, and there are some data into queues that need to be processed. So I am trying to prolong this scoreboard run_phase using this method. Here are is some pseudo-code that I have used.
function void phase_ready_to_end(uvm_phase phase);
if (phase.get_name() != "run") return;
if (queue.size() != 0) begin
phase.raise_objection(.obj(this));
fork
begin
delay_phase(phase);
end
join_none
end
endfunction
task delay_phase(uvm_phase phase);
wait(queue.size() == 0);
phase.drop_objection(.obj(this));
endtask
I have taken inspiration for this implementation from this link UVM-End of Test Mechanism for your reference. Here are some of the ungated thoughts in my mind on which I need guidance and help.
to the best of my understanding the phase_ready_to_end is called at the end of run_phase and when it runs it raises the objection for that scoreboard run_phase and runs delay_phase task.
That Delay Phase task is just waiting for the queue to end, but I am not seeing any method or task which will pop the items from the queue. Does I have to call some method to pop from the queue or as according to the 1st point above the raised objection will start the run phase so there is no need for that and we have to wait for a considerable amount of time?
Let me give you some pre-context to this question. I have a scoreboard where there are two queues whose write methods are implemented and they are being fed correctly by their source.
task run_phase (uvm_phase phase);
forever begin
compare_queues(); // this method takes data from two queues and compares them, both queues implementation are fine and they take data from their respective sources. Let me give you a scenario, let's suppose there are a total of 10 transactions being generated but the scoreboard was able to process only 6 of them and there are 4 transactions left when all objections are dropped. So to tackle that I implement this phase_to_ready_end method in my scoreboard.
end
endtask
The problem with this method that I am having is that, when I raise the objection in this phase_ready_to_end and call delay_phase method, nothing happens. And I am curious is there more to this implementation or not?
Sorry for the delay. I have shared more context to the existing question. Please see to that, let me know if it is confusing.
We have a pair of monitors that calls write method implemented inside the scoreboard. The monitors typically capture the transaction from BUS and call these WR methods to push the transactions. Thus two source and destination monitors WR into two - source and destination - queues as and when they find the transactions.
We have a checker task with RD-n-check running in forever loop in the run-phase of scoreboard. It's in a while loop and watches if the destination queue has non-zero entry. Once it finds so, it pops the head entry from destination queue and then pops the head entry from source queue as well and compares the two entries to declare if the check was a PASS or FAIL.
There are more than 2 queues and more than a pair of source/destination of course, but broadly this is the architecture around here.
Now in the current scenario, it seems that the checker tasks stop prints after certain point of time in some of the test cases. Upon adding debug prints thoroughly, it seems that checker tasks that does the job #2/#3 above and gets called inside the forever loop of the run-phase, exits gracefully one last time. However they are entered again - which is to say that the forever loop that should be calling them didn't call. As if the forever loop of run-phase stopped completely.
We also added another forever loop in run-phase that observes whether the queues are empty. From prints inside that parallel loop and from the monitor prints, we know that the queues aren't empty and monitors did push WRs into the queues for a long time.
It seems that the forever loop stopped working suddenly ( going by prints spewed out) all of a sudden but another set of threads that we added in runphase in another forever loop just to monitor those queues - keep printing that the queues have contents. So run-phase shouldn't be over but the checker tasks running in forever has stopped.
We are using Vivado 2020.2 for the simulation. This is a baffling/weird problem for us and we did go through prints multiple times to make sure nothing has been missed out. It seems we are missing very very basic or has hit a bug/broken some basics of UVM coding to land into here.
If you have any help, thoughts here, will appreciate that greatly.
The function phase_ready_to_end() gets called at the end of every task-based phase when all objections have been dropped (or never raised at all).
Typically a scoreboard has a queue or some kind of array of transactions waiting to be checked sent from a monitor via an analysis_port write() method. If your scoreboard is an in-order comparison checker, the queue size is zero when there are no more transactions waiting to be received.
If you look at the code in the link you shared, there is the following in the write_south method doing exactly that:
if (!item.compare(item_stream.pop_front()))

How do I loop something and wait for something before re-looping? [swift]

Im basically trying to make a segment of code run over and over once they tap once, and run only if the previous run was completed.
How would I do this exactly, Im completely new to Swift.
At the end of your first loop, put a variable that sets to true and then under the IBAction where they tap once, check if that variable is true or not and if it is true, do your re-loop.
Another way you could do it is loop in the viewDidLoad, which is called before any visuals appear. This way, there's no way they could tap the button or whatever you're monitoring until the view has appeared, which is a separate function.
But I doubt you need to wait for a loop to finish, because the execution time of a loop is so fast it will have happened before they can tap (unless it's a very long loop).
1) IBAction ( code would start to run)
2) You could use a if statement to check to see if what you want done is done.
3) You could use a for to determine how long the code is ran.

can a timer trigger during another timer's callback?

I have two timers running simultaneously. The first timer triggers every 1 second and takes 0.2 seconds to run. The second timer triggers every 20 minutes and takes 5 minutes to run. I would like to have the first timer continue triggering during the 5 minutes it takes the second timer execute its callback. In practice, during the second timer's callback the first timer does not trigger. Is it possible to configure the timers to execute the way I want?
There is a workaround, depending on how your timer callbacks' work is structured. If the long timer callback is running a long loop or sequence of calls to different functions, you can insert drawnow() or pause(0.01) calls to make it yield to Matlab's event dispatch queue, which will handle pending handle graphics and timer events, including your other Timer's trigger.
It's sort of like old-school cooperative multitasking where each thread had to explicitly yield control to other threads, instead of being pre-empted by the system's scheduler. Matlab is single-threaded with respect to M-code execution. When a Matlab function is running, events that get raised are put on an event queue and wait until the function finishes and returns to the command prompt, or drawnow(), pause(), uiwait() or a similar function is called. This is how you keep a Matlab GUI responsive, and is documented under their Handle Graphics stuff. But Matlab timer objects use the same event queue for their callbacks. (At least as of a couple versions ago; this is only semi-documented and might change.) So you can manage their liveness with the same functions. You may also need to tweak BusyMode on your timers.
This is kind of a hack but it should get you basic functionality as long as you don't need precise timing, and don't need the callbacks' code to actually run in parallel. (Whichever timer callback has yielded will wait for the other one to finish before proceeding with its own work.)
If the long callback is really blocked on a long operation that you can't stick drawnow calls in to, you're out of luck with basic Matlab and will need to use one of the workarounds the commenters suggest.

Matlab: simulate command window input by a script

I need a way to execute a script in matlab from within another script. The tricky part is, that the first script is a while loop, which polls every 60 seconds for a new job. If a job is found (created by me), the main.m file should be called. Now, the problem is that I want to be able to modify main.m and all other functions while the while loop is already running. The loop looks something like this:
while run
- pause 60 seconds
- get jobs form text file on network drive
- run main(jobID)
- save result on network drive
end
I thought the eval command would do the trick. But it doesn't. I think Matlab compiles all functions that could be called during runtime as soon as I start my while loop. From then on I cant change anything without restarting the while loop. (I can change it but Matlab ignores all changes).
Is there a way around this problem? I thought there was a method of executing commands inside the command window, just as if a user had typed it. But I cant remember.
Amro's solution with rehash works perfectly. Matlab detects changes in m-files even when it's already running a script!
I think you may be able to do what you want with a timer object.
First create a main.m function to define and initialize your timer:
function main
% Create timer that calls the sub-function checkmfiles every 60 seconds
t = timer('TimerFcn', #checkmfiles, 'Period', 60, 'ExecutionMode', 'fixedRate');
start(t);
function checkmfiles(obj,events)
% Just a dummy function, you'll need to expand it to fit your needs
if exist(f1) == 2
disp('''f1.m'' found.');
eval('f1');
else
disp('No file found.');
end
The example above assumes that f1.m doesn't exist initially. You can run main.m and then create an arbitrary f1.m (example assume that the function takes no inputs) afterwards that will be run by the timer callback. This method has the added benefit that it doesn't tie up your Matlab session while the timer runs.

How to handle class methods being called again before they are finished?

What is the best way to handle this situation on an iPhone device: My program ramps the pitch of a sound between two values. A button pressed calls a method that has a while loop that does the ramping in small increments. It will take some time to finish. In the meantime the user has pressed another button calling the same method. Now I want the loop in the first call to stop and the second to start from the current state. Here is the something like what the method should look like:
-(void)changePitchSample: (float) newPitch{
float oldPitch=channel.pitch;
if (oldPitch>newPitch) {
while (channel.pitch>newPitch) {
channel.pitch = channel.pitch-0.001;
}
}
else if (oldPitch<newPitch) {
while (channel.pitch<newPitch) {
channel.pitch = channel.pitch+0.001;
}
}
}
Now how to best handle the situation where the method is called again? Do I need some kind of mulitthreading? I do not need two processes going at the same time, so it seems there must be some easier solution that I cannot find (being new to this language).
Any help greatly appreciated!
You cannot do this like that. While your loop is running no events will be processed. So if the user pushes the button again nothing will happen before your loop is finished. Also like this you can’t control the speed of your ramp. I’d suggest using a NSTimer. In your changePitchSample: method you store the new pitch somewhere (don’t overwrite the old one) and start a timer that fires once. When the timer fires you increment your pitch and if it is less than the new pitch you restart the timer.
Have a look at NSOperation and the Concurrency Programming Guide. You can first start you operation the increase the pitch and also store the operation object. On the second call you can call [operation cancel] to stop the last operation. Start a second operation to i.e. decrease the pitch and also store the new object.
Btw: What you are doing right now is very bad since you "block the main thread". Calculations that take some time should not be directly executed. You should probably also have a look at NSTimer to make your code independent of the processor speed.
Don't use a while loop; it blocks everything else. Use a timer and a state machine. The timer can call the state machine at the rate at which you want things to change. The state machine can look at the last ramp value and the time of the last button hit (or even an array of UI event times) and decide whether and how much to ramp the volume during the next time step (logic is often just a pile of if and select/case statements if the control algorithm isn't amenable to a nice table). Then the state machine can call the object or routine that handles the actual sound level.