Copying data.... opinions wanted

Join Date
Apr 2002
Location
No income tax, no capital gains tax. Freedom!
Posts
8,389
Designing a COPY or COP command should be easy, but there are so many things to consider. We have decided to add a COPY command even though it is not part of the IEC specification. This should make it easier and faster to copy data around within the controller. The IEC specification doesn't have a COPY or similar command by another name. The IECE specifications requires using a FOR or WHILE loop which isn't very efficient and by now you should know we count time in nanoseconds.

We have the internal part of the COPY command done and it works but now we need to decide how it looks to the user.

We have decided the format will look something like this
COPY(src,dst,count); // duh

Examples:
1. COPY(src,dst,count); // src and dst may or may not be an array
2. COPY(src,dst,count); // dst is an array and i can be index to copy the next block
3. COPY(src,dst,count); // src is an array and i can be index to copy the next block
4. COPY(src,dst,count); // both src and dst are arrays.

We think the first 3 options will be used most to copy data from Ethernet/IP I/O or Profibus DP I/O to other locations.

The most common will be the example 1 where Profibus or Ethernet I/O has just updated a command in the first register of the I/O block. Based on a command a program will be started and that program will copy the data to some variables where they will be used.

The second most common version will be example 2. In this case the cam table will be downloaded over multiple transfers. A new command will indicate that data is ready in the other 31 data registers to be copied. ( Profibus DP can only have consistent data transfers of 32 32 bit value ). The Profibus DP and Ethernet/IP IO locations are fixed and is just a small window through which all the data must be passed. There needs to be a away to transfer cam tables of any size through the small Profibus DP window.

The third most common version will be shifting the data like example 4 but the source and the destination are the same array:
COPY(array[0],array[1],count);

The problem is how does one specify the source is an address and not a value? If we document that the source and destination are address and not values this is inconsistent with the normal way of expressing values. Should we use
COPY(#array[0],#array[1],count); or
COPY(@array[0],@array[1],count);

Is it important to indicate that the src and dst parameters of the COPY command are address and not values.
If so would you use a symbol @,#, & or a function such as ADDR(src) and ADDR(dst) to indicate the parameter are addresses?

COPY(ADDR(array[0]),ADDR(array[1]),count); // too much typing but the intentions are clear.

What if the source and destination are variables and not arrays? Should we allow the user to index off the variable and treat it like and array? If so should we allow COPY(src,dst,count) even though src and dst are just simple 1 register variables. If you think we should allow indexing of a single variable is using the array format misleading or should there be a separate function that makes it clear that the variable is being indexed like an array. For instance COPY(ADDR(src,i),ADDR(dst,i),count) where i can be any expression that evaluates to a DINT and is added to the address of src or dst.

What about the count? Should that be in terms of data type or just total number of registers. I don't like the way Rockwell implemented their COP where it depends of the destination type.
I prefer using number of registers regardless if the UDT or data type is many registers. One can always make count equal to the number of elements time the element size. This is very flexible.

BTW, our COPY command will copy over lapping data up or down. I think the way Rockwell blew it. I have read too many threads about how to shift data up one location. This should be easy an natural.
COPY(#array[0],#array[1],count);
Will shift data up not not fill. We can make a FILL command for that if we need to.

One thing we want to do is to avoid pointer or address arithmetic as much as possible. The IEC specification avoids the use of pointers for good reason and we want to also.

Opinions wanted.
 
The IEC spec uses the move command, which allows (at least in some implementations) moving arrays or UDTs. Is it not better to enhance your Move function rather than move away from IEC?
 
GeoffC said:
The IEC spec uses the move command,
Yes, to move one item to one item like the Siemens Move block. I will look at the latest version of the specfication tomorrow to see if the MOVE block has been enhanced since my copy of the specification. I doubt a length has been added to the MOVE block.

which allows (at least in some implementations) moving arrays or UDTs.
My copy of the IEC spefication says the IEC Move block allows one input and one output of type any. There is no length specified. This means that items must be copied one at a time. An item may be of type any or a derived type so one array may be copied to another or one structure can be copied to another. This does not allow for partial copies or shifting data up or down.

Those 'some implementations' may be non-standard. I will see tomorrow.

Is it not better to enhance your Move function rather than move away from IEC?
Yes, but the goal is to make PLCs and motion controllers easier to program, not to be a slave to a specificaton that is imperfect, incomplete, inefficient or makes programming more difficult that it should be. I shall see tomorrow/today now.
 
Your right, I use the move instruction to move elements, whole arrays or whole structures, there is no provision for length
 
My copy of the IEC spefication says the IEC Move block allows one input and one output of type any. There is no length specified
Isn't the length part of the ANY data type ?
At least this is so in Siemens. And you can copy from defined structure to defined structure using symbols, or a freely selected number of bytes adressing absolutely. (In S7 you have to use the BLKMOV standard block)
 
Ah, looking at the problem through Siemens colored glasses.

I am trying to save my customer from that.

JesperMP said:
Isn't the length part of the ANY data type ?
No.

At least this is so in Siemens.
IEC and Siemens are not the same.

And you can copy from defined structure to defined structure using symbols, or a freely selected number of bytes adressing absolutely. (In S7 you have to use the BLKMOV standard block)
I am trying to save the world from having to build any pointers. That is an abomination. Programming the S7 side is hard enough. I don't want to make it any harder than it needs to be on the motion controller side. I don't want our tech support guys having to waste the time explaining any pointers or even pointers in general. The IEC specification doesn't use pointers but in this case the source and destination is actually a pointer or addresss. Notice, the RS5000 copy command, COP, doesn't indicate the source and destination are really addresses and not values. If that doesn't confuse anybody then imitating the RS5000 COP command is the way to go. ( except for the lack of ability to shift data up ).

Lets say you need to download a cam table of 80 points from the PLC to a motion controller and you have 32 32 bit registers to do it. Register 0 is a command register. When the command is 1 the PLC wants to read data from the motion controller. When the command is 2 the PLC wants to write data. Register 1 is the address to were the PLC will write to in the motion controller. Register 2 is the length. The PLC can use the other 29 registers to transfer data. It will take 3 transfers to download the 80 point cam table. When the motion controller sees the write command (2) coming from the PLC it goes to a write program that copies the up to 29 register, from the other 29 Profibus DP I/O registers, to the correct spot in the motion controller ( the cam table ) and then echoes the command back to let the PLC know it is done and ready for the next command. The motion conmtroller is fast enough that is can easily copy the data before the next PLC scan. During this communication process the PLC does not care about the data being stuffed in the 29 registers that are being moved to the profibus DP registers. The PLC is just copying the next 29 registers of data than must go to the motion controller. The motion controllers write routine also doesn't care about the data except it knows it must move the data from the Profibus DP registers to the cam table.

I have customers that down load 4 to 6 cam tables for curve sawing every time a new piece of wood must be cut. NO two logs are the same.

You can see that I am trying to solve a problem of moving laege amounts of data to and from the Profibus DP I/O registers. It is sometime impossible to fit a data structiure or array in the 29 registers. The IEC specification doesn't really cover this.

I have no control over how this is done on the PLC side. The customers will pick their poison. I ( my customers ) need a way of moving data to and from the Profibus DP registers where there are no data type restrictions. So far the rs5000 COP command looks good. In C I would use the memmove function:
http://www.mkssoftware.com/docs/man3/memmove.3.asp
Note the memmove function preserves the data when it is shifted up unlike the RS5000 COP command.
 
Peter Nachtwey said:
The problem is how does one specify the source is an address and not a value? If we document that the source and destination are address and not values this is inconsistent with the normal way of expressing values. Should we use
COPY(#array[0],#array[1],count); or
COPY(@array[0],@array[1],count);

Is it important to indicate that the src and dst parameters of the COPY command are address and not values.
If so would you use a symbol @,#, & or a function such as ADDR(src) and ADDR(dst) to indicate the parameter are addresses?

COPY(ADDR(array[0]),ADDR(array[1]),count); // too much typing but the intentions are clear.

Peter, I'm not sure that I see this as a problem. There are many instructions for which the argument must be an address and a value is not allowed. It doesn't really make sense to use a value as the source argument and no sense at all to use a value as the destination argument. If you already have a fill instruction then document that both arguments are addresses. Add # or @ characters only if you feel you need to emulate someone elses instruction for the sake inter-platform familiarity, or you could make it optional, the programmer could enter the # character if it was his habit to do so because of AB familiarity, but the compiler ignores it. If you really wanted to preserve the optiion of COPY to copy a constant into an array instead of using a FILL, then since this is likely to be the least often used version then require a type cast before the constant, otherwise, assume its an address.

COPY((float)1.5, dest_array,lenght)

Just an idea.


What about the count? Should that be in terms of data type or just total number of registers. I don't like the way Rockwell implemented their COP where it depends of the destination type.
I prefer using number of registers regardless if the UDT or data type is many registers. One can always make count equal to the number of elements time the element size. This is very flexible.

Agreed, the length should be the number of native words moved.
But you might want to provide a sizeof statement for the programmers convenience so he doesn't have to look up the size of the UDT or go back and change the COPY instruction should he modifiy his UDT. Like in C, sizeof is not an intruction, its a compiler directive solved at compile time.

COPY(src_udt_array,dest_udt_array, 10*sizeof(udt)) //copy 10 udts.
If the UDT is 18 words long then 10*sizeof(udt) becomes 180 at compile time.

I've got not idea how this fits into the IEC framework, just some ideas.

(edit) Looking at what I just said about the sizeof compiler directive, I guess I can see why Rockwell chose to use the destination data type to determine the length, it eliminates the need for the compiler directive. Maybe using the destination element size isn't so bad after all.
 
Last edited:
Alaric said:
COPY((float)1.5, dest_array,lenght)

Just an idea.

Yes, not bad if all programmers were C programmers. I think we would rather have a FILL function. Our tech support doesn't want to explain type casting and only one in ten customer will read the documention to see that a type cast is necessary. The other 9 customers will ask why data is being copied. Do you see the problem?

Agreed, the length should be the number of native words moved.
Noted, I was strongly leaning that way because of my example above where the amount of data being transfered is a hardware limitation and not a software one.

But you might want to provide a sizeof statement for the programmers convenience so he doesn't have to look up the size of the UDT or go back and change the COPY instruction should he modifiy his UDT.
I agree. SIZEOF, LENGTH and LAST.

COPY(src_udt_array,dest_udt_array, 10*sizeof(udt)) //copy 10 udts.

You vote is noted. However, what do you do when the data doesn't belong to an array? What is I have 50 parameters to transfer from the PLC to the motion controller and they are just 50 variables that define a 'recipe' for making a part. The first copy function would

COPY(ProfibusData,FirstParam,29);
The second copy command would need to do either one of the following:
COPY(ProfibusData,ThirtyethParam,29); or
COPY(ProfibusData,FirstParam+29,21); or

but what if there are 500 parameters of positions, velocities, acceleratons, dwell times, time out times etc? Then I need to do something like:

COPY(ProfibusData,FirstParam,count); or

and treat FirstParam as an array even though it isn't. That can confuse many.

I don't want to force the users to
COPY(ProfibusData,FirstParam,29);
COPY(ProfibusData,FirstParam[29],29);
COPY(ProfibusData,FirstParam[58],29);
COPY(ProfibusData,FirstParam[77],29);
COPY(ProfibusData,FirstParam[106],29);
...
until 500 parameter are copied.
In this case the FirstParam would be treated like an array but it would be better to use a variable like
COPY(ProfibusData,FirstParam,29);
and increment I by 29 each time through the loop. FirstParam would be made to look like an array even though it isn't.

Someone here suggested we make a new function that converts a variable and a offset to an address such as

COPY(ProfibusData,ADDR_OF(FirstParam,I),29);
where the ADD_OF adds I to the address of FirstParam. At least this is clear but then why the special case? Not
COPY(ADDR_OF(ProfibusData,0),ADDR_OF(FirstParam,I),29);
Now if is clear the first two parameters are addresses.

What is clearest to you?

I've got not idea how this fits into the IEC framework, just some ideas.
It doesn't. The IEC framework is not perfect or complete. They certainly didn't ask me first. At Delta we can spend hours picking apart ( arguing about ) the fine points until I don't care anymore.

Opinions on indexing off of single variables are wanted. I would be happy to just treat single variables as arrays for the purposes of the COPY command.

(edit) Looking at what I just said about the sizeof compiler directive, I guess I can see why Rockwell chose to use the destination data type to determine the length, it eliminates the need for the compiler directive. Maybe using the destination element size isn't so bad after all.
Yes, but I need to be able to specifiy the number of registers as in my Profibus DP data transfer example above. Limiting length to sizeof or data types would not work when there are a fixed number of registers to stuff the Profibus DP data through.
 
Peter Nachtwey said:
COPY(ProfibusData,ADDR_OF(FirstParam,I),29);
where the ADD_OF adds I to the address of FirstParam. At least this is clear but then why the special case? Not
COPY(ADDR_OF(ProfibusData,0),ADDR_OF(FirstParam,I),29);
Now if is clear the first two parameters are addresses.

What is clearest to you?

COPY(ADDR_OF(ProfibusData,0),ADDR_OF(FirstParam,I) ,29);
 
504bloke, this is the leading contender at Delta right now.

Except we would still allow just the variable or array name if there is no indexing.
COPY(ProfibusData,ADDR_OF(FirstParam,i),count)
but I must admit your way is more consistent.

504bloke said:
COPY(ADDR_OF(ProfibusData,0),ADDR_OF(FirstParam,I) ,29);

The trick is that the ADDR_OF function will always uses register offsets.

My earlier suggestion of
COPY(ProfibusData,FirstParam,count)
does not work because the index I will increment by the data type size. The offset or I must be in registers not in increments of data types because there is no guarantee that data will come through the Profibus DP I/O in integer number of UDTs. Since in my example only 29 registers are transfer in each block the chances are small the UDT will be 29 registers long.
 
How about stating a specific format for the FOR..WHILE loop that the compiler will recognize and automatically generate the optimised copy code. No need for a new copy command.
 
Good idea but....

L D[AR2 said:
How about stating a specific format for the FOR..WHILE loop that the compiler will recognize and automatically generate the optimised copy code. No need for a new copy command.
So what if the data type has 4 32 bit registers. How does one copy just 29 registers? 28 registers is 7 UDTs and 32 is 8 UDTs. See my Profibus DP I/O example above.

We don't permit FOR and WHILE loops within a step. We actually count the nanaseconds that each steps takes to make sure that each step is executed within a scan and is synchronous to the motion control loop which can be as short as 0.5 milliseconds. An infinite or long would take too much time and we can't allow jitter in the scans like a PLC can. This is for a motion controller and the motion controller must do a little motion control between the steps, transitions, I/O and commununications.

Finally, the compiler is not as efficient as hand written assembly language used in the functions.
 
My 0.02

I look forward to using this command. I'm not much help but I thought I would add that you could also look at SFC21 "Fill" command from Siemens. I don't know if this is an IEC command but it does some of what you want to do.
 
Actually, what I want is closer to BLKMOV SFC 20

The FILL function will be .... another function.

CharlesM, I am sure you can see the problem. Right now there is no nice way to copy data blocks that are bigger than the Profibus DP I/O window. Now that we have Profibus DP on our newest controller it is just a matter of time before someone wants to download large cam tables.

I think we have a handle on this now. Now if I can only get my S7-315 DP configured to test this out.
 

Similar Topics

Hello everyone, friends. I need help with something related to SCL. In a FB, I need to copy the value in the DB to the DB at another address. I...
Replies
3
Views
1,385
I created a UDT with recipe parameters and have created several Recipe tags using that UDT as a data type, as well as an "Active_Recipe" tag. if...
Replies
1
Views
1,754
A rung is set up that goes something like this: If sysMessage > 46 ONS---> Cop SysDisp_message Destination: DatabaseMessageHold Watching it in...
Replies
4
Views
2,312
Hey guys. I have a situation where I need to compare a dynamic data value to a static value, then take the greater of the two and use that in my...
Replies
7
Views
3,952
Need a little help with a better way to copy data. I am saving data in an array and I want to move the data from the second oldest to the oldest...
Replies
5
Views
1,503
Back
Top Bottom