SQO and SQI on a ControlLogix: the Sequencer That Will Not Step

SQO and SQI on a ControlLogix: the Sequencer That Will Not Step

SeqCtl.POS sat at 1 for three days on a 1756-L83E while the indexer kept running on step one, and the rung holding the SQO had nothing in it at all — left rail, instruction, right rail. That is the entire fault, and the execution table explains it in two lines.

Prescan sets the SQO enable bit to true. Rung-condition-in going false is what clears it. And the position increments when the enable bit transitions from false to true, which on an unconditional rung is a transition that never happens, because the bit was already true before the first scan of Run and nothing in the project ever takes it down.

So the first thing to put in a watch window is not the position. It is .EN.

The line in the execution table that explains most of this

The SQO execution table is four rows long and two of them are doing all the work.

Prescan: the enable bit is set to true. Rung-condition-in is false: the enable bit is cleared to false. Rung-condition-in is true: follow the flow chart, which is where the increment lives. Postscan: not applicable. Put that beside the description at the top of the same page — when .EN transitions from false to true, .POS is incremented, and the position resets to 1 when it becomes greater than or equal to .LEN — and the behaviour of a sequencer stops being mysterious. The instruction does not step because the rung is true. It steps because the rung became true, which means something upstream of the SQO has to go false between steps, and on a machine that runs steadily the only candidate is usually the step-complete condition itself.

The rung being true is not the event. The rung becoming true is the event.

Three timing lanes showing the SQO enable bit from the end of prescan through eight scans: an unconditional rung where .EN stays true and never increments, a rung already true at the mode change where the first increment is missed, and a rung pulsed by a step-complete bit that increments on every rising edge

The top lane is a machine that ran for three days on step one. The middle lane is the one to be careful about, because it works, it just starts one step late.

That middle lane needs a caveat, because it is read out of the execution table rather than printed in it. If the rung is already true at the moment the controller goes from Program to Run, prescan has left .EN true, so the first scan of Run produces no transition and no increment — while the masking operation, which the manual ties to .EN being true rather than to the transition, still writes the current element to the destination. I have not put a scope on that to watch the first millisecond. Put .EN and .POS in a watch window on your own controller and toggle the key before you rely on it.

What the position means, and why element 0 is a parking space

.POS is where the instruction is now. It is not where the instruction is going.

Advertisement

That sounds like pedantry until you write the fault display. With a Length of 8 and an array of nine elements, .POS runs 1, 2, 3 up to 8, sets .DN when it equals .LEN, and then resets to 1 on the next transition rather than to 0. Element 0 is never written to the destination during normal cycling and the only way back to it is a RES on the control structure — the manual’s own example conditions that RES on the first-scan bit. So the array you build needs one more element than the Length, the extra one is a park position, and the machine has not looked at it since the last power cycle. An error typed into element 0 will sit there undisturbed for a year, until the day somebody resets the sequencer.

Now, not next. Write that on the fault display before you write anything else.

A nine-element DINT array drawn as the sequencer table for an eight-station indexer, each element showing its binary step pattern and what the step does, with element 0 marked as the park position, the position pointer at element 3, and a wrap arrow back to element 1

Length 8, nine elements, position 3. The wrap goes to 1 and not to 0, which is the off-by-one that sends people looking for a missing step at the end of the cycle.

Array sized exactly to the Length is the other half of the same mistake. An array of eight with a Length of 8 puts the last step’s subscript one past the end of the tag, and a subscript that exceeds its dimension is a major fault, type 4 code 20.

Nine elements for eight steps. Write it in the tag description so the next person does not shorten it.

One more from the operand tables, printed identically on all three sequencer instructions: do not use CONTROL.POS in the Array subscript. Give the instruction the first element of the array and let it do its own indexing. Writing Steps_Out[SeqCtl.POS] makes the rung resolve a subscript and then hands the instruction a starting point it will index from again.

Why there are two instructions

SQO steps and writes. SQI confirms. That is the division of labour, and it is the reason the reference manual describes SQI as detecting when a step is complete in a sequence pair.

The pair share one CONTROL tag and work on two different arrays. The SQI takes the machine’s actual input word as its Source, masks both it and the element at .POS, and sets rung-condition-out true when the two agree — meaning the machine has physically reached the state that step was asking for. Put the SQI to the left of the SQO on the same rung and that true is exactly the false-to-true transition the SQO is waiting for, so the sequencer advances on confirmation rather than on a timer. As soon as .POS moves, the inputs no longer match the new step’s pattern, the SQI goes false, .EN clears, and the rung is armed for the next confirmation without a single one-shot anywhere.

No one-shot, no timer, and no guess about how long the step is going to take.

A ladder rung with an SQI followed by an SQO, both naming the control tag SeqCtl with Length 8, the SQI comparing Station_Inputs against the Steps_In array and the SQO writing the Steps_Out array into Station_Outputs, with a five-step description of what one confirmed step looks like

Two arrays, two masks, one control tag. The rung is a handshake rather than a sequence of timers.

Use an SQI on its own and you take on the stepping yourself: the manual’s worked alternative is an ADD to increment the position, a GRT to decide whether another value is available, and a MOV to reset the position after a full pass. It works, and it is more rungs than the pair.

Advertisement

Three instructions to replace one. That is most of the argument for the pair.

There is a trap inside the shared control tag and it comes from the pseudo-operand rule that FAL and FSC live under too. Length and Position are written into the control tag at download and never again, and where two instructions share a backing tag and specify different values, the later value overwrites the earlier one. Type 8 into the SQI’s Length box and 9 into the SQO’s and one of them wins silently. Keep the two numbers identical and check them in the tag editor after a download rather than on the instruction face.

Check the two Length values in the tag editor. The instruction face will not tell you.

SQL is the third of the family, and it is the loader: it writes a Source value into the array at .POS, which is how you teach a sequencer a step from the machine instead of typing the bit pattern by hand.

The mask, in the two shapes it goes wrong

The mask decides which bits of the destination the sequencer owns — 0 blocks, 1 passes — and the instruction reads the destination as well as writing it, ANDing the current value with the complemented mask so that the bits it does not own survive.

That is why you would ever want to leave bits alone. Bits 0 to 7 of Station_Outputs belong to the sequencer; bits 8 to 15 belong to the manual jog logic; a mask of 16#0000_00FF hands the sequencer its eight and protects the rest on every step. Get the mask too wide and there is no error of any kind — just a sequencer quietly stamping zeros over another routine’s outputs eight times a cycle, reported months later as an intermittent fault by somebody who does not know the sequencer exists.

No error, no fault bit, and nothing in the cross-reference that points at the sequencer.

The second shape is narrower and easier to miss. The operand tables say INT and SINT mask types are zero extended to the size of a DINT, and zero blocks: enter 16#FFFF as the mask against a 32-bit array element and what the instruction actually uses is 16#0000_FFFF, so bits 16 to 31 of the destination can never change, whatever you put in the array. The bit pattern is in the table, the instruction is running, and the top half of the word is dead. The worked mask arithmetic is laid out bit by bit in our sequencer reference article if you want to follow one through.

The rest of the list, in the order it is worth checking

Most of a stuck sequencer is visible in a watch window on the control tag before you open a rung.

A field table of what to look at when a sequencer will not step: the enable bit stuck true, the position not moving, the position stuck at zero, a Length of zero, an array sized equal to Length, CONTROL.POS used in a subscript, a sixteen-bit mask against a DINT, two instructions with different Length values, and a type 4 code 20 major fault

Six of the nine rows are answered by the control tag alone. The three marked ones are the ones that produce no error of any kind.

A Length of 0 in the tag while the instruction face reads 8 means the number was typed and never downloaded, because the Length box is a pseudo-operand and not a live setting. A position stuck at 0 on a machine that has been running means nothing has stepped since the last RES. And the sequencers are on the list of instructions not allowed in safety routines, which is worth knowing before you design a guard-door sequence around one.

A Length of 0, a position stuck at 0, and an enable bit stuck true. Check all three.

When a sequencer is the wrong shape entirely

Worth one honest paragraph, because the answer genuinely is sometimes no.

A sequencer earns its place when the bit pattern per step is fixed, the step count is stable, and the sequence is a ring rather than a tree — a rotary indexer, a wash cycle, a bottling carousel on a CompactLogix 5380. It stops earning its place the moment a step can go to one of three places next, or waits on two different permissives, or needs a name on the HMI rather than a number. A DINT holding a state number, a CASE statement and a UDT array holding the step data gives you named steps, arbitrary transitions and a fault display that can say “capping” instead of saying 6, and on a Logix controller that is often the better machine to inherit. What you give up is compactness, which matters less than it used to. What you should not do is rewrite a working SQO into forty rungs of state logic because a sequencer feels old-fashioned; if Structured Text is where the project is heading, that is a decision for the next machine.

Compactness against explainability. That trade decides it, not the age of the instruction.

Advertisement

What to do at the panel

Put SeqCtl.EN, SeqCtl.POS, SeqCtl.LEN and SeqCtl.DN in a watch window, in that order, and run one cycle. If .EN never goes false, the fault is the rung and not the sequencer, and what you are looking for is whatever is supposed to take the step-complete condition away. If .EN cycles and .POS does not, check .LEN for a zero and the array dimension against the Length.

Binary display in the tag editor costs nothing and saves the next person an hour.

Then set the array’s display style to binary in the tag editor before you leave, and comment the tag with what each bit drives. Nobody is going to work out that 3084 means stations 2, 3 and 11 at two in the morning, and the ladder troubleshooting routine is a lot shorter when the table reads as a table.