PLC5 to ControlLogix translated indirect addr

JamesL

Member
Join Date
Mar 2014
Location
Maine
Posts
18
PLC5 to ControlLogix translated FALs are broken by indirect reference:
Hi folks, I’m new to PLC’s, I’ve been learning support on some PLC5 heat treat ovens. My Dilemma: I’ve got a new ControlLogix PLC/furnace that has our translated PLC5 ladder on it. Much of it works now after fixing i/o, timers etc, but I’m struggling with indirect references that our PLC5 ladder used.

I’ve been reading here and think I understand the basic idea behind indexed addressing, and indirect addressing, it makes some sense to me how the old logic used them. But the new PLC errors on those rungs and I’m not sure which way to go.

Below are two examples of translated FALs. A seems it'll be okay, B does not...

Example A: Oddly, the translation missed the length. But I presume if I fix that it’ll be okay (no error on CLX rung).

PLC 5 FAL
Control R116:8
Length 30
Position 0
Mode ALL
Destination #N111:0
Expression #N127:0
Translated ControlLogix FAL
Control R116[8]
Length 0
Position 0
Mode ALL
Destination N111[R116_008_POS]
Expression N127[R116_008_POS

Example B: The translation tool indicates “The address references an indirect file number. It was not translated.” The rung is preceded with an “e” offline, and will not allow me to import/run it on the plc. How should that destination address be handled on ControlLogix?
PLC 5 FAL
Control R116:0
Length 30
Position 0
Mode ALL
Destination #N[N119:0]:[N119:1]
Expression #N127:0
Translated ControlLogix FAL
Control R116[0]
Length 30
Position 0
Mode ALL
Destination N[N119_0][R116_000_POS+N119_1]
Expression N127[R116_000_POS]

Thank you,
JamesL
 
Last edited:
Perhaps make the destination address ( N[N119_0][R116_000_POS+N119_1] ) a two dimensional array?
What is the range of N119:0 ?
 
Hi Mike, N119 is an Integer / 50 elements. I'll need to read up on how to configure the two dimensional array.

The original Destination makes sense to me #N[N119:0]:[N119:1] means "start at address N (value of n119:0)(value of n119:1) to create a location... i.e. if n119:0=5 and n119:1=12 at that moment, the Destination is #N5:12 . The translated Destination seems to make sense to do the same task, but this must be forbidden in the new controller? If so it's hard to find examples of how to rewrite what must have been a common problem with indirect addressing translations to ControlLogix
 
Last edited:
JamesL,

The first example you gave can be replaced by a COP instruction, as the PLC5 FAL is just used to copy 30 INTs from N127:0 thru 29, to N111:0 thru 20.

PLC 5 FAL
Control R116:8
Length 30
Position 0
Mode ALL
Destination #N111:0
Expression #N127:0
Translated ControlLogix COP
Source N127[0]
Destination N111[0]
Length 30




The second example is trickier, as I'm sure you are aware.

I think Mike_RH is on the right tack, as there was obviously a range of INT files in the PLC5 that were addressed dynamically by the value in N119:0. If you made N119[0] as the index to the first dimension of your 2-dimensional array, and N119[1] as the index to the second dimension, then the syntax becomes clearer.

Destination N[N119_0 , R116_000_POS+N119_1]

Note that in all cases where an array element such as N119[0] is needed, then the conversion process will have made an alias tag to it, to avoid the "nested index", which is prohibited in Logix5000. e.g. N[N119[0],R116[0].POS+N119[1]] is illegal due to the nested []'s

You will need to be careful - N119:0 (which was used as a pointer to a group of Integer files) could not have had values starting at 0, as these file numbers 0, 1, and 2 are strictly reserved for Output, Input, and Status files. It could be possible that the group of files started at something like N100, N101, N102, etc. You will waste a whole bunch of memory if you just create your new 2-dimensional array N to match the range of values that could have populated N119:0.

I suspect that N119:0 was calculated as "some number + the starting file number" preceding the FAL. It would make sense to remove that ADD if it exists, and then you can reduce the size of the first dimension of the 2-dimension array to match the possible range of "some number"

The whole thing just looks like some sort of recipe grabbing ?, where the recipes are stored in contiguous N files, and recipes numbered 0 to 9 were fetched from NXXX to NYYY data files.
 
Thanks for the info guys. I think i'm getting it daba: I've reviewed these rungs and here is what is occuring: This is a data collection routine. What happens is another routine(12) snapshots current cycle conditions (date, time, temps, vac, etc) and puts them in N127 "process data storage."
Back in this routine(11) my FALs move N127 to Interim Data Collection and/or Scada collection:
Example A occurs if Interim Data Buffer is full and copies N127 to N111 which is grabbed by Scada, and YES, I think you're correct that a simple copy would work there if the FAL gives me trouble.
Example B occurs when Interim Data Buffer is NOT full, and a few rungs down I can see that every time control R116:0 is DN, N119:0 'Interim File Pointer' and N119:1 'Interim Block Pointer' are both indexed. This updates the FAL destination to the next Interim location each time data is moved/copied by FAL. This stores entire cycle in Interim. *N119:0 always starts at 600 at beginning of cycle, so my Interim Collection area is N600 thru N629 (each are Int 1000).
<sorry, probably tmi, but I'm thinking out loud>
So, if I'm getting this, it's doing exactly what you two suspected. So daba, is it as simple as correcting the destination address from
N[N119_0][R116_000_POS+N119_1] to what you wrote with the comma? [N119_0 , R116_000_POS+N119_1]
I'll try that to see if the 'error' indication on the rung clears and test it.
 
Last edited:
Thanks for the info guys. I think i'm getting it daba: I've reviewed these rungs and here is what is occuring: This is a data collection routine. What happens is another routine(12) snapshots current cycle conditions (date, time, temps, vac, etc) and puts them in N127 "process data storage."
Back in this routine(11) my FALs move N127 to Interim Data Collection and/or Scada collection:
Example A occurs if Interim Data Buffer is full and copies N127 to N111 which is grabbed by Scada, and YES, I think you're correct that a simple copy would work there if the FAL gives me trouble.
Example B occurs when Interim Data Buffer is NOT full, and a few rungs down I can see that every time control R116:0 is DN, N119:0 'Interim File Pointer' and N119:1 'Interim Block Pointer' are both indexed. This updates the FAL destination to the next Interim location each time data is moved/copied by FAL. This stores entire cycle in Interim. *N119:0 always starts at 600 at beginning of cycle, so my Interim Collection area is N600 thru N629 (each are Int 1000).
<sorry, probably tmi, but I'm thinking out loud>
So, if I'm getting this, it's doing exactly what you two suspected. So daba, is it as simple as correcting the destination address from
N[N119_0][R116_000_POS+N119_1] to what you wrote with the comma? [N119_0 , R116_000_POS+N119_1]
I'll try that to see if the 'error' indication on the rung clears and test it.

You will need to do something about that "initial value" of N119:0, in roder to use it as the index to the first dimension of your 2-dimensional storage array, other wise it will have to be created as [630,1000]. Whilst that is OK, the processor can handle that size of array, you will not be using the first 600 x 1000 INTs of it, so it would be a total waste of memory - 1,200,000 bytes to be exact !!

You only want 30 x 1000 INTs of data storage, so it would make sense to create a 2-dimensional array that size only. The initial value of N119[0] needs to be modified so that it cycles from 0 to 39, not 600 to 639

Also you need to check that the conversion hasn't created DINT arrays where the originals were INT data-files.
 
You will need to do something about that "initial value" of N119:0, in roder to use it as the index to the first dimension of your 2-dimensional storage array, other wise it will have to be created as [630,1000]. Whilst that is OK, the processor can handle that size of array, you will not be using the first 600 x 1000 INTs of it, so it would be a total waste of memory - 1,200,000 bytes to be exact !!

You only want 30 x 1000 INTs of data storage, so it would make sense to create a 2-dimensional array that size only. The initial value of N119[0] needs to be modified so that it cycles from 0 to 39, not 600 to 639

Also you need to check that the conversion hasn't created DINT arrays where the originals were INT data-files.

Daba,
First, I really appreciate the responses, this one helped clear up some array mystery for me.
Yes, the conversion created all the N600 thru N630 Controller Tags as INT [1000].

So would creating a 2d array N119_0[630, 1000] permit my data to write to N600 thru N630 as before? Or would calling it N600(630,1000) step on the N600 tags already in place?
What I'm confused is if/how this gets the data into the N600 addresses like before so that all the other code/ moves/ fetch find the data where they expect.
If it does, I'll try it first (even though it's wasteful) and see if the rung error clears and if my data gets saved/moved. Then I can fix the other 6 FALs that are errored due to indirect addressing like example B had.

Basically I can run the furnace with this PLC5 > CLX converted logic now, but these 5 or 6 rungs with indirect address FAL errors prevent me from saving data/alarms and setting some key handshake/triggers etc and calling it a 'running' furnace.

~I use to not could spell enguneer. Now I are one.~
-james
 
Last edited:
So would creating a 2d array N119_0[630, 1000] permit my data to write to N600 thru N630 as before? Or would calling it N600(630,1000) step on the N600 tags already in place?
What I'm confused is if/how this gets the data into the N600 addresses like before so that all the other code/ moves/ fetch find the data where they expect.

Allow me to add my 2 cents as I just got back from a startup of a PLC5 to CLX with a very similar issue. The indirect addressing involving the PLC5 data table file number creates quite a mess in this instance. If you created a two dimensional array tag called N[630,1000], you would be creating the best case replica of the PLC5 data table.

However, as you discovered in your question above, the conversion took that one huge 2D array and broke it up for you into several 1D arrays (N600[1000], N601[1000], ... N630[1000]) right? You can create the 2D array and make the indirection work in both arrays, but you then had the issue of moving the data into your N600 tag. I know of no simple clean way to do that.

In the application I just worked on, I removed the level of indirection formerly used by N119:0 in your example and only kept that used by N119:1. Logic would need to be created to examine the value in N119[0] and hard code which tag to use (N600, N601, etc.) for the FAL with one level of indirection. If you only have 6 FAL instructions, this may be the best way to go.

Sadly, this is one of those cases where auto conversion just doesn't cut it.
 
Allow me to add my 2 cents as I just got back from a startup of a PLC5 to CLX with a very similar issue. The indirect addressing involving the PLC5 data table file number creates quite a mess in this instance. If you created a two dimensional array tag called N[630,1000], you would be creating the best case replica of the PLC5 data table.

However, as you discovered in your question above, the conversion took that one huge 2D array and broke it up for you into several 1D arrays (N600[1000], N601[1000], ... N630[1000]) right? You can create the 2D array and make the indirection work in both arrays, but you then had the issue of moving the data into your N600 tag. I know of no simple clean way to do that.

In the application I just worked on, I removed the level of indirection formerly used by N119:0 in your example and only kept that used by N119:1. Logic would need to be created to examine the value in N119[0] and hard code which tag to use (N600, N601, etc.) for the FAL with one level of indirection. If you only have 6 FAL instructions, this may be the best way to go.

Sadly, this is one of those cases where auto conversion just doesn't cut it.

I really appreciate info. Yes, it's very frustrating that there seems to be no basic CLX solution to what must have been a routine way to iterate addresses in PLC5... <And yes, I'm new to PLCs and trying to wrap my brain around things above my slowly, painfully, progressing capabilities - so take my whining with a grain of salt>.

So, I think I understand you to mean, that it would probably work if I hard code my new cycle to start data destination to [N600, R116_POS+N119_1], then when N119_1 value hits max (where it used to iterate N119_0 to get destination from N600, to N601, I would need to mov/hard code destination with N601 in lead like [N601, R116_POS+N119_1] and so on...

*added* Would it make sense to replace my Current FAL with two commands: EQU "if N199_0=600 then FAL 30 words to destination N600[R116_POS+N119_1] ,
then add branches with an EQU & FAL for each value N199_0 can be(the next would be EQU N199_0=601, then FAL 30 to N601[R116_POS+N119_1] and so on through the 30 '600' files.

*added* In that method, would each FAL need it's own Control? or since only one will execute at a time, could they all refer to the same 30 step control e.g. R116_0?

It seems convoluted, but would leave all the other N119_0 and N119_1 iterations and related code untouched and the data collection would end up where it belongs I think...
 
Last edited:
*added* Would it make sense to replace my Current FAL with two commands: EQU "if N199_0=600 then FAL 30 words to destination N600[R116_POS+N119_1] ,
then add branches with an EQU & FAL for each value N199_0 can be(the next would be EQU N199_0=601, then FAL 30 to N601[R116_POS+N119_1] and so on through the 30 '600' files.

It seems convoluted, but would leave all the other N119_0 and N119_1 iterations and related code untouched and the data collection would end up where it belongs I think...

Yes, I agree that it is convoluted. Possibly you can look through your code and eliminate some of the branches. (Hey, in this rung data always gets stored in either N620 or N621 only!)

Daba's idea of the 2D array proposed earlier would work, but it still leaves you with the need to then get the data from the 2D array to your existing N600 tags, as you pointed out. COP or CPS commands may work in this instance, but depending on how/where these tags are used in your ladder, it can be tricky.

There may be a simpler way to do it but without dissecting your whole ladder, it's hard to say. I would hesitate to give a more detailed answer for fear of inadvertantly busting something elsewhere in your program. As I've learned the hard way, wrongly executed indirection programming can create a HUGE mess.
 
Thanks RonJohn, my predicament sounds exactly like what you encountered.
I've taken your thoughts and tried offline replacing my example B problem FAL with the method above <created a branch for each possible pointer N119_0 value followed by a FAL with it's appropriate N600, 601, etc destination followed by the Control+N119_1 pointer.>
The error indication on the rung cleared.
It seems wasteful to have 30 individual branches (60 compare plus FAL commands), to replace what PLC5 did with one branch, one FAL... But, to me at least, if it works, it seems less wasteful than creating a giant array to put the data in, and then have to figure out how to move it to my N600-N630 files/tags anyway.
So here goes - I'm going to repeat the effort for the 4 hung FALs in this routine and try it out. Today/Monday.
Thank you all for your insight, I'll report back my results.
 
Thanks RonJohn, my predicament sounds exactly like what you encountered.
I've taken your thoughts and tried offline replacing my example B problem FAL with the method above <created a branch for each possible pointer N119_0 value followed by a FAL with it's appropriate N600, 601, etc destination followed by the Control+N119_1 pointer.>
The error indication on the rung cleared.
It seems wasteful to have 30 individual branches (60 compare plus FAL commands), to replace what PLC5 did with one branch, one FAL... But, to me at least, if it works, it seems less wasteful than creating a giant array to put the data in, and then have to figure out how to move it to my N600-N630 files/tags anyway.
So here goes - I'm going to repeat the effort for the 4 hung FALs in this routine and try it out. Today/Monday.
Thank you all for your insight, I'll report back my results.

That approach would work, i.e. having 30 branches equating each to successive values of N119[0], and might be safer in the long run.... But do yourself a favour and replace the FALs with COP instructions, no control needed, and much faster.

Further thoughts.... I think I would prefer this method over re-structuring your data storage as a 2-D array, there's less that could go wrong, there's less changes to do, there's less risk..... all at the expense of one big rung (or you could do it as 30 rungs, makes very little difference)
 
Last edited:
Allow me to add my 2 cents as I just got back from a startup of a PLC5 to CLX with a very similar issue. The indirect addressing involving the PLC5 data table file number creates quite a mess in this instance. If you created a two dimensional array tag called N[630,1000], you would be creating the best case replica of the PLC5 data table.

However, as you discovered in your question above, the conversion took that one huge 2D array and broke it up for you into several 1D arrays (N600[1000], N601[1000], ... N630[1000]) right? You can create the 2D array and make the indirection work in both arrays, but you then had the issue of moving the data into your N600 tag. I know of no simple clean way to do that.

You can do this with a bench processor with PLC code, just run some logic that loops through and copies it, file by file, it might be thirty rungs to get it done. I agree since there is no Arithmetic in this FAL, it is just a copy. Also, why not shift the index numbers to start at zero while you are cleaning this up?

The other thing I see is that you may need to calculate the index prior to using it in the FAL (or COP) instruction, I don't think that can be an expression as shown by the translated version. You need a tempDINT or INT to add the index and offset right before the instruction that is using indirection in your new 2D array tag.

But I have written temporary code to copy and manipulate data to prepare new logic to work from new tags or a new arrangement of it, run it on a real PLC or even in an emulator, then delete that file or rung(s) and SaveAs again...
 
Last edited:
That approach would work, i.e. having 30 branches equating each to successive values of N119[0], and might be safer in the long run.... But do yourself a favour and replace the FALs with COP instructions, no control needed, and much faster.

Further thoughts.... I think I would prefer this method over re-structuring your data storage as a 2-D array, there's less that could go wrong, there's less changes to do, there's less risk..... all at the expense of one big rung (or you could do it as 30 rungs, makes very little difference)

Friday afternoon I rewrote the offending rungs with 30 successive FALs (one for each possible n119_0) and did a short test run. The processor accepts the rungs (not indicted error), but I only got data in my N600 (first one). I need to look a little deeper this morning to see if it was an indexing issue with N119_1 or if it's just because the run was very short.

Also both you folks mentioned COP would suffice here, and (duh) I was in new-guy-just-fix-the-fal mode.

I have a senior tech working with me today and he will be poking at this too. I will follow up with info/code if I need you to look closer.

Thank you guys for all the advice.
 
You can do this with a bench processor with PLC code, just run some logic that loops through and copies it, file by file, it might be thirty rungs to get it done. I agree since there is no Arithmetic in this FAL, it is just a copy. Also, why not shift the index numbers to start at zero while you are cleaning this up?

The other thing I see is that you may need to calculate the index prior to using it in the FAL (or COP) instruction, I don't think that can be an expression as shown by the translated version. You need a tempDINT or INT to add the index and offset right before the instruction that is using indirection in your new 2D array tag.

But I have written temporary code to copy and manipulate data to prepare new logic to work from new tags or a new arrangement of it, run it on a real PLC or even in an emulator, then delete that file or rung(s) and SaveAs again...

Yes, I think I'll switch to COP for those as well.
Regarding the indexing, do you mean rather than start at n600?
I figured I'd leave them since I wasn't creating an array (and leaving unused reserved space), then all my data ends up in the same 'files' as before so I don't need to find the source for all my scada scripts fetching from n600-n630.

I'm already struggling figuring out when/where all the triggering/acknowleging is happening (or not), anthing I don't have to redirect is one more thing I don't have to worry about missing!
 

Similar Topics

Hello, I'm starting in the PLC world, mostly doing troubleshooting and little changes to programs for the last year and a half, also have done a...
Replies
12
Views
3,623
Hello, I am currently converting a project from PLC5 to ControlLogix. I have migrated the program from Logix5 to Logix5000 and any Block Transfer...
Replies
4
Views
3,345
Hello, Today I am trying to figure out the best way to write from controllogix to a plc5 only on change. The situation: - Migrated a Winview...
Replies
3
Views
2,111
We have a controllogix setup with 3 racks, and 14 racks of PLC5 using RIO cards. Here is my question. One of the PLC5 racks has a...
Replies
8
Views
1,715
In one of my project, end-user wants to connect Controllogix 1756 IO's with PLC 5/40E controller on DH+ protocol. 1756 DHRIO card is installed in...
Replies
9
Views
6,717
Back
Top Bottom