FBC and DDT: Comparing an Array Against a Reference, and Which One Reports What

One sentence in 1756-RM018A separates these two instructions: each time the DDT instruction finds a mismatch, the DDT instruction changes the reference bit to match the source bit, and the FBC instruction does not. Everything else about them — the operands, the two control structures, the result array, the fault codes, the 0.16 µs per bit — is identical.

That one sentence decides which of them belongs in your project.

FBC answers “how does the machine differ from the known-good state”, and it keeps answering it, scan after scan, for as long as the difference exists. DDT answers “what has changed since I last looked”, once, because the act of reporting a mismatch is also the act of absorbing it into the reference. One is a comparison against a standard. The other is a change detector that eats its own reference, and pointing it at a golden master you wanted to keep is the mistake this instruction is famous for.

FBC and DDT operand blocks with Source InputState element 0, Reference GoodState element 0, Result Mismatch element 0, compare control CmpCtrl with Length 128, and result control ResCtrl with Length 32

Two CONTROL tags, not one. The manual’s caution about sharing them is the strongest wording in the chapter.

What both of them actually do

Take a machine whose input state lives in four DINTs: 128 bits of photo eyes, limit switches, guard interlocks and drive-ready bits, copied in from a 1756-IB16D and a pair of 1734-IB8 modules on the far end of the network. Beside it sits a second four-DINT array holding what those bits read when the machine is stopped, guarded and healthy. Point an FBC at the pair with Length 128.

It walks the bits, and every time source bit n differs from reference bit n it writes the number n into the next element of the Result array and advances the result control’s .POS. Three mismatches on a machine with a guard open, a jammed eye and a drive not ready gives you Mismatch[0] = 17, Mismatch[1] = 42, Mismatch[2] = 96, and a result .POS of 3. Bit 42 is InputState[1].10, because 42 minus 32 is 10, and working that out by hand at three in the morning is the part nobody enjoys. These are bit numbers within the compared range rather than tag names, so the useful version of this always has a lookup beside it — a string array, an HMI message table, or a UDT indexed by bit number — turning 42 into “infeed guard door”. Without that, the instruction has produced a list of integers that only the person who wrote the reference can read.

The Length counts bits, the same as it does on a bit shift instruction.

Four DINTs is 128, not 4.

Get the unit wrong low and you compare the first handful of bits and declare the machine healthy. Get it wrong high and the instruction reads past the end of the array, sets .ER and generates a major fault, which is at least honest about itself.

The mode bit, and what each mode is for

.IN in the compare control chooses the search mode, and it changes the instruction’s whole character.

Clear .IN and the instruction is in all mode: each time the rung goes from false to true it searches for every mismatch between the two arrays and records all of them, setting .FD after the last one. Set .IN and it is in one-at-a-time mode: each false-to-true transition finds the next mismatch, stops there, sets .FD and records the position. All mode gives you the complete picture in one scan and pays for it in that scan. One-at-a-time spreads the same work across as many scans as there are mismatches, which is the closest thing these instructions have to the distribution that FAL and FSC get from their Mode operand, and that pair has its own article on this site.

Advertisement

One-at-a-time only advances when the rung cycles.

So a rung held true reports one mismatch and then nothing at all.

That looks exactly like a working instruction which has found everything, and it is the failure that sends people digging through the reference array. Drive it from a condition that genuinely toggles — a sequencer step, an alternating bit, the same one-shot that triggered the comparison — and check .DN on the compare control to know when the sweep has finished.

Two control tags, and the caution that earns its capital letters

1756-RM018A prints a CAUTION here rather than an IMPORTANT, and the wording is worth quoting in the rung comment: use different tags for the compare control structure and the result control structure, because using the same tag for both could result in unpredictable operation, possibly causing equipment damage and injury to personnel. They are not interchangeable, and they count different things.

The compare control holds .LEN as the number of bits to compare and .POS as the current bit. The result control holds .LEN as the number of storage locations in the Result array and .POS as the current position in it. Point both at one tag and the instruction is using the same two numbers to mean four things, and a bit index that walks to 128 is simultaneously a result index walking off the end of a 32-element array. Cross-reference the control tags before believing this one is right, because it is easy to type in a hurry and impossible to spot by reading the rung.

Size the result array for the bad day

The Result array needs one element for every mismatch the instruction might record.

Get that wrong and the fault is Type 4, Code 20: a result .POS greater than the size of the result array.

Work out that worst case rather than the expected one.

The expected case is two or three mismatches, because that is what a machine with one guard open looks like and it is what you tested with. The bad day is a 1734-IB8 dropping off the network and thirty-two bits going to zero in one scan, or somebody downloading a project with a different reference, or the first scan after a power-up when nothing has been read yet and the entire 128 bits disagree. A DINT[32] result array is comfortable right up until the moment 40 bits differ, and then the controller faults, during exactly the event you built the diagnostic to catch. A DINT[128] array covers every bit the compare can reach and costs 512 bytes. Size the result array for the full Length, or cap the comparison at what the result array can hold and accept that a flood reports only the first n. Either is defensible. Faulting is not, and it is worth knowing which of the four places will name the instruction when it happens.

The first 32-bit word of the source and the reference with bit 17 differing, a result array holding 17, 42 and 96, and the two behaviours on the next scan

Scan two is the whole difference. The FBC still reports three mismatches; the DDT has already absorbed them.

Which one, for which job

The decision is genuinely simple once the reference behaviour is clear.

Use FBC when the reference is a standard you want to keep — a known-good input state, a commissioning snapshot, a recipe as it was downloaded. The instruction reports the same differences on every sweep, which is what you want for a screen that says what is currently wrong, and the reference survives every comparison because nothing writes to it. Use DDT when you want an event rather than a state: a list of what changed since the last sweep, a first-out record of which input moved first, a change log that feeds a message to a historian. The reference becomes a rolling copy of the last known state, which is exactly right for that job and useless for any job that needs the original back.

Never point a DDT at your golden master.

Copy it first.

COP GoldState[0] WorkRef[0] 4 costs 0.27 µs and is the difference between a reference you can still compare against next year and one that has quietly become a copy of whatever the machine was doing this morning.

What the comparison costs

Both instructions carry the same per-bit term, and it is a big one.

LOGIX-RM002B gives FBC as 0.193 + (x × 0.16) µs with no mismatches and DDT as 0.177 + (x × 0.16) µs, where x is the number of bits compared, and each recorded mismatch adds roughly 0.13 µs on top — 0.193, 0.315 and 0.428 µs of overhead for zero, one and two mismatches on the FBC, against 0.177, 0.325 and 0.455 on the DDT. The two are the same instruction as far as timing goes, so cost never decides between them. What the per-bit term does decide is how much you compare: 128 bits costs 21 µs and nobody will notice, 4096 bits — 128 DINTs, a decent-sized machine’s whole input image — costs 655 µs, and that is a serious number to spend on every sweep of a diagnostic that exists to be reassuring.

Per bit, this is the most expensive way to notice a change.

A FAL with an XOR expression over the same 128 DINTs costs about 124 µs and tells you which words differ rather than which bits, and a plain comparison of four DINTs against four DINTs costs almost nothing and tells you only that something differs. The honest design question is which answer the screen actually needs, and the answer is usually bit numbers for a small, well-chosen set of inputs rather than for every bit in the controller. Compare the fifty bits that mean something, not the four thousand that exist, and run the sweep once a second rather than every scan — scan time spent proving nothing is wrong is the easiest cost in a project to justify and the hardest to notice.

A table of the published rows for FBC and DDT at zero, one and two mismatches, with the cost of a 128-bit and a 4096-bit sweep worked out beside them

The per-bit term is identical for both. Only the mismatch overhead differs, and only in the third decimal place.

Advertisement

What to check next

Read the two control tags on every FBC and DDT in the project and confirm they are different tags, then check that the result array is at least as long as the compare Length or that something limits how many mismatches can be recorded. Then decide, deliberately, whether the reference in front of you is meant to survive: if it is, the instruction must be FBC, and if a DDT is already pointed at it, that array is no longer the reference anybody thinks it is. Where the comparison drives an alarm list, the bit-number-to-message lookup is the part worth reviewing hardest, because a diagnostic that reports “mismatch at bit 42” to an operator at three in the morning has reported nothing at all.