EL6751- SDO communication
CANopen SDO (Service Data Object) communication is used to read or write any parameters in the CANopen bus node's object directory. The EL6751 CANopen terminal uses the SDO communication for the configuration of the communication parameters when starting up. Two types of application-specific SDO communication are additionally possible:
1. Downloading Application-Specific Parameters when Starting Up
The appropriate parameters are to be entered here in the System Manager for the corresponding node in the "SDO" tab. The objects that result from the configuration in the CAN node tab appear in square brackets. Any desired number of object directory entries can then be inserted.
The terminal expects a positive acknowledgement of the parameter download from the relevant bus device. If it was not possible to write a parameter (the bus device has aborted the SDO) the terminal then attempts to read the corresponding value back and to compare it with the value that was to be written. This is because it could, for instance, be a read-only value, and therefore already correctly configured within the bus device. If the values match the terminal goes to the next parameter entry.
2. Upload and Download at Runtime via ADS
It is possible to perform SDO accesses to the bus devices' object directories using Beckhoff's ADS communication when the system is running. This is also possible from the PLC, from the NC, from the OPC server, from ActiveX controls or from any other ADS device.
The whole SDO protocol is handled by the terminal. Using the ADS Write or ADS Read functions the parameters are transferred to the terminal, and the data is transferred (write) or fetched (read). The "IDXGRP" parameter here corresponds to the 16-bit index in the CANopen object directory, while "IDXOFFS" corresponds to the 8 bit sub-index in the CANopen object directory. Details about the ADS function blocks can be found in the TwinCAT documentation (Beckhoff Information System).
The ADS function block parameters are represented as follows in the SDO parameters:
ADSREAD / ADSWRITE
Parameter |
Description |
---|---|
NETID |
The NetID is a string, 23 bytes in length, and is formed by default from the IP address of the computer with an additional two bytes. It addresses the EL6751 and can be taken from the "ADS" tab in the System Manager. |
PORT |
Contains the ADS device's port number - this is the port number of the CANopen bus device that is to be addressed. |
IDXGRP |
Corresponds to the 16 bit index in the CANopen object directory. |
IDXOFFS |
Corresponds to the 8 bit sub-index in the CANopen object directory. |
LEN |
The length of the parameter that is to be read or written, in bytes. |
DESTADDR (only ADSREAD) |
Contains the address of the buffer which is to receive the data that has been read. The programmer is himself responsible for dimensioning the buffer to a size that can accept 'LEN' bytes. The buffer can be a single variable, an array or a structure, whose address can be found with the ADR operator. |
SRCADDR (only ADSWRITE) |
Contains the address of the buffer from which the data to be written is to be fetched. The programmer is himself responsible for dimensioning the buffer to such a size that 'LEN' bytes can be taken from it. The buffer can be a single variable, an array or a structure, whose address can be found with the ADR operator. |
READ |
The ADS command is triggered by a rising edge at this input. |
TIMEOUT |
States the time before the function is cancelled. |
BUSY |
This output remains TRUE until the function block has executed a command, but at the longest for the duration supplied to the 'Timeout' input. While Busy = TRUE, no new command will be accepted at the inputs. Please note that it is not the execution of the service but its acceptance whose time is monitored. |
ERR |
This output is switched to TRUE if an error occurs during the execution of the command. |
ERRID |
Contains the command-specific error code of the most recently executed command. Is reset to 0 by the execution of a command at the inputs. |
The ERRID is a 32-bit value. The Low word (bits 0 to 15) contains the general ADS ERROR CODES, while the High word (bits 16 to 31) returns SDO-specific error codes:
MSB |
LSB
| |||
Bit 31 |
Bit 30...24 |
Bit 23...20 |
Bit 19..16 |
Bit 15...0 |
1 |
Bits 6 to 0 of the SDO error code |
Bits 19 to 16 of the SDO error code |
Bits 27 to 24 of the SDO error code |
ADS ERROR code, see chapter Error handling and diagnostics for meaning |
If one of the values SDO Additional Code, SDO Error Code or SDO Error Class is larger than the available data width (hidden bits set), then the value 0x2115 is returned in the High word (bits 16 to 31).
Sample: SDO Read via ADS
In the following sample program (structured text) for the use of ADS services for SDO communication, object 0x1000, sub-index 0, from the node with port number 0x1001 is read. The DeviceType is CANopen. This is coded as UnSigned32, and is therefore 4 bytes long.
SDO_READ(
StartReading := ReadStart,
CO_Index := 16#1000,
CO_SubIndex := 16#0,
DataLength := 4,
PortNr := 16#1001,
ADSNetID:='192.168.10.11.2.1'
);
IF SDO_READ.ReadDataAvailable THEN
ReadStart := FALSE;
ReadError := SDO_READ.Error;
ReadData := SDO_READ.ReadData;
END_IF
The SDO_READ function block that has been called in turn calls the ADSREAD function a number of times. It looks like this (starting with the variable declaration):
FUNCTION_BLOCK SDO_READ
VAR_INPUT
ADSNetID:STRING(23); (* The AMSNetID addresses the EL6751. Can be empty if only one local single channel card is present*)
PortNr:WORD; (* This Port No. addresses the CANopen Node (see System Manager) *)
CO_Index:DWORD; (* This is the Index of the CANopen Object Dictionary Entry*)
CO_SubIndex:DWORD; (* This is the Sub-Index of the CANopen Object Dictionary Entry*)
DataLength:DWORD; (* This is the Length of the CANopen Object Dictionary Entry*)
StartReading:BOOL; (* only reset to FALSE after ReadDataAvailable=TRUE*)
END_VAR
VAR_OUTPUT
ReadData:ARRAY[0..255] OF BYTE;
ReadDataAvailable:BOOL;
Error:DWORD;
END_VAR
VAR
state:BYTE := 0;
ADSREAD:ADSREAD;
END_VAR
CASE
state OF
0:
IF StartReading THEN
ReadDataAvailable := FALSE;
Error := 0;
ADSRead(
NETID:= ADSNetID,
PORT:= PortNr,
IDXGRP:= CO_Index,
IDXOFFS:= CO_SubIndex,
LEN:= DataLength,
DESTADDR:= ADR(ReadData),
READ:= TRUE,
TMOUT := T#1s
);
IF ADSRead.err THEN
state := 2;
ReadDataAvailable := TRUE;
Error := ADSRead.ErrId;
ELSE
state := 1;
END_IF
ELSE
ADSRead(
NETID:= ADSNetID,
PORT:= PortNr,
IDXGRP:= CO_Index,
IDXOFFS:= CO_SubIndex,
LEN:= DataLength,
DESTADDR:= ADR(ReadData),
READ:= FALSE,
TMOUT := T#1s
);
END_IF
1:
ADSRead(READ:= FALSE);
IF ADSRead.err THEN
state := 2;
ReadDataAvailable := TRUE;
Error := ADSRead.ErrId;
ELSE
IF NOT ADSRead.busy THEN
state := 2;
ReadDataAvailable := TRUE;
END_IF
END_IF
2:
ADSRead(READ:= FALSE);
state := 0;
END_CASE
Sample: SDO Write via ADS
In the following sample program (structured text) for the use of ADS services for SDO communication, object 0x6200, sub-index 3, from the node with port number 0x1001 is written. It concerns digital outputs to an I/O node.
(* Data to be written *)
WriteData[0] := 16#55;
(* write Object *)
SDO_WRITE(
StartWriting := WriteStart,
CO_Index := 16#6200,
CO_SubIndex := 3,
DataLength := 1,
PortNr := 16#1001,
WriteData := WriteData,
ADSNetID:='192.168.10.11.2.1'
);
IF SDO_WRITE.WriteDataFinished THEN
WriteStart := FALSE;
WriteError := SDO_WRITE.Error;
END_IF
The SDO_WRITE function block that has been called in turn calls the ADSWRITE function a number of times. It looks like this (starting with the variable declaration):
FUNCTION_BLOCK SDO_WRITE
VAR_INPUT
ADSNetID:STRING(23); (* The AMSNetID addresses the EL6751. Can be empty if only one local single channel card is present*)
PortNr:WORD; (* The Port No. addresses the CANopen Node (see System Manager) *)
CO_Index:DWORD; (* This is the Index of the CANopen Object Dictionary Entry*)
CO_SubIndex:DWORD; (*This is the Sub-Index of the CANopen Object Dictionary Entry*)
DataLength:DWORD; (* This is the Length of the CANopen Object Dictionary Entry*)
StartWriting:BOOL; (*only reset to FALSE after WriteDataFinished=TRUE*)
WriteData:ARRAY[0..255] OF BYTE; (*This array contains the data to be written to the CANopen Object Dictionary*)
END_VAR
VAR_OUTPUT
WriteDataFinished:BOOL;
Error:DWORD;
END_VAR
VAR
state:BYTE := 0;
ADSWRITE:ADSWRITE;
END_VAR
CASE
state OF
0:
IF StartWriting THEN
WriteDataFinished := FALSE;
Error := 0;
ADSWrite(
NETID:= ADSNetID,
PORT:= PortNr,
IDXGRP:= CO_Index,
IDXOFFS:= CO_SubIndex,
LEN:= DataLength,
SRCADDR:= ADR(WriteData),
WRITE:= TRUE,
TMOUT := T#1s
);
IF ADSWrite.err THEN
state := 2;
WriteDataFinished := TRUE;
Error := ADSWrite.ErrId;
ELSE
state := 1;
END_IF
ELSE
ADSWrite(
NETID:= '',
PORT:= PortNr,
IDXGRP:= CO_Index,
IDXOFFS:= CO_SubIndex,
LEN:= DataLength,
SRCADDR:= ADR(WriteData),
WRITE:= FALSE,
TMOUT := T#1s
);
END_IF
1:
ADSWrite(WRITE:= FALSE);
IF ADSWrite.err THEN
state := 2;
WriteDataFinished := TRUE;
Error := ADSWrite.ErrId;
ELSE
IF NOT ADSWrite.busy THEN
state := 2;
WriteDataFinished := TRUE;
END_IF
END_IF
2:
ADSWrite(WRITE:= FALSE);
state := 0;
END_CASE