Productivity 3000 FIFO: How do I queue mixer calls in order?

Brian Holt9 min read
AutomationDirectHMI ProgrammingTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

The plant has mixers calling material from silos over shared conveying lines. Mixer 1 calls silo 1 on line 1. Mixer 2 calls silo 1 on line 2. While those hoppers fill, mixer 3 calls silo 2 on line 1 and has to wait until mixer 1's hopper is full. There are 12 call signals in total, and they must be served in the order they arrived. A FIFO on the Productivity3000 (P3000) is the right tool. The attempts below are the ones that usually come first, followed by what works.

Stop Using the Shift/Rotate Example as a Queue

The downloadable FIFO example that uses SHIFT/ROTATE is a bit shift register. It is not a request queue.

  • A shift register moves bits one position per clock pulse. A bit's position tells you how many clocks have passed. It does not tell you which mixer asked first.
  • A single bit cannot say who called. You would need one register per call and extra logic to compare their ages. That is exactly the job the FIFO instruction already does.
  • It works for tracking parts on a conveyor at fixed pitch. It fails for random-arrival requests competing for a shared line.

Use the dedicated FIFO instruction in Productivity Suite. It stores word values in an array and returns them oldest-first.

Stop Loading on the Raw Call Bit

Driving the FIFO load input straight from a mixer's call contact is the most common reason the queue "fills up with garbage."

  • Level-triggered load: the call stays on for many scans. If the instruction responds to the input state, you get duplicate entries. If it responds to the input edge, the load fires once, but nothing stops the same mixer from being queued again after the next dropout and re-call.
  • Twelve rungs, twelve FIFO loads: wiring each call to its own FIFO instruction on the same array makes the entry order depend on rung order in the scan, not on arrival order. When two calls land in the same scan, one entry can also be lost.
  • No "already queued" interlock: a mixer that chatters its call bit gets queued several times and gets served twice.

The fix is structural. Capture each call edge into a pending bit. Block re-queueing with a queued bit. Feed the FIFO from a single loader that inserts one ID per load pulse.

Stop Unloading on a Timer or Every Scan

Unloading on a timer, or leaving the unload input true, pops entries whether or not a line can take them. The queue drains and the requests vanish before any mixer is served. Unload only when all three of these are true:

  1. The queue is not empty. Read the instruction's count or empty status, not an assumption.
  2. The target line is idle. No batch is active and the previous hopper has reported full.
  3. The unload is a one-shot, so one unload equals one dispatched call.

Understand What the FIFO Actually Stores

A FIFO instruction manages an array of words plus an internal pointer or count.

  • Load writes the value in the source tag into the next free slot and increments the count.
  • Unload copies the oldest value into the destination tag, removes it, and decrements the count.
  • The array does not care what the numbers mean. You have to encode each call as an integer. It does not store bits or tag names.

Give each of the 12 call signals a unique ID, 1 to 12. Keep a small lookup table, either integer arrays or simply rung logic, that maps each ID to its mixer, silo, and line. A value of 0 then means "no call." That is useful when you check the unload destination.

Size the array for at least 12 entries. With the queued-bit interlock, each call can sit in the queue only once, so 12 is the worst case. Productivity Suite's own help for the FIFO instruction lists the exact field names for source, destination, array, and the full, empty, and count status. Open the instruction dialog and map those fields to the tags below. Do not guess at them.

Decide: One Queue or One Queue per Line

How the 12 calls map to lines decides the architecture. Settle this before writing rungs.

Plant condition Queue design Why
Each call is fixed to one line (for example, mixer 3 from silo 2 always uses line 1) One FIFO per line A single shared queue causes head-of-line blocking. If the oldest entry needs busy line 1, a call for idle line 2 waits behind it for no reason.
Any free line can serve any call One FIFO for all calls Unload the oldest entry to whichever line goes idle first. Arrival order is preserved across the whole plant.
Mixed: some silos reachable on one line only One FIFO per line; route at load time using the lookup table Keeps strict order within each line. Keep the routing rule in one rung so it is easy to audit.

The scenario described, where mixer 3 waits for mixer 1 because both use line 1, is the first case. The line is the shared resource, so queue per line.

Build the Queue Logic

The tag names below are examples. Create them in the Productivity Suite tag database with whatever naming standard you use. The logic is shown as pseudo-ladder. It is not a copy of the instruction's dialog.

  1. Capture call edges. For each call n (1 to 12): on the rising edge of Call_n, if Queued_n is off, set Pending_n.
  2. Single loader. On any scan where no load is in progress, find the lowest-numbered pending call. Move its ID into the load source tag for its line's FIFO. Pulse that FIFO's load input, clear Pending_n, and set Queued_n. Handle one call per pulse. Any calls still pending load on the next scans, which is a few milliseconds of skew and irrelevant against hopper fill times.
  3. Dispatch. For each line: when the line is idle, the FIFO is not empty, and no dispatch is active, pulse unload once. The oldest ID lands in Line1_ActiveID.
  4. Validate the popped call. If the call for that ID has dropped (the mixer cancelled while queued), clear its Queued bit, zero the active ID, and let the next scan unload again. A FIFO cannot delete entries from the middle, so stale calls get discarded at the head.
  5. Run the transfer. Use the lookup for the active ID to open the correct silo discharge and mixer hopper valves on that line. Set Line1_Busy.
  6. Release. On the hopper-full signal for the active mixer: stop the transfer, clear Line1_Busy, clear Queued_n for that ID, and zero Line1_ActiveID. The next unload is now allowed.
// Pseudo-ladder, example tag names
// 1. Edge capture (repeat n = 1..12)
|--[ Call_n  ^ ]--[/Queued_n]-------------------------( SET Pending_n )

// 2. Loader: priority chain, only first pending call fires
|--[Pending_1]--[/LoadBusy]--( MOVE 1 -> L1_LoadSrc )( SET L1_LoadPulse )
|                            ( RST Pending_1 )( SET Queued_1 )( SET LoadBusy )
|--[Pending_2]--[/LoadBusy]--( MOVE 2 -> L2_LoadSrc )( SET L2_LoadPulse ) ...
|  ... Pending_12
|--[ LoadBusy ]------------------------------( RST LoadBusy ) // end of scan

// FIFO instruction per line: Load = L1_LoadPulse, Unload = L1_UnloadPulse
|--[L1_LoadPulse]--[L1_UnloadPulse]--[ FIFO  array=L1_Queue[1..12]
|                                           src=L1_LoadSrc
|                                           dest=Line1_ActiveID ]
|--[ L1_LoadPulse ]--------------------------( RST L1_LoadPulse )

// 3. Dispatch
|--[/Line1_Busy]--[ L1_NotEmpty ]--[ Line1_ActiveID = 0 ]--( L1_UnloadPulse, one-shot )

// 6. Release
|--[ Hopper_Full(Line1_ActiveID) ]---( RST Line1_Busy )( RST Queued_id )
|                                     ( MOVE 0 -> Line1_ActiveID )

Put the loader rungs before the FIFO instruction rungs in the scan. A call then enters the queue in the same scan it is captured.

Match Symptoms to Causes

Symptom Likely cause Fix
Queue count jumps by many on one call Load driven by level, not edge Load from a one-shot pulse through the loader
Same mixer served twice No Queued_n interlock; call bit chatters Block re-queue until released on hopper full
Calls served in rung order, not arrival order Multiple FIFO loads on the same array in one scan Single loader, one ID per load pulse
Queue empties with nothing filled Unload on timer or held true Gate unload on line idle, queue not empty, and one-shot
Line 2 idle while calls wait Single shared queue, head needs busy line 1 One FIFO per line
Line stalls on a mixer that no longer calls Cancelled call still in the queue Validate the popped ID and discard if the call dropped
Queue full or overflow flag set Array smaller than 12, or duplicates loaded Size array at 12 or more, and fix the interlock

Test with Simulated Bits Before Touching the Silos

Simulate first, as a working example of this setup did. Use internal bits for the mixer calls and the hopper-full signals, and leave the real I/O out until the sequencing is proven.

  1. Build a Data View with the FIFO array, count, the empty and full status, each LineX_ActiveID, and all Pending and Queued bits.
  2. Order test: set call bits for mixers 1, 3, and 5 on line 1 in that order, a second apart. The array must read 1, 3, 5, and Line1_ActiveID must go to 1.
  3. Release test: toggle mixer 1's hopper-full bit. The active ID must change to 3, and the count must drop by one.
  4. Simultaneous test: set two calls in the same scan, for example with one bit driving both through a test rung. Both must appear in the queue, and neither may be lost.
  5. Chatter test: toggle a queued call on and off several times. The count must not grow.
  6. Cancel test: drop a queued call before its turn. It must be skipped, and the next call must be dispatched.
  7. Power-loss test: decide what should happen on restart. Either make the queue array, count, and active IDs retentive (check the tag's retentive setting), or clear everything on first scan and let the mixers re-call. Mixing the two leaves Queued bits set with an empty queue, and those mixers are never served.

Move to live I/O only after all seven tests pass. Get it running on one line first, then add the second.

FAQ

Can I use the P3000 shift register instead of the FIFO for mixer calls?

Only if calls arrive at a fixed clock, which mixer calls do not. A shift register tracks position per clock pulse, not which of 12 calls arrived first. Use the FIFO with each call encoded as an integer ID from 1 to 12.

Does the P3000 FIFO load a value every scan the load input is on?

Read the instruction help to confirm whether its load input is edge- or level-sensitive. Either way, drive it from a one-shot pulse through a single loader, with a queued-bit interlock, so each call enters exactly once.

When should I call AutomationDirect support about the FIFO instruction?

Stop and call AutomationDirect technical support if the simulated order, release, and simultaneous-call tests pass but the live queue still loses or reorders entries, or if the instruction's status bits disagree with the array contents in Data View. Have the project file, CPU firmware version, and a Data View capture of the queue ready when you call.

Back to blog