Dynamic (Indirect) Addressing
Today’s post is another guest article, this one written by Steve Myres. Steve owns Automation Solutions, a controls integration company that also provides machine mechanical, electrical, and fluid power troubleshooting and design.
In this article, I’ll describe and compare the tools various PLC brands have given us for working with memory locations that are dynamically calculated by the PLC at run-time, rather than entered literally and referring to the same register every time the PLC executes that instruction. In PC programming, this is often referred to as using “pointers”. I usually use the term “indirect addressing” with PLC’s, but that’s AB’s name for a particular type, so it’s both vendor-specific and narrower than the concept I’m describing, so to avoid confusion, I’ll use the phrase “dynamic addressing” in this article to refer to these capabilities in general.
Allen-Bradley has had good dynamic addressing for a couple of decades now, in two forms, “indirect” and “indexed” addressing. The following description refers only to table-based controllers like the PLC-5 and SLC, as the concept is significantly different in a tag-based controller like a ControlLogix or CompactLogix. In indirect addressing, parts of the address to be calculated are replaced by a literal address enclosed in square brackets. An AB static or literal address would be of the form N7:100, with the file reference before the colon and the element number after. You can virtualize either or both (N[N7:0]:0, N7:[N7:0], or N[N7:0]:[N7:1]). The contents of the register specified are used in place of the part of the address that was replaced, so if N7:0 contained 12, then N7:[N7:0] would be interpreted as N7:12. Integer registers can be accessed to the bit level by designating the bit position with a slash, as N7:0/15, but I don’t recall if you can indirectly address the bit position. AB’s second form is “indexed” addressing, meaning that you can set a special register, called the “index register” to a certain value, and that all addresses you designate with a number sign “#” before the address, will be offset by the value in the index register. If the index register is set to 4, then #N7:100 would be interpreted as N7:104. You can even use both indirect and indexed addressing on the same element, as in #N7:[N7:0]. Note that the processor uses indexing and the index register internally on some instructions such as COP, so it’s impossible to use indexed addressing with these instructions (and the address entered automatically gets a number sign added), though you can still use indirect addressing.
Classic Koyo PLCs’ implementation, which they call “pointer” addressing, is also global, but limited to indirect mode without indexing. Data memory is called “V-Memory”, and is octal addressed. You might have a math box where V2040 is added to V2050. To use an indirect address, you substitute a “P” in place of the “V”, so “P2100” means “The register whose address is stored, in binary form, in V2100”. There are instructions that convert from octal so you can enter the actual octal address in ladder and have it converted before storage in V2100. Since the “P” substitutes for a “V” in the syntax, this implementation is limited to addressing only V-Memory dynamically, though since all variables are stored in V-memory (reals, 32 bit BCD and binary INTs, etc.), this limitation isn’t quite as severe as you might think.
Do-More, designed and built by Host Engineering and also available from Automation Direct, has improved on that in a couple ways. First, the address syntax is now more AB-like, which allows all types of memory (V, N, D, R, C, X, Y, etc) to be addressed dynamically, though the pointers still must be V-Memory locations. The syntax is V[V100] or C[V100]. The other enhancement is adding a feature similar to indexed addressing, but only available when indirect addressing is used. You can also enter a constant offset as part of the pointer, as in D[V100 + 50]. The constant offset must be in the range 0 to 63.
Idec Microsmart PLC’s have an implementation of dynamic addressing that includes the concepts of both indexed and indirect addressing. Rather than being a global addressing mode that can be applied anywhere like AB, Koyo, or Do-More, it’s limited to a single indirect move instruction, so rather than be able to work on registers in place at a dynamically calculated location, you can only move registers at such a location to another dynamically specified location. Fortunately, this is a very common application for dynamic addressing, fetching a recipe of setpoints from a table and loading them into the locations for the running setpoints, or saving the running ones to a recipe slot. Then for recipes the instruction vs. address mode limitation isn’t really a hindrance, and the instruction allows “repeats” (MOV N consecutive registers from the source to N registers at the destination), so it does work well for recipe management. The IMOV instruction takes four parameters, source pointer and offset, and destination pointer and offset. This is both the power and the awkwardness of the instruction. OTOH, it’s much more flexible than if the source or destination were fixed-only, but it’s often the case that one or the other is fixed, and when it is, entering address parameters in the instruction is a little roundabout. Given the format of the instruction (pointer, offset, pointer, offset), and the fact that most instructions like ADD and so on will accept either a register address or a constant, you’d think you could enter a literal address by simply entering it and placing a 0 in the offset, but for some reason this instruction won’t accept constants in the offset arguments. You have to create a register, set it to 0, reference it in the offset, and hope nothing overwrites it.