FC510x - PCI-Karten für CANopen

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.

 
SDO-Eintrag bearbeiten

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

 
Parameter
Beschreibung
NETID
Die NetID ist ein String mit 23 Byte Länge und ergibt sich per Default aus der IP-Adresse des Rechners, ergänzt um zwei Bytes. Sie adressiert die FC5101 Karte und kann dem Griff "ADS" im System Manager entnommen werden.
PORT
Enthält die Portnummer des ADS Gerätes - hier also die Portnummer des zu adressierenden CANopen Busteilnehmers.
IDXGRP
Entspricht dem 16 Bit Index im CANopen Objektverzeichnis.
IDXOFFS
Entspricht dem 8 Bit Subindex im CANopen Objektverzeichnis.
LEN
Die Länge des zu lesenden bzw. zu schreibenden Parameters in Bytes.
DESTADDR
(nur ADSREAD)
Enthält die Adresse des Puffers, der die gelesenen Daten aufnehmen soll. Der Programmierer ist selbst dafür verantwortlich den Puffer in der Größe so zu dimensionieren, dass er ‚LEN' Bytes aufnehmen kann. Der Puffer kann eine Einzelvariable, ein Array oder eine Struktur sein, dessen Adresse man mit dem ADR - Operator ermitteln kann.
SRCADDR
(nur ADSWRITE)
Enthält die Adresse des Puffers, aus dem die zu schreibenden Daten geholt werden sollen. Der Programmierer ist selbst dafür verantwortlich, den Puffer in der Größe so zu dimensionieren, dass ‚LEN'- Bytes daraus entnommen werden können. Der Puffer kann eine Einzelvariable, ein Array oder eine Struktur sein, dessen Adresse man mit dem ADR - Operator ermitteln kann.
READ
Durch eine steigende Flanke an diesem Eingang wird der ADS-Befehl ausgelöst
TIMEOUT
Gibt die Zeit bis zum Abbrechen der Funktion an
BUSY
Dieser Ausgang bleibt solange auf TRUE, bis der Baustein eine Befehlsanforderung ausführt, längstens aber für die Dauer der, an dem 'Timeout'-Eingang angelegten, Zeit. Während Busy = TRUE wird an den Eingängen kein neuer Befehl angenommen. Bitte beachten Sie, dass nicht die Ausführung des Dienstes, sondern nur dessen Annahme zeitlich überwacht wird.
ERR
Dieser Ausgang wird auf TRUE geschaltet, wenn bei der Ausführung des Befehls ein Fehler aufgetreten ist.
ERRID
Enthält den befehlsspezifischen Fehlercode des zuletzt ausgeführten Befehls. Wird durch das Ausführen eines Befehls an den Eingängen auf 0 zurückgesetzt.

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:

 
MSB
LSB
Bit 31
Bit 30...24
Bit 23...20
Bit 19..16
Bit 15...0
1
Bit 6..0 des SDO Error Codes
Bit 19..16 des SDO Error Codes
Bit 27...24  des SDO Error Codes
ADS ERROR Code, Bedeutung siehe Kapitel Fehlerbehandlung und Diagnose

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 per ADS
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