CANopen Master Documentation
Version 6.06.02
Loading...
Searching...
No Matches
SDO / USDO communication

Within the CANopen CC protocol access to entries of a device Object Dictionary is provided by means of Service Data Objects (SDO). Within the CANopen FD protocol access is provided by means of Universal Service Data Objects (USDO).

For the reason of backwards compatibility and in order to keep switching between CANopen CC and CANopen FD simple it is possible to use only the SDO API. In case the protocol stack is running in CANopen FD mode the corresponding functions of the USDO module are called.

API

The API provides functions for read (refer to ComSdoReadObject()) and write (refer to ComSdoWriteObject()) access to the device's object dictionary. Both functions use a pointer to an array of type CoObject_ts, which references the object dictionary entry by index and sub-index.

Once the data transfer has been started, a segmented (or block) transfer is handled by the protocol stack autonomously depending on the data element size. In the same way an upload or download of multiple entries is managed by the protocol stack. An active SDO/USDO communication is aborted upon two incidences:

  • a timeout condition occurs (see Timeout event)
  • the SDO/USDO server responds with an abort message

Please note that for CANopen CC only one SDO connection between a SDO server and SDO client is allowed.

Marker field

The field CoObject_ts::ubMarker can be used by the application for own purposes, e.g. for implementation of a state machine. The possible application value range for the field is 0 to eCOM_OBJECT_MARKER_USER_END.

Event handling

The SDO/USDO module provides three event handlers which are called on different conditions.

Event

calls function

Communication success

ComObjectEventReady()

Communication abort, client or server

ComObjectEventReady()

Communication abort, timeout

ComObjectEventTimeout()

Communication progress (Segmented/Block)

ComObjectEventProgress()

The code located in the file com_user.c for these event handlers provides an example and has to be adopted to the application.

void ComObjectEventReady(uint8_t ubNetV, uint8_t ubNodeIdV, CoObject_ts * ptsCoObjV, uint32_t ulAbortV)
{
(void) ulAbortV;
if (ptsCoObjV != (CoObject_ts *) 0L)
{
switch (ptsCoObjV->ubMarker)
{
ComDemoAppConsoleLog(ComDemoNodeInfoString(ubNetV, ubNodeIdV));
ComNodeSetHbProdTime(ubNetV, ubNodeIdV, 500);
ComNmtSetHbConsTime(ubNetV, ubNodeIdV, 1000);
break;
ComDemoNmtConfigurationDone(ubNetV, ubNodeIdV);
break;
default:
break;
}
}
}
void ComDemoAppConsoleLog(const char *szMessageV)
ComStatus_tv ComNmtSetHbConsTime(uint8_t ubNetV, uint8_t ubNodeIdV, uint16_t uwTimeV)
Set consumer heartbeat time.
ComStatus_tv ComNodeSetHbProdTime(uint8_t ubNetV, uint8_t ubNodeIdV, uint16_t uwHeartbeatV)
void ComObjectEventReady(uint8_t ubNetV, uint8_t ubNodeIdV, CoObject_ts *ptsCoObjV, uint32_t ulAbortV)
@ eCOM_OBJECT_MARKER_NODE_GET_INFO
Definition com_object.h:77
@ eCOM_OBJECT_MARKER_NODE_SET_HEARTBEAT
Definition com_object.h:80
Object structure.
Definition com_object.h:122
uint8_t ubMarker
Definition com_object.h:131

Timeout event

The communication timeout between SDO / USDO client request and SDO / USDO server response is device / application specific. The initial SDO / USDO communication timeout for the client is set to 50 milliseconds. The connection timeout value can be changed by means of the ComSdoSetTimeout() function.

In case of a communication timeout the protocol stack will call the ComObjectEventTimeout() handler. The code of the ComObjectEventTimeout() handler provides an example and has to be adopted to the application. It is located inside the com_user.c file.

void ComObjectEventTimeout(uint8_t ubNetV, uint8_t ubNodeIdV, CoObject_ts * ptsCoObjV)
{
if (ubNetV == eCOM_NET_1)
{
if (ubNodeIdV == 1)
{
if( (ptsCoObjV->uwIndex == 0x2000) && (ptsCoObjV->ubSubIndex) == 1 )
{
// time-out on this object
}
}
}
ComDemoNmtConfigurationDone(ubNetV, ubNodeIdV);
}
@ eCOM_NET_1
Definition com_defs.h:746
void ComObjectEventTimeout(uint8_t ubNetV, uint8_t ubNodeIdV, CoObject_ts *ptsCoObjV)
uint16_t uwIndex
Definition com_object.h:125
uint8_t ubSubIndex
Definition com_object.h:128

In addition, the protocol stack will transmit a SDO / USDO abort message with an appropriate abort code.

CANopen CC timeout

Time-stamp ID Format DLC Data Comment
------------ ---- ------ --- ------------------------ ----------------------------
192247.15644 601 CBFF 8 40 00 10 00 00 00 00 00 Read index 1000:00h
192247.65746 601 CBFF 8 80 00 10 00 00 00 04 05 SDO abort, timeout

CANopen FD timeout

Time-stamp ID Format DLC Data Comment
------------ ---- ------ --- ------------------------ ----------------------------
192573.18166 67F FBFF 6 01 11 01 01 00 10 Read index 1000:01h
192573.68268 67F FBFF 7 01 7F 01 01 00 10 12 USDO abort, timeout

Code examples

Code examples for accessing entries of a device object dictionary are located in the file source/application/examples-com/com_demo_sdo.c.

Object read operation

The demo function ComDemoSdoObjectRead() reads data from the following object dictionary entries:

Index / Sub-Index Name Local variable
1000:00h device type ulIdx1000G
1001:00h error register ubIdx1001G
1008:00h manufacturer device name szIdx1008G[]
1017:00h producer heartbeat time uwIdx1017G
1018:01h Identity Object, vendor-ID ulIdx1018_1G

The array atsObjDictReadG holds the data elements to be read. Each entry has a pointer to an individual data storage location. Please note that the string size for the manufacturer device name (1008:00h) is limited to 32 byte. In case the manufacturer device name of the CANopen device exceeds this limit the data transfer will be aborted.

CoObject_ts atsObjDictReadG[] = {
{ 0x1000, 0x00, 0x00, 4, eCO_DT_UNSIGNED32, &ulIdx1000G },
{ 0x1001, 0x00, 0x00, 1, eCO_DT_UNSIGNED8, &ubIdx1001G },
{ 0x1008, 0x00, 0x00, 32, eCO_DT_VISIBLE_STRING, &szIdx1008G },
{ 0x1017, 0x00, 0x00, 2, eCO_DT_UNSIGNED16, &uwIdx1017G },
{ 0x1018, 0x01, 0x00, 4, eCO_DT_UNSIGNED32, &ulIdx1018_1G }
};
@ eCO_DT_UNSIGNED16
Definition canopen.h:881
@ eCO_DT_UNSIGNED8
Definition canopen.h:876
@ eCO_DT_UNSIGNED32
Definition canopen.h:886
@ eCO_DT_VISIBLE_STRING
Definition canopen.h:896
ComStatus_tv ComDemoSdoObjectRead(uint8_t ubNetV, uint8_t ubNodeIdV)
{
ComStatus_tv tvStatusT;
uint8_t ubSdoClientT;
ubSdoClientT = ComSdoGetClient(ubNetV);
ulObjCntG = sizeof(atsObjDictReadG) / sizeof (CoObject_ts);
tvStatusT = ComSdoReadObject( ubNetV, ubSdoClientT, ubNodeIdV, &atsObjDictReadG[0], &ulObjCntG);
return(tvStatusT);
}
int32_t ComStatus_tv
Function return value.
Definition com_defs.h:127
uint8_t ComSdoGetClient(uint8_t ubNetV)
ComStatus_tv ComSdoReadObject(uint8_t ubNetV, uint8_t ubClientV, uint8_t ubNodeIdV, CoObject_ts *ptsCoObjV, uint32_t *pulObjCntV)

In case of a timeout condition, the handler ComObjectEventTimeout() will be called. On success or in case of an communication abort the handler ComObjectEventReady() will be called.

Object write operation

The demo function ComDemoSdoObjectWrite() writes data to the following object dictionary entries:

Index / Sub-Index Name Local variable
1017:00h producer heartbeat time uwIdx1017G
1400:01h RPDO1, identifier ulIdx1400_1G
1400:02h RPDO1, transmission type ubIdx1400_2G
1800:01h TPDO1, identifier ulIdx1800_1G
1800:02h TPDO1, transmission type ubIdx1800_2G
1800:05h TPDO1, event timer uwIdx1800_5G

The array atsObjDictWriteG holds the data elements to be written. Each entry has a pointer to an individual data storage location. The values for each variable are set in the beginning of ComDemoSdoObjectWrite().

CoObject_ts atsObjDictWriteG[] = {
{ 0x1017, 0x00, 0x00, 2, eCO_DT_UNSIGNED16, &uwIdx1017G },
{ 0x1400, 0x01, 0x00, 4, eCO_DT_UNSIGNED32, &ulIdx1400_1G },
{ 0x1400, 0x02, 0x00, 1, eCO_DT_UNSIGNED8, &ubIdx1400_2G },
{ 0x1800, 0x01, 0x00, 4, eCO_DT_UNSIGNED32, &ulIdx1800_1G },
{ 0x1800, 0x02, 0x00, 1, eCO_DT_UNSIGNED8, &ubIdx1800_2G },
{ 0x1800, 0x05, 0x00, 2, eCO_DT_UNSIGNED16, &uwIdx1800_5G }
};
ComStatus_tv ComDemoSdoObjectWrite(uint8_t ubNetV, uint8_t ubNodeIdV)
{
ComStatus_tv tvStatusT;
uwIdx1017G = 500; // set heartbeat value to 500 ms
ulIdx1400_1G = 0x211; // set RPDO identifier value to 211h
ubIdx1400_2G = 0xFF; // set RPDO transmission type to FFh (event)
ulIdx1800_1G = 0x191; // set TPDO identifier value to 191h
ubIdx1800_2G = 0xFF; // set TPDO transmission type to FFh (event)
uwIdx1800_5G = 100;; // set TPDO event timer to 100 ms
ulObjCntG = sizeof(atsObjDictWriteG) / sizeof (CoObject_ts);
tvStatusT = ComSdoWriteObject( ubNetV, 0, ubNodeIdV, &atsObjDictWriteG[0], &ulObjCntG);
return(tvStatusT);
}
ComStatus_tv ComSdoWriteObject(uint8_t ubNetV, uint8_t ubClientV, uint8_t ubNodeIdV, CoObject_ts *ptsCoObjV, uint32_t *pulObjCntV)