COPY Function

COPY(src, dst, len)

Copies up to 32 contiguous registers from src to dst. Both src and dst must be located in the variable table. Len specifies the number of registers to be copied.

This command is useful when sending large blocks of data to the variable table via some communications types, and that data needs to be moved around. This applies especially to PROFIBUS, PROFINET or EtherNet/IP I/O modes that use the variable table.

Parameters

Src(Address)
The address of the first item of the source data to be copied. The source must a location in the variable table.

Dst(Address)
The address of the first item of the destination to which data will be copied. The destination must be a location in the variable table.

Len (DINT)
The number of registers to be copied. A maximum of 32 registers can be copied. Each register is 32 bits.

Returns

The COPY function does not return a value.

Remarks

The data types of the src and dst registers do not need to match. COPY preserves the bits in the registers that are copied. That is, it does not convert the data.

Best programming practice is to set up the data in arrays, and copy from and to arrays. This is usually the cleanest and most manageable method. The RMC also provides the ADDR_OFS function to help copying blocks of individual variables. See Using COPY with the ADDR_OFS Function below for details and examples.

The RMC will not range-check arrays in the Variable Table when copying to or from them. If the len is longer than the array, it will copy beyond the end of the array.

The RMC will range-check local arrays when copying to or from them. This includes arrays declared in user functions or in user program steps.

Notice that although the variable table is broken up into multiple individual files (%MD56, %MD57, etc.), the COPY function can wrap across these file boundaries. For example, copying 30 registers to %MD56.250 will place the first 6 items in %MD56.250 to %MD56.255, and the last 24 items in %MD57.0 to %MD57.23.

An invalid address parameter during compile will trigger a verify error. An invalid address parameter during runtime will trigger a program fault and stop the current task, and the copy will not be performed. This applies to src and dst and the entire range as defined by len.

Multiple COPY statements can be used in a single Expression (113) command, each copying up to 32 registers. Like all assignment expressions, the COPY statement will execute completely before going to the next assignment or copy.

Examples

For the examples that follow, use the following variable table. Notice that i and Len are DINTs.

Variable

Tag Name

Type

 

ProfiData

DWORD[16]

0

ProfiData[0]

DWORD

1

ProfiData[1]

DWORD

:

:

:

15

ProfiData[15]

DWORD

16

i

DINT

17

Len

DINT

18

 

REAL

19

Move1ReqPos

REAL

20

Move1Vel

REAL

21

 

REAL

 

CurveData

REAL[500]

22

CurveData[0]

REAL

23

CurveData[1]

REAL

24

CurveData[2]

REAL

:

:

:

521

CurveData[499]

REAL

Example: Copying values

Copy two values from ProfiData[1] and ProfiData[2] to Move1ReqPos and Move1Vel:

COPY(ProfiData[1],Move1ReqPos, 2);

Example: Writing Curve Data

Writing a curve with 500 registers into CurveData via PROFIBUS. In this example, only 16 registers can be sent to the RMC at a time. A user program would do a loop that transfers the data from ProfiData[2] through ProfiData[15] in successive copies, with some handshaking done between each copy. The variable i must be initialized to zero before starting this loop. The loop assumed to stop when i reaches 500:

Len := MAX(500 - i, 14);

COPY(ProfiData[2], CurveData[i], Len);

i := i + Len;

Using COPY with the ADDR_OFS Function

The ADDR_OFS function can be used to calculate an address from a base address and an offset. For example, if the first tag in the block is called MyFirstTag, then the address of a tag located 4 registers after MyFirstTag can be calculated with:

ADDR_OFS( MyFirstTag, 4)

This is useful when copying from blocks of data that are not declared as arrays. However, best programming practice is usually to set up the data in arrays, and use the COPY function on those arrays, which makes the ADDR_OFS unnecessary.

Example: Simple

Consider a block of 30 miscellaneous parameters in the variable table, each as individual tags. Suppose the user wants to load these parameters using a 14-register PROFIBUS buffer. Therefore, on each subsequent cycle of receiving PROFIBUS data, the following three copy commands would be issued:

COPY(ProfiData[2], MyFirstTag, 14);

COPY(ProfiData[2], MyFifteenthTag, 14);

COPY(ProfiData[2], MyTwentyNinthTag, 2);

 This would be difficult to maintain if a tag is inserted. Consider how the following is more maintainable:

COPY(ProfiData[2], ADDR_OFS(MyFirstTag,0), 14);

COPY(ProfiData[2], ADDR_OFS(MyFirstTag,14), 14);

COPY(ProfiData[2], ADDR_OFS(MyFirstTag,28), 2);

This method can also easily be used to make the length general and put in a loop.

Example: Looping from PROFIBUS Master

This example introduces an advanced and code-efficient manner of using the COPY and ADDR_OFS functions to copy large amounts of data via a small PROFUBUS buffer. Suppose the first data item of the PROFIBUS buffer contained length and offset information, packed into the lower and upper 16 bits of the register. The PROFIBUS master would control the offset and length of the writes. There would be no need to implement looping logic in the RMC, and the handshaking would be reduced.

The code could look like similar to this:

CopyLen := DWORD_TO_DINT(SHR(ProfiData[1], 16));

CopyOffset := DWORD_TO_DINT(ProfiData[1] AND 0xFFFF);

COPY(ProfiData[2], ADDR_OFS(MyFirstReg, CopyOffset), CopyLen);

 

This example could be further improved to be more safe. For example:

CopyLen := DWORD_TO_DINT(SHR(ProfiData[1], 16));

If ( CopyLen > 0 ) Then

    CopyOffset := DWORD_TO_DINT(ProfiData[1] AND 0xFFFF);

    If ( CopyOffset < MaxOffset AND CopyOffset + CopyLen <= MaxOffset ) Then

        COPY(ProfiData[2], ADDR_OFS(MyFirstReg, CopyOffset), CopyLen);    

    Else

        LOG_EVENT(10, CopyOffset, CopyLen);

    End If

End If

 

The Log_Event function would provide the user with some indication of the fault.

 

See Also

ADDR_OFS | Standard Functions


Send comments on this topic.

Copyright © 2024 Delta Computer Systems, Inc. dba Delta Motion