BSL and BSR: A Shift Register That Tracks Product, One Bit Per Position

Type 8 into the Length of a BSL whose array is DINT[8] and you have built a shift register eight positions long, not eight elements long, and the other 248 bits of that array will sit there untouched for the life of the machine. 1756-RM018A prints the reason in one line under Operands: Length is the number of bits in the array to shift. Everything else on this instruction follows from that one word.

Bits. Not elements, not bytes, not words.

A BSL shifts the specified bits one position toward the high end, drops the bit that falls off into .UL, and loads your Source Bit into bit 0. A BSR does the same journey the other way: bit 0 falls into .UL, everything shifts down, and the Source Bit goes into the top of the range. Clock either one from belt travel rather than from time and you have a map of the conveyor in memory, one bit per position, which answers a question no FIFO can — not what order product arrived in, but where each piece is right now.

BSL and BSR operand blocks with Array ZoneMap element 0, Control ZoneShift, Source Bit PhotoEye, Length 240, and the CONTROL bits EN, DN, UL and ER shown with their states

Length 240 with a DINT[8] array uses 240 of the 256 bits available. The remaining 16 never move.

One bit per position, and the arithmetic that sizes it

Put a 12 m accumulation conveyor under this and the design is three numbers. Pick a resolution — say 50 mm, because that is comfortably smaller than the shortest carton you will ever run — and the conveyor becomes 240 positions, so ZoneMap is DINT[8] and Length is 240. Clock the BSL once for every 50 mm of belt travel, taken from an encoder rather than a timer, and ZoneMap bit 0 is the 50 mm of belt under the infeed eye while bit 239 is the discharge. The photo eye at the infeed writes the Source Bit: 1 if product is there at the instant of the shift, 0 if not. From then on the controller knows the position of everything on that belt without another sensor, because the map moves at exactly the speed the belt does.

Resolution is the only real decision here, and it costs twice.

It costs memory, which nobody cares about on a 5580, and it costs scan, which is the number that ends up mattering. Halving the resolution to 25 mm doubles the bit count to 480 and doubles the shift rate, because a shift now has to happen every 25 mm of travel rather than every 50. So the instruction runs twice as often and each run costs roughly twice as much, and the total cost per metre of belt goes up by four. That is the trade nobody writes down: resolution enters the scan budget squared, and it is the reason a shift register that ran fine on a 12 m accumulation belt falls over when somebody copies it onto a 60 m sorter.

The system-level design of an encoder-driven tracking map is its own job. This is what the instruction does underneath it.

Advertisement

BSL or BSR: which direction is down the line

There is no difference in cost or behaviour between them, only a convention the whole project then inherits.

The natural one is BSL with bit 0 at the infeed. New product enters at bit 0, indices increase toward the discharge, and reading ZoneMap[3].14 tells you about a position 110 places along. It reads the way the conveyor runs, left to right, and the arithmetic from position number to array subscript and bit is the obvious position / 32 and position MOD 32. BSR earns its place when the physical direction is the other way. A return line, a reversing shuttle, an indexer that steps backwards on recovery: on those, BSR keeps the index numbering matching the direction of travel, and 1756-RM018A’s own example shows what it does at a word boundary, which is worth reading twice. Shift right across the boundary between array_dint[1] and array_dint[0] and array_dint[1].0 moves into array_dint[0].31. The register is one continuous run of bits and the array subscripts are just where those bits happen to live, so a 240-bit register is not eight separate 32-bit registers and never behaves like one.

A 240-bit shift register drawn as eight DINT words with the bit numbering running continuously across the word boundaries, and the same map annotated with conveyor positions

The word boundary is invisible to the instruction. Position 32 is bit 0 of the second DINT.

The array is DINT, and the Length is still in bits

Two operand rules on this instruction catch people, and both are one line in the manual.

The first is the array type. The Operands table gives Array as DINT ARRAY — not SINT, not INT, and not a BOOL array, which is the one people reach for first because a shift register is obviously made of bits. A BOOL[240] looks like the right data structure and Logix Designer will refuse it, and the reason it refuses is the second rule: the instruction works on contiguous memory and counts bits through it, so it needs the 32-bit words the controller actually stores. The second rule is the Length again, and it bites in a different place the second time. If Length exceeds the size of the array you get a major fault, Type 4, Code 20, because the first specified bit plus the number of bits to be shifted passes the end of the array.

Set Length to 260 on a DINT[8] array and that is a faulted controller, not a warning.

There is also a .ER bit, and it does less than you would hope.

1756-RM018A gives its condition as .LEN less than 0, which is the only error state the instruction reports on its own. Every other way of getting this wrong is a fault or a silent wrong answer, so do not write logic that watches .ER and imagine it is monitoring the shift register. Watch .UL and watch the bit pattern instead.

The bit that falls off the end

.UL is where the product leaves, and it is the output half of this instruction that most people never use.

When the BSL shifts, the bit at the top of the range does not vanish — the instruction unloads it into the .UL

Advertisement
bit of the control structure, where it stays until the next shift. So .UL going true means one thing precisely: a piece of product has just left the last tracked position. That is the discharge event, available one scan after it happens, with no extra photo eye and no extra rung, and it is the natural trigger for a divert, a count, or a handshake to the next conveyor’s controller. 1756-RM018A’s own BSL example makes the indexing concrete: with Length 10 starting at bit 0 of array_dint[0], the instruction unloads array_dint[0].9 into .UL and loads the source bit into array_dint[0].0.

The unloaded bit is the one at Length minus 1, and not the one at Length.

.UL survives exactly one shift.

If the routine that reads it runs less often than the routine that shifts — different tasks, or a shift inside a FOR loop that runs several times in a scan — the discharge events get overwritten before anything sees them. A counter on .UL in the same routine, immediately after the BSL, is the fix, and comparing that count against a separate count at the end of the line is the cheapest health check this whole scheme has.

When the two counts disagree the map has drifted, and a drifting map is the failure that matters.

When the shift outruns the scan

Now the part the instruction reference states as a formula and never as a number you can act on.

LOGIX-RM002B prints BSL on a ControlLogix 5580 as 0.100 + (x × 0.09) µs and BSR as 0.107 + (x × 0.09) µs, with x in bits. Work that through the 12 m accumulation belt: 240 bits is 21.7 µs per shift, and at 0.5 m/s with 50 mm resolution the shift happens ten times a second, so the instruction costs 217 µs per second of running — about two hundredths of one percent of the controller. Nothing. Now work it through a 60 m sorter at 10 mm resolution: 6000 bits is 540 µs per shift, the belt runs at 1.5 m/s so the shift fires 150 times a second, and the same instruction now wants 81 ms of every second.

That is 8% of a controller spent moving bits sideways, whether or not one carton is on the belt.

Compare that per-byte and the shift register looks worse still.

An FFU moves a whole 32-bit element for 0.07 µs while a BSL moves one bit for 0.09 µs, so per byte of data moved a bit shift costs roughly forty times what a FIFO shift costs. You are not paying for data movement, you are paying for bit addressing, and that is the honest reason to keep the resolution as coarse as the shortest product allows.

The failure when you get this wrong is not slowness, and that is what makes it expensive. It is missed shifts. Put the BSL in a 10 ms periodic task on a belt that travels 15 mm per scan at 10 mm resolution and the map needs more than one shift per scan, which it will not get, and the tracking silently stretches. Overlaps show up in the Task Properties Monitor tab as a Task Overlap Count, and as bit 6 of MinorFaultBits in the FAULTLOG object if a GSV reads it from the program. A shift register clocked this hard is one of the reliable ways controller scan time climbs without anybody adding logic.

A table comparing a 12 m accumulation belt at 50 mm resolution against a 60 m sorter at 10 mm, ending in 0.22 ms and 81 ms of controller time per second

The instruction cost is the small half. The shift rate is what turns 540 µs into 8% of a controller.

Where this is the wrong instruction

A shift register answers where, and it answers nothing else.

It has no idea what is at each position beyond one bit of true or false, so the moment the question becomes “which order number is that carton” the map has to be an array of DINTs or a UDT indexed by position, moved with a COP or a FAL rather than a BSL, and the FIFO instructions are the right pair when arrival order rather than position is what you need. A shift register is also wrong on any line where product can overtake, stop independently, or be removed without the belt moving — the map moves with the belt and knows nothing else, so a carton lifted off by hand leaves its bit travelling to the discharge and triggering a divert for nothing.

A line with slip between belt and encoder drifts by exactly that slip, quietly, over a shift.

Re-synchronise rather than trusting it. An eye partway along that clears or sets the bit it is looking at, once per carton, keeps the map honest for the cost of one rung and one sensor.

Advertisement

What to check next

Work out your own two numbers before touching any logic: bits per metre, and shifts per second at maximum belt speed. Multiply the second by 0.100 plus 0.09 times your bit count and you have the cost per second of running, and if that is over about 5% of a scan budget the resolution is too fine and the answer is coarser positions, not a faster task. Then check that .UL is read in the same routine that shifts, that Length is a bit count and not an element count, and that something independent counts product at the discharge so a drifting map announces itself. If the map drifts by a fixed amount every time the line restarts, look at the restart sequence rather than the instruction — a shift register that is not clocked while the belt creeps back into position comes back wrong by exactly that creep.