SDO Kommunikation mit FC510x
CANopen SDO (Service Daten Objekt)-Kommunikation dient zum Auslesen bzw. Beschreiben beliebiger Parameter im Objektverzeichnis des CANopen Busknotens. Die FC5101CANopen PCI Karte benutzt die SDO Kommunikation zur Konfiguration der Kommunikationsparameter beim Aufstarten. Zusätzlich sind zwei Arten der anwendungsspezifischen SDO Kommunikation möglich:
1. Download von anwendungsspezifischen Parametern beim Aufstarten
Hierzu sind die entsprechenden Parameter im System Manager bei dem entsprechenden Knoten im Griff "SDO" einzugeben. In eckigen Klammern erscheinen die Objekte, die sich aus den Konfigurationen im Griff CAN Node ergeben. Anschließend können beliebige Objektverzeichniseinträge angefügt werden.
Die Karte erwartet eine positive Quittierung des Parameterdownloads vom jeweiligen Busteilnehmer. Falls ein Parameter nicht geschrieben werden konnte (SDO-Abbruch durch Busteilnehmer), so versucht die Karte den entsprechenden Wert auszulesen und mit dem zu schreibenden Wert zu vergleichen - es könnte sich ja z. B. um einen Read_only Wert handeln, der bereits korrekt im Busteilnehmer konfiguriert ist. Bei Übereinstimmung geht die Karte zum nächsten Parametereintrag.
2. Upload und Download zur Laufzeit per ADS
Zur Laufzeit des Systems können SDO-Zugriffe auf die Objektverzeichnisse der Busteilnehmer über die Beckhoff ADS-Kommunikation erfolgen. Diese ist aus der SPS, aus der NC, vom OPC-Server, aus ActiveX-Controls oder von beliebigen anderen ADS Teilnehmern aus möglich.
Hierbei wird das SDO Protokoll komplett auf der Karte abgehandelt. Mit den ADS-Funktionen ADS Write bzw. ADS Read werden die Parameter auf die Karte übergeben und die Daten übergeben (Write) bzw. abgeholt (Read). Hierbei entspricht der Parameter "IDXGRP" dem 16 Bit-Index im CANopen Objektverzeichnis und "IDXOFFS" dem 8-Bit Subindex im CANopen Objektverzeichnis. Details zu den ADS Funktionsbausteinen finden sich in der TwinCAT Dokumentation (Beckhoff Information System).
Die Parameter der ADS Funktionsbausteine bilden sich wie folgt auf die SDO Parameter ab:
ADSREAD / ADSWRITE
Die ERRID ist ein 32 Bit Wert. Das Low-Word (Bits 0...15) enthält die allgemeinen ADS ERROR CODES, das High-Word (Bits 16...31) gibt SDO-spezifische Error Codes zurück:
Falls einer der Werte SDO Additional Code, SDO Error Code oder SDO Error Class größer ist als die zur Verfügung stehende Datenbreite (ausgeblendete Bits gesetzt), so wird im High-Word (Bits 16..31) der Wert 0x2115 zurückgegeben.
Beispiel: SDO Read per ADS
Im folgenden Beispielprogramm (Strukturierter Text) für die Verwendung der ADS Dienste für die SDO Kommunikation wird Objekt 0x1000, Subindex0 aus dem Knoten mit der Portnummer 0x1001 ausgelesen. Es handelt sich um den CANopen DeviceType. Dieser ist als UnSigned32 codiert und damit 4 Bytes lang.
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
Der aufgerufene Funktionsbaustein SDO_READ ruft seinerseits mehrfach die ADSREAD Funktion auf. Er sieht wie folgt aus (zunächst die Variablendeklaration):
FUNCTION_BLOCK SDO_READ
VAR_INPUT
ADSNetID:STRING(23); (* The AMSNetID addresses the FC5101 card. 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
Beispiel: SDO Write per ADS
Im folgenden Beispielprogramm (Strukturierter Text) für die Verwendung der ADS Dienste für die SDO Kommunikation wird Objekt 0x6200, Subindex3 aus dem Knoten mit der Portnummer 0x1001 beschrieben. Es handelt sich um digitale Ausgänge auf einem E/A Knoten.
(* 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
Der aufgerufene Funktionsbaustein SDO_WRITE ruft seinerseits mehrfach die ADSWRITE Funktion auf. Er sieht wie folgt aus (zunächst die Variablendeklaration):
FUNCTION_BLOCK SDO_WRITE
VAR_INPUT
ADSNetID:STRING(23); (* The AMSNetID addresses the FC5101 card. 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