FIFO queue setup

Big Brunsy

Lifetime Supporting Member
Join Date
Apr 2014
Location
Iowa
Posts
23
I'm fairly green at PLC programming compared to everyone here. I have a firm understanding of most commonly used instructions. Everything I've learned came from reading this forum, watching youtube, and trial/error in real world.

That being said, I'm trying to hurry up and write a program for our resin distribution system that was running on an old Digi International processor that went obsolete in 2016 and has decided to finally die.

I am updating to a 1769-L33ER v32 since that's what I have sitting on the shelf.

My issue is I need whatever station calls for resin first to be the first one in the queue to get it. Then when it does its fill cycle for that station, move on to the next one weather the one it just filled is full or still needs more. Then, if it does still need more to be entered at the end of the queue again.

I've tried searching on here and have gained some knowledge, but still am stuck at this part in my program.

Any help would be greatly appreciated.
 
Last edited:
I have never used that cpu so not sure if it has a fifo
But if you can use arrays it can be simply programmed.
A trigger (call for resin) writes a specific value (station number) into an array of int.
Then also it shifts the array on by 1. Then use an equal array function and monitor the last word in the array for any 0 (This can be done every second or so depending how quick you must react). If the last word is 0 the also shift the array untill it gets a value bigger than zero....Very rush explanation but i hope you get the idea
 
By "Whatever station calls for resin first", you actually mean "any station calling for resin". If two, or 10, call at the same time, which is first? If none are calling, and one does, that is first, and only.


I wouldn't really bother with a FIFO, unless you have an extremely long fill cycle, but that doesn't seem to be the case.


I'd just check each one in sequence, if it has demand, perform a fill cycle, then step through all the others to check, and back around again.
 
By "Whatever station calls for resin first", you actually mean "any station calling for resin". If two, or 10, call at the same time, which is first? If none are calling, and one does, that is first, and only.


I wouldn't really bother with a FIFO, unless you have an extremely long fill cycle, but that doesn't seem to be the case.


I'd just check each one in sequence, if it has demand, perform a fill cycle, then step through all the others to check, and back around again.

Exactly...if you use a sequence then it would work fine. The reason I gave my explanation is when you do not have a permanent signal for when something is needed. If you do have a permanent signal then normal sequence program will do fine. If you dont then I think my explanation with a sequence applies
 
Exactly...if you use a sequence then it would work fine. The reason I gave my explanation is when you do not have a permanent signal for when something is needed. If you do have a permanent signal then normal sequence program will do fine. If you dont then I think my explanation with a sequence applies

I just use a copy. Not exactly what you are looking for, but maybe will spur an idea in code.

Capture fifo.PNG
 
Are more than two resin stations are involved?


Do calls for resin from the stations come in asynchronously?



Should each station have exactly either 0 or 1 calls active at any time i.e. once station N registers a call for resin, do you want to prevent it from issuing another call until its current call is serviced?


I think a FIFO handles this nicely, especially if the answers to those queries are all yes.


I don't understand the nature of the problem you are having though. Do you not understand the mechanics of the FIFO? I find making a test program often helps. E.g. trigger the FIFO with a rising edge every second or so to put semi-random values, such as the low 8-16 bits of the microseconds WALLCLOCKTIME, into the FIFO, and watch those values move through the array.


Can you post a snippet from the Digi program?
 
Are more than two resin stations are involved?
9 stations serviced by 2 loaders. So 2 stations could be active at any time depending on what loader is assigned to it.

Do calls for resin from the stations come in asynchronously?
Calls for resin are made by a sensor inside the hopper. They come as the resin level drops below that point.


Should each station have exactly either 0 or 1 calls active at any time i.e. once station N registers a call for resin, do you want to prevent it from issuing another call until its current call is serviced?

Yes. The calls for resin are a constant input until such a time that resin is back above the sensor


I don't understand the nature of the problem you are having though. Do you not understand the mechanics of the FIFO? I find making a test program often helps. E.g. trigger the FIFO with a rising edge every second or so to put semi-random values, such as the low 8-16 bits of the microseconds WALLCLOCKTIME, into the FIFO, and watch those values move through the array.

I do not. I didn't even know such an instruction existed until starting my research for this issue.

Can you post a snippet from the Digi program?

I do not have the program, or any way to get it.


This is what I've come up with so far....

Capture247.JPG
 
I think the FIFO is the best choice for your application
I have done many filling applications similar to yours
A few things to consider
In this case you FIFO is event driven
In a PLC there is no such thing as simultaneous calls or load all programs run from top to bottom so the call in line 10 will always be called wile a call in line 11 will only be called if line 10 is not called
Don’t forget you must LOAD and UNLOAD a FIFO, you load it when a new station call’s and unloads when the station is serviced. Us the index to determine if the FIFO is empty a so you need to keep track of what station are loaded so you fill the FIFO with the same station
 
I do not. I didn't even know such an instruction existed until starting my research for this issue.
In this document, there are flow charts of how the FFL works on pp. 565 and 566. FFU is a bit below that.

FFL and FFU instructions are usually implemented in pairs, there needs to be an instance of a common control structure assigned to each of the pair, which keeps track of ths state of the FIFO. The FIFO stack is a separate array.

The key is that those instructions act on a rising edge of their input rungs; the control structure's .EN and .EU bits keep track of the FFL's and FFU's, respectively, input rungs' states from the last (i.e. previous) scan of the program. So, e.g. when the FFL input rung is True and .EN is 0, that is a rising edge and the FFL loads the input value onto the FIFO stack array, and that .EN is assigned a 1; on the next scan, since .EN is 1 from the previous scan, even if the input rung is still True, that FFL will not load the input value again because it does not see a rising edge.

The issue that design causes with this resin station filling application is that two resin stations could call for resin on the same scan, or on contiguous scans, so the first statiion could trigger the rising edge and add its index to the FIFO and assign a 1 to the .EN bit, then the second station's call (a 1 input) would never be detected as a rising on that or any successive scan because that .EN bit is 1.

The way around that problem is to have a separate array of .EN-equivalent "last scan's value" bits, one for each resin station. Each of those bits is only assigned a 1 when its station's index is FFLed (added) onto the FIFO, and assigned a 0 when its station's index is FFUed (removed) from the FIFO, and the .EN and .EU bits are always re-assigned a 0 any time the FFL/FFU instructions flip them to 1.

That approach would look like this (probably in a loop on N from 0 to 8, representing the nine resin stations):
Code:
  calls[N]  calls_active[N]        calls_active[N]
----] [-----------]/[-----------+--------(L)---------------+--
                                |    ___________________   |
                                +---[FFL                ]--+
                                |   [Source            N]  |
                                |   [FIFO     fifo_array]  |
                                |   [Control         ctl]  |
                                |   [Length            9]  |
                                |   [U][Position          0][/U]  |
                                |                          |
                                |        ctl.EN            |
                                +---------(U)--------------+
Where
N - is the number of the resin station being tested on this rung to determine if that station is calling to be filled and N is not yet on the FIFO
calls[N] - is 1 whenever resin station N is calling to be filled
calls_active[N] - is 1 whenever resin station N's number, N, has been loaded via that FFL onto the FIFO and that call has not be serviced by a loader yet.
ctl - is the Control Structure associated with this FIFO.
fifo_array - is an array of at least 9 integers ('N' values) that keeps track of which resin stations are calling to be filled and have been loaded onto the FIFO
The logic around the corresponding FFU instruction will not be strictly parallel to this, because the rising edge trigger will be when a loader comes available and there is at least one resin station index in the FIFO i.e. ctl.POS > 0. The will still be a need to Unlatch the ctl.EU bit to 0 because there are two unloaders, which could both become available to take station indices on the same scan.

The calls_active[N] bit will be Unlatched to 0 when the loader completes servicing the call for resin station N.
 
Here's how I'd approach it.

Create a UDT called "StationUDT" or something, with at least the following elements:
StationID (DINT)
Call (BOOL)
CallAck (BOOL)
CallServiced (BOOL)

The StationID is a numeric value representing each station, 1 through n. So, Station 1's ID is 1, station 2's ID is 2, station n's ID is n, you get the idea.
The Call tag is set by each station when it needs filling.
The CallAck tag is set by the FIFO logic once it has acknowledged the call and entered it into the queue.
The CallServiced tags is set by your filling sequence, once it has filled that station. When the CallServiced tag is turned on, both the Call tag and the CallAck tag should be turned off.

Then create an array of this UDT with as many stations as you have, plus one (plus one because you probably don't have a station zero, and arrays start at zero). If you have 10 stations, you'll end up with a tag called e.g. Stations of type StationUDT[11]. When you expand this out, you'll see 11 instances of your UDT, called Station[0] through Station[10].

Next, make sure to set the StationID for each station to the correct value. When I'm doing things like this, I typically hard-code that with a MOV instruction that moves the right value to the tag every scan.

Next, create an array of DINT's to store your call queue. If you have 10 stations, make the array 10 elements long.

Then, write code so that every time a station requires filling, it turns on it's Call tag - e.g. if station 5 requires filling, it will turn on Station[5].Call

Finally, write logic to store those calls in the DINT array as they're received, using a FIFO. Add logic to unload them from the array using the FIFO as they're serviced. Something like the attached screenshot. This is a very simple example, in a real world application there would likely be a little more to it, but I've kept it very "bare-bones" so you can hopefully adapt it to suit your needs.

Screen Shot 2021-05-21 at 8.47.15 am.png
 
Here's how I'd approach it. ...


Nice.


There needs to an Unlatch of the .EN on the end of Rung 2; the .CallAck bits ensure rising edge detection.


Something similar needs to be done with the .EU bit on Rung 3, because there are two fillers serving all of the stations.
 
There needs to an Unlatch of the .EN on the end of Rung 2; the .CallAck bits ensure rising edge detection.
Good catch - or else an XIO of the .EN in the rung preceding it (which is how I normally do it).
Something similar needs to be done with the .EU bit on Rung 3, because there are two fillers serving all of the stations.
I missed the bit about there being two fillers - that would change it a little, but that's why I made it bare-bones, so it could be adapted :nodi:
 
Sorry to bring up an old thread. I've been playing around with the sample from ASF as a template for my own hopper fill system. Works great when the new calls happen 1 at a time. Not so great when I have multiple stations calling at the same time (comparing to initial startup of a system where all hoppers are empty). I'm comparing a float (load cell analog input) to a preset value to generate the station call bit, but when run, the first scan just sets the call acknowledge bits (will set all of them) but never increments the fifo position. So after the first scan, call acknowledge bits are set but the fifo is still empty.
Not an expert here but I have tried implementing different interlock conditions to no avail.
Any advice?
 
Sorry to bring up an old thread. I've been playing around with the sample from ASF as a template for my own hopper fill system. Works great when the new calls happen 1 at a time. Not so great when I have multiple stations calling at the same time (comparing to initial startup of a system where all hoppers are empty). I'm comparing a float (load cell analog input) to a preset value to generate the station call bit, but when run, the first scan just sets the call acknowledge bits (will set all of them) but never increments the fifo position. So after the first scan, call acknowledge bits are set but the fifo is still empty.
Not an expert here but I have tried implementing different interlock conditions to no avail.
Any advice?

See posts 11 and especially 12 in this thread: @ASF meant to include an [OTU Filling_FIFO.EN] instruction between Rungs 1 and 2.

An alternative would be to prepend an [XIO Filling_FIFO.EN] instruction to Rung 2.

P.S. the .CallAck bits are not all set (latched) on the first scan, but they are all latched so quickly over the first few scans you would not detect, visually, the difference; can you see why?
 
Last edited:
Brian is quite an expert on fifo's (shift registers) & has posted many solutions, so his knowledge is good.
I also have a lot of experience having done quite a few in my 40+ years in this game.
Fifo's sound great for putting data into a queue, however, there are a number of problems.
If it is a conveyor that feeds a number of take off junctions & these junctions are for example given a code the shift register works well in the following manner, pulses are generated by some form of encoder on the conveyor drive, when a part arrives at the infeed of the conveyor it's code is put into the shift register, this then moves along the shift register every pulse from the conveyor.
Each takeoff intersection has it's current id, when a part is shifted into a register that is located at that junction it is compared with the current takeoff ID if the same then it is ejected at that position simple, only sometimes depending on the PLC the first location in the fifo is shifted but the first location is not zeroed, so this may need to be taken into consideration.
If the system is only shifted on a request i.e. like a system that feeds a number of machines that request product then normal operation of a fifo is not exactly what is needed, as the queue is only shifted when a machine is calling. so a different approach is required.
Example we have a system where 4 hoppers give signals to say "Fill ME", sounds easy i.e. 4 element fifo, machine 1 wants product the first register in the fifo is populated with the machine ID, & shifted down, trouble is it is only shifted one place so the feed system does not see the ID as it will probably be looking at element 4, so rather than shift on machine putting the ID in the first element then shift on the last element going to 0, in other words shift on removal rather than population.
So a pulse to shift is initiated when the last element is 0.
Way this can work, a machine requests product, the machine id is put into element 0, no other action, if element 4 is a 0 this shifts the data down the fifo & element 0 is set to 0, the ID in element 4 is then in the first place in the queue, the feed system takes the Machine ID, sets the feed motion & resets elemnt 4 to 0, this initiates a shift to take place ensuring that the next in queue is put in element 4. does not matter if there are 0 in all elements just keeps shifting down every scan (or you could make this in any time frame you wsh).
However, as posted on another thread, what if a machine breaks down, do you need to keep the others running ?, scenario: the system is running queueing as expected but machine 2 breaks down but it is in the queue, let's say element 2, so now we have an ID in the queue but the machine is out of action, when it gets to element 4 the feed system cannot put product into the machine, answers are: 1 some form of manual entry to delete a machine ID in the queue or perhaps an automatic way of doing it, for example, have an auto signal from each machine, if that is not true then iterate though the array & if that machine ID is present delete it by replacing it with a 0.
So think about the things that are important:
Do you really need an encoder, this produces thousands of pulses perhaps per metre, do you really need an encoder ? perhaps a simple star wheel & proximity, providing the window for any eject point is wide enough to see perhaps a couple of pulses.
What if situation: perhaps on a system where a machine calls for product based on first come first served, something goes wrong i.e. a machine breaks down, how do you remove that request from the queue ? manually or an automatic deletion of the request in the queue or perhaps some form of rejection of the request.
 

Similar Topics

Hello, I'm currently programming a MicroLogix 1400 in RSLogix Micro, and I'm trying to put data into FIFO queues. Would you know how to use the...
Replies
4
Views
5,084
I am not sure if this is possible but if there is a way, you guys would be the ones to know. I am currently working on a project where we are...
Replies
7
Views
220
Hello all, I'm using a 5069-L330ER in a project and I need to essentially capture some data that will be shown as a trend on a screen. The data...
Replies
9
Views
963
Hello! I have a network of conveyors bringing raw product to 4 machines. A sensor in the hopper of each machine calls for more product. I'm...
Replies
15
Views
5,876
Hello everyone, has anyone out there ever made a FIFO using an FFL and FFU instructions on a Micro800? I have tried setting it up just as I would...
Replies
9
Views
3,121
Back
Top Bottom