Using the CANopen Library

Service definition interface

All CANopen services the application needs must be defined before they can be used. Therefore definition functions are available for each service. These definition functions setup the service parameters to their default values.

The name of the functions for the definition interface always starts with the prefix "define" followed by an abbreviation of the service object e.g. definePdo().

If the function returns the value "success" (return value: CO_OK), then the created service can be used by the application.

Figure 18 illustrates the naming scheme for functions that use CANopen services.

Figure 18: naming scheme of CANopen Library interface functions

Service request interface

In order to be able to use CANopen service functions, request functions are available. The function name consists of three sections. The first word of the service request name is the abbreviation of the CANopen service object (read, write, start ...). The second word is the kind of the CANopen service (PDO, SDO, SYNC ...) and finally the abbreviation of the word request "Req", e.g. writePdoReq().

There are two kinds of request functions:

  • The first kind of requests directly execute the request in the user application. These are all the requests, which can be completely executed immediately by the CANopen layer, e.g. startSyncReq() or writePdoReq().

  • The second kind of requests result in a response or confirmation from another node in the CANopen network. Here the request will start a more complex set of messages, e.g. readSdoReq() or readPdoReq(), because an interaction with another node in the CANopen network is necessary for it to complete. The application can determine the completion of the request, e.g. the reception of a response, using the confirmation functions.

Error free return from the request functions (CO_OK) means that the statement was executed error free up to putting created CAN messages into the CAN transmit buffer.

The successful transmission of a CAN message is the job of the CAN driver (not of the request function) and depends, amongst other things, on the current CAN bus load.

Service indication/confirmation interface

On reception of certain CAN messages, error conditions (e.g. a Heartbeat message is missing, a Timeout occurred) and other events (e.g. a completed request) the user is informed by the CANopen Library by indication or confirmation functions also referred to as callback‑functions.

The confirmation is an answer to a confirmed service request (e.g. SDO). All other events are so-called indications. Function names that are CANopen service indications and confirmations are appended with "Ind" e.g. pdoInd() as the abbreviation for indication and "Con" e.g. sdoRdCon() as abbreviation for confirmation. The prefixes of the indication and confirmation functions have the same meaning as in the request interface description.

The receive principle for the service indication/confirmation is shown in Figure 19.

Figure 19: indication / confirmation interface

It is possible to define an error handling for interrupted SDO transfer (Abort-DomainTransfer-Service), for guarding indications (lost guarding, start/failed Heartbeat, boot-up message), for an emergency message reception or for errors received from the CAN controller (driver).

All user interface functions have been defined in the modules usr_301.c, usr_302.c, usr_303.c, usr_304.c, usr_305.c and nmtslave.c. The file names are derived from the corresponding CANopen standards, e.g. usr_301.c relates to standard CiA-301. However, only the function calls are defined in the provided template modules. The template modules are located in the CANopen Library delivery in <installation_directory>\examples\templates. The behavior of the indication or confirmation functions must be filled in by the application programmer.

When a user interface function is called, a message was received or an event has occurred. The corresponding values in the object dictionary have been updated before the call. Some of the functions require certain conditions to be met. These conditions are described in the following chapters.

Node-ID setup

Many of the CANopen service functions use pre-defined COB-identifiers for communication. These pre-defined COB-identifiers are determined on the basis of the device node-ID. For higher flexibility the CANopen Library uses a function to determine the node-ID.

Within the function getNodeId(), located in usr_301.c,  the user can determine the node-ID, e.g. by reading out some DIP switches, and then transfer it to the CANopen Library. It calls this function once from initCANopen() and once from the resetCommInd() function.

CANopen timer usage

The CANopen Library uses an internal timer concept that can also be used for application-specific purposes. As a basis a hardware timer is used. It is included by the driver and increments a variable in a predefined interval. This interval is called timer tick and is the smallest resolution of timer dependent processes. All timer dependent processes of the CANopen Library can only be executed in multiples of timer ticks. Timer ticks are counted normally in an UNSIGNED16 variable. If the define CONFIG_LARGE_TIMER is set, timer ticks are counted in an UNSIGNED32 variable. Therefore the maximum value of a timer event is FFFFh * length or FFFFFFFFh * length of a timer interval.

The timer itself does not need any additional memory. Therefore any desired number of timer processes can be started. For every function that needs a timer a static timer structure has to be provided by the calling function. All timer structures are administered in a linked and sorted list. This makes it possible that even with many timers there is no loss in execution time. Further it is possible to use the timer as a cyclic timer. The following functions provide the programming interface to the CANopen timer:

function

description

addTimerEvent()

add a timer event to the timer list

removeTimerEvent()

delete a timer event from the timer list

changeTimerEvent()

modify an active timer event

checkActiveTimer()

check for an active timer

userTimerEvent()

user indication - timer has been finished

Table 23: timer functions of the CANopen Library

By using the function addTimerEvent() the new timer is added. When the timer is elapsed the indication function userTimerEvent() is called. In this function the user can specify further actions. When the timer has to be switched off before time is up, removeTimerEvent() can be used. All timer functions expect as a first parameter a pointer to the data structure of the timer. This structure has to be provided as static data from the calling function. The structures are modified by the timer functions. Therefore the user program itself must not alter the data of the static timer structures.

The second parameter specifies the timer interval in 1/10 of msec. And the third parameter is the timer type. For application-specific timers it shall be set to CO_TIMER_TYPE_USERSPEC. For cyclic timers additional the attribute CO_TIMER_TYPE_CYCLIC has to be set.

Example of the usage of a timer:

TIMER_EVENT_T myTimer;  /* define timer struct */ /* add a cyclic timer for 1 sec */ addTimerEvent(&myTimer, 10000, \     (CO_TIMER_TYPE_USERSPEC | CO_TIMER_TYPE_CYCLIC)); ... void userTimerEvent(TIMER_EVENT_T *pTimer) {     if (pTimer == &myTimer)     {         /* start my reaction */     } }

Listing 1: example for timer usage

SDO usage

SDO transfers are peer-to-peer connections between two nodes - a server node and a client node. The client is using SDO read or write requests to access object dictionary of the server. SDO transfers are confirmed services and therefore 2 COB-IDs are necessary for each connection, one for the request, one for the response. Each node can have many SDO connections and can be a server, client or both at the same time.

There are three different transfer modes possible: Expedited Transfer, Segmented Transfer and Block Transfer. The CANopen Library automatically selects the best mode for each transfer.

If a node wants to permit access to its own object dictionary, it has to provide at least one server SDO connection, i.e. by creating an SDO communication object using the defineSdo() function call, or more than one if more clients shall have concurrent access to its object dictionary. If a node wants to access the object dictionary of other nodes it has to initialize a client SDO for each node it wants to connect to, also using the defineSdo() function call.

All SDO communication services have to be initialized by the function defineSdo().

Except the first server SDO, all SDOs are marked as invalid after the initialization. Only the COB-IDs for the first server SDO are initialized with the default COB-ID on the basis of the node-ID (see pre-defined connection set). The COB-IDs for the other SDOs shall be set and validated using the function setCobId(), see Listing 2.

/* create SDO server service 1, this service has to use a standardized COB-ID */ defineSdo(1, SERVER); /* create SDO client service 1 to device with the node-ID 2 */ defineSdo(1, CLIENT); /* configure COB-IDs for the SDO client service 1 */ /* for SDO request from SDO client to SDO server */ cobId = 0x600 + 2; setCobId(0x1280, 1, cobId); /* for SDO response from SDO server to SDO client */ cobId = 0x580 + 2; setCobId(0x1280, 2, cobId);

Listing 2: example for defining SDOs and setup COB-IDs

SDO server

The SDO server permits access to the owned object dictionary to other nodes via the CANopen network. For the access to the three mandatory objects in the object dictionary every CANopen node must have at least one server SDO object. Only the first server SDO is available immediately after the initialization. If more server SDOs shall be used the COB-IDs for those SDOs have to be configured (Listing 2).

All attempts of a read or write access from a remote node to the owned object dictionary are indicated by the sdoRdInd() and sdoWrInd() functions.

A read access from any other node in the network to the owned object dictionary is indicated by the function sdoRdInd(). In this function the application can update the requested value (the object dictionary entry addressed by index and sub-index) before the CANopen Library sends back the response message to the client. If the indication function sdoRdInd() returns an error, an SDO abort transfer will be generated and sent back to the originator (the read service requester).

Error codes are generated automatically by the CANopen Library, see appendix.

/*************************************************************** sdoRdInd - indicates the occurrence of an SDO read access * \retval CO_OK success \retval CO_E_xxx error */ RET_T sdoRdInd(     UNSIGNED16 index,       /**< [in] index of object */     UNSIGNED8 subIndex      /**< [in] sub-index of object */     CO_COMMA_LINE_PARA_DECL /**< [in] additional parameter */     ) { RET_T coRetVal;       /* CANopen Library return value */    coRetVal = CO_OK;    if (0x2000 == index)    {        /* increment application-specific counter */        actual_u32++;     }    return (coRetVal); }

Listing 3: example for SDO read indication

A write access to the owned object dictionary is indicated by the function sdoWrInd(), see Figure 20.

Figure 20: flow chart for SDO write indication

First the write permission flag and the value limits are tested by the CANopen Library. If the value is within the limit range the user can run additional tests on the value by the function testSdoValue(), before it is written into the object dictionary. These tests can be necessary if the application uses the corresponding variable for a second task or an interrupt service routine or for data with size greater than 4 bytes. For variables with size of max. 4 bytes (e.g. UNSIGNED8-UNSIGNED32, INTEGER8-INTEGER32, REAL32 values) the old value is stored before the new value is written into the object dictionary and the function sdoWriteInd() is called. In the case of an error return value from sdoWriteInd() the old value is restored.

Listing 4: example for SDO write indication

SDO client

The SDO client initiates all SDO transfers. For each SDO client connection an SDO communication object has to be initialized. After the initialization all client SDOs are disabled by default. To enable these SDOs the COB-IDs must be set according to the server’s COB-IDs - with setCobId(), see Listing 2.

Read and write access to the object dictionary of another node is started with readSdoReq() and writeSdoReq(). Parameters for the function calls are the SDO number, index and sub-index in the object dictionary of the SDO server and a data buffer for transmission data. The application has to ensure that the data buffer is large enough for all data which are to be transferred.

An error free return value from the request functions does not necessarily mean a successful transmission. It means only that the transfer was successfully initiated by saving the first data into the transmit message buffer. The application is informed about the termination of the transfer through the functions sdoWrCon() and sdoRdCon(). If an error occurs these functions can evaluate the error reason.

Listing 5: example for SDO write confirmation

If an SDO server does not respond to the request from the SDO client within a determined period of time the SDO client can abort the transfer with an SDO abort transfer protocol. This is done automatically by the CANopen Library when the time, given by writeSdoReq() or readSdoReq(), is up. The application is informed by the indication function sdoRdCon() or sdoWrCon() about this event.

SDO communication up to four bytes can be transmitted by so-called expedited transfer. This means, all data can be passed in one CAN message. For larger data the segmented transfer has to be used. The CANopen Library automatically forces the correct transfer type by checking the requested byte count.

Domain upload and download

A domain in CANopen is unstructured data, which can have a size up to 232 - 1 bytes. Domains can be whole application programs or large data structures, e.g. pictures. The application is responsible for the interpretation of the domain content.

Domains can only be transferred by SDO. In order to handle such large data some exceptions to the common CANopen objects are necessary. All objects with domain entries have the type DOMAIN_T. This type is a pointer to void. The pointer must be initialized by:

  • the Industrial Communication Creator by the Default Value and Size of the object or

  • the application by calling the functions setDomainAddr() and setDomainSize() during runtime, see Listing 6

Listing 6: domain initialization

The functions for manipulating the domain start address and the domain size are useful for building ring buffers and other segmented buffer structures e.g. for drive interpolation data. Further certain segments of a domain can be uploaded e.g. for program debugging. The functions for manipulating are completed by appropriate getter functions:

  • getDomainAddr() and

  • getDomainSize()

Domain transfers can be started with the SDO functions writeSdoReq() or readSdoReq(). After the transfer is finished, the normal indication functions sdoRdInd() and sdoWrInd() will be called, respectively. In some applications an additional indication function after a defined block of transferred data is necessary, because the receive buffer is not large enough or the data shall be flashed into a ROM area. The CANopen Library can handle this for the SDO client and the SDO server for upload and download transfers.

All SDO transfers are initialized by the SDO client, so the SDO server is always the passive part. Therefore the indication size for the SDO server must be setup at compile time. It can be done by the Industrial Communication Creator. If the configured data size is elapsed, the indication function sdoDomainInd() is called. Here the application can save or flash the received data. After that, the receive buffer will be cleared and the next data will be received until the next border of the configured data size is reached. Then the indication function is called again.

Listing 7: example for sdoDomainInd()

The SDO client can define the size for the confirmation individually for each transfer by starting a domain transfer using the function writeSdoDomainReq() or readSdoDomainReq(). If the given confirmation size is reached, the corresponding indication function sdoDomainRdCon() or sdoDomainWrCon() is called, before the next CAN message is transferred. At the end of the transfer, the normal indication functions sdoRdCon() or sdoWrCon() is called.

For program and firmware download CANopen defines the objects 1F50h for the program download and the object 1F51h for program control.

SDO block transfer

SDO transfers are based on the client-server model with a confirmation after each transfer. For a larger block of data this will take a large amount of time. Therefore the protocol SDO block transfer has been defined.

Using the SDO block transfer a sequence of blocks can be transmitted without a large overhead of confirmation each 8 bytes. Each block is a sequence of up to 127 segments (e.g. CAN messages) containing only a sequence number and the data.

Each SDO block transfer starts with an initialization phase, where the SDO server and the SDO client can prepare themselves for transferring the blocks and negotiating the number of segments in one block.

There is a finalization phase after transferring the blocks, where the SDO client and SDO server can optionally verify the correctness of the previous data transfer by comparing checksums derived from the data set.

For the SDO block transfer a Go-Back-n ARQ (Automatic Repeat Request) scheme is used to confirm each block.

If the SDO server does not support SDO block transfer the SDO client automatically falls back to the SDO segmented transfer.

There are no other programming interface or indication functions to use the CANopen Library with SDO block transfer. Instead SDO block transfers are automatically used for the SDO server and for SDO client if the data to be transferred is greater than or equal to the compiler-define

#define CONFIG_BLOCK_MIN_DATASIZE

This compiler-define can be set by the Industrial Communication Creator.

For all transfers the SDO client has to initiate the connection to the SDO server. If the SDO server does not support SDO block transfer the transfer is repeated automatically with segmented transfer. In this case the user is not informed.

During the initialization phase the block size and the usage of CRC checksum are negotiated. Therefore the defines CONFIG_BLOCK_CRC and CONFIG_BLOCK_MAX_CNT are provided if the CANopen device shall support this feature. If CONFIG_BLOCK_CRC is set, the SDO client will try to use the CRC generation for transfers. The maximum segment for one block can be set with the define CONFIG_BLOCK_MAX_CNT.

If the SDO server does not support CRC generation or only supports smaller block sizes the values from the SDO server are used.

All values for SDO block transfer can be set with the Industrial Communication Creator.

SDO abort codes

The SDO Abort Transfer is a negative conformation of a SDO request. This service contains a code, which specifies the kind of the abort. The CANopen Library by port supports the following SDO abort codes:

SDO abort code

CANopen Library return value

description

05030000h

CO_E_SDO_INVALID_TOGGLEBIT

Toggle bit in the SDO upload segment protocol not alternated.

05040000h

CO_E_SDO_TIMEOUT

SDO protocol timed out.

05040001h

CO_E_CMD_SPEC_INVALID

The CANopen Library has occurred an unexpected or unknown command specifier in the SDO protocol.

05040002h

CO_E_SDO_INVALID_BLKSIZE

The block size in the SDO block transfer protocol is invalid. The block size must be in the range: 0 < blksize < 128

according to CiA-301.

05040004h

CO_E_SDO_INVALID_BLKCRC

CRC error occurred during SDO block transfer,

05040005h

CO_E_MEM

There is not enough memory available for a CANopen service. Maybe the resources for the CANopen service are not installed in the Industrial Communication Creator.

06010000h

CO_E_NO_ACCESS

The access to an object fails.

06010001h

CO_E_NO_READ_PERM

Attempt to read a write-only object.

06010002h

CO_E_NO_WRITE_PERM

Attempt to write a read-only object.

06020000h

CO_E_NONEXIST_OBJECT

Object does not exist in the object dictionary.

06040041h

CO_E_MAP

Object can not be mapped to the PDO.

06040042h

CO_E_DATA_LENGTH

The number and length of the objects to be mapped exceeds the PDO length.

06040043h

CO_E_PARA_INCOMP

There is a general parameter incompatibility reason.

06040047h

CO_E_INTERNAL_INCOMP

There is a general internal incompatibility in the device.

06060000h

CO_E_HARDWARE_FAULT

Access failed due to an hardware error.

06070010h

CO_E_WRONG_SIZE

Data type does not match , length of service parameter does not match.

06070012h

CO_E_SIZE_TOO_HIGH

Data type does not match, length of service parameter too high.

06070013h

CO_E_SIZE_TOO_LOW

Data type does not match, length of service parameter too low.

06090011h

CO_E_NONEXIST_SUBINDEX

Sub-index does not exist.

06090030h

CO_E_TRANS_TYPE

Value range of parameter exceeded (only for write access).

06090031h

CO_E_VALUE_TO_HIGH

Value of parameter written too high.

06090032h

CO_E_VALUE_TO_LOW

Value of parameter written too low.

06090036h

CO_E_LIMIT_ORDER

Maximum value is less than minimum value.

060A0023h

CO_E_SRD_NO_RESSOURCE

There is no resource available for a new SDO connection.

08000000h

CO_E_SDO_OTHER

There is a general error.

08000020h

CO_E_INVALID_TRANSMODE

Data can not be transferred or stored to the application.

08000021h

CO_E_LOCAL_CONTROL

Data can not be transferred or stored to the application because local control.

08000022h

CO_E_DEVICE_STATE

Data can not be transferred or stored to the application because of the present device state.

08000023h

CO_E_DICTIONARY

Object dictionary dynamic generation fails for or no object dictionary is present, e.g. object dictionary is generated from file and generation fails because of an file error.

08000024h

CO_E_NO_DATA_AVAILABLE

No data available.

Table 24: SDO abort codes

PDO usage

PDOs are used to transfer real-time data without overhead. The PDO service is briefly described in chapter 2.3.

Initialization

Before usage all PDOs must be defined. A maximum of 512 Receive PDOs and 512 Transmit PDOs with a maximum PDO mapping of 64 entries for each direction are possible. Initialization is done with the function definePdo().

Listing 8: example for PDO definition

During the initialization of the CANopen Library a Reset Communication is executed and all entries of the object dictionary are set to their default values. For the first 4 Receive PDOs and the first 4 Transmit PDOs the default values for the COB-IDs are calculated according to the Pre-defined Connection Set and the actual node-ID. The new COB-IDs are entered into the object dictionary, independently of the default values of the object dictionary generated by the Industrial Communication Creator.

For fast access at run time all PDO data and the addresses of the PDO mapping variables are stored in internal administrative structures.

Configuration

PDO configuration can be done local or via the CANopen network.

PDO communication and mapping parameters must have the access right read-write for the configuration during run-time using SDO via the CANopen network. For dynamic PDO mapping the PDO mapping parameters have the access right read-write. The PDO mapping parameters are constant for static PDO mapping. The local configuration does not require special access rights.

For additional PDO mapping entries the memory must be reserved during compiling, i.e. the maximal number of PDO mapping entries must be created for the PDO in the Industrial Communication Creator.

The configuration has to be done according to the following standardized procedure:

  1. set bit 31 of the COB-ID sub-object to disable the PDO service (mandatory)

  2. configure the PDO communication parameter sub-objects (optional)

The conditions for the configuration are:

  • The sub-object is supported.

  • The sub-object has the access right writeable.

  • The new value is allowed for this PDO.

  1. set the number for valid mapping entries in the PDO mapping parameter object, sub-index 0 to 0 in order to disable the PDO mapping (mandatory for PDO mapping configuration)

  2. configure the PDO mapping in the PDO mapping parameter object, sub-index 1-64 (optional)

The condition for the configuration is:

  • It must be allowed to map the object into the PDO.

  1. set the number for valid mapping entries in the PDO mapping parameter object, sub-index 0 to the desired number of valid PDO mapping entries in order to enable the PDO mapping (mandatory for PDO mapping configuration)

  2. reset bit 31 of the COB-ID sub-object to enable the PDO service (mandatory)

Only for the COB-ID (sub-index 1 of the PDO communication parameter object) and the inhibit time (sub-index 3 of the PDO communication parameter object) it is required that the PDO must be disabled for configuration.

Listing 9: example for COB-ID configuration of TPDO1

Listing 10: example for the configuration of PDO inhibit time local for TPDO1

For all local modifications of the communication parameters in the object dictionary the function setCommPar() has to be called in order to update the internal structures. Changes via the CANopen network using SDO and the function setCobId() automatically update the internal structures.

Listing 11: example for configuration of the PDO mapping for RPDO1

The PDO mapping can take place bit-wise or byte-wise. The bit-wise PDO mapping is necessary for variables unequal to 8, 16 or 32 bit (i.e. bit variables) and without holes at the CAN transmission. If variables are to be mapped bit-wise, the compiler-define CONFIG_BIT_ENCODING must be set. This requires, however, larger code blocks and a longer processing time for PDO than the byte-wise PDO mapping.

PDO producer

PDO request

Transmitting asynchronous PDOs is done using the function writePdoReq(). Only the PDO number is given as function argument. The CANopen Library automatically composes the transmit buffer by saving the mapped data at the transmit buffer. Asynchronous PDOs are transmitted immediately, synchronous PDOs are stored and transmitted after the next applicable SYNC message, RTR-only PDOs are also stored and transmitted after the next RTR request.

Listing 12: example for PDO transmission request

A positive return value of the function writePdoReq() does not mean that the PDO message was sent successfully. It means only that a successful entry into the transmit buffer of the CANopen Library was done. In the case of errors, e.g. node not in state NMT/OPERATIONAL, the function returns with the appropriate error code and does not transmit the data. For the return value CO_E_INHIBITED caused by a running PDO inhibit timer the CANopen Library provides a special handling described in chapter 4.7.3.2.

PDO inhibit time

PDOs are transmitted with high priority. To avoid blocking of the CAN communication by high priority PDOs a PDO inhibit time parameter can be defined. The PDO inhibit time is a minimum time between two consecutive transmissions of this PDO. If the PDO inhibit time has not elapsed yet, the function writePdoReq() returns an error code. The application can try to send it later if the PDO inhibit time is elapsed.

Listing 13: example for waiting on ending of PDO inhibit time

Please consider that the waiting on ending of the PDO inhibit time does not block other processes. The PDO inhibit time can be set via the CANopen network by a configuration tool and is therefore not determined by the application. The PDO inhibit time can last more than 6 s as maximum.

For TPDOs with the PDO transmission type RTR-only event-driver (253), asynchronous manufacturer-specific (254) and asynchronous profile-specific (255) it is possible, that the CANopen Library transmits the TPDO if the PDO inhibit time is elapsed automatically. This functionality has to be activated by the compiler-define CO_CONFIG_PDO_INHIBITTIME_RESEND by the Industrial Communication Creator.

The indication function coUserPdoInhibitTimeInd() is called before the TPDO is transmitted and allows the application to decide for each individual PDO whether it shall be transmitted.  The transmission of the TPDO depends on the return value of the indication function, see Figure 21.

The indication function coUserPdoInhibitTimeInd() requires the compiler-define CO_CONFIG_PDO_INHIBITTIME_RESEND  and has to be activated by the compiler-define CO_CONFIG_PDO_INHIBITTIME_INDICATION by the Industrial Communication Creator.

Figure 21: automatic retransmission of TPDOs after PDO inhibit time is elapsed

PDO event time

If the SYNC period is too small or there is no SYNC in the network, PDO can also be sent time driven by specifying an event timer. The event timer can be used for asynchronous PDO only. If the entry for the event timer is greater than zero the PDO is transmitted cyclically with this rate. Before the PDO is transmitted, the indication function pdoEventTimerInd() is called. The application can update the value in the object dictionary before the data are filled into the transmit buffer.

Please note that the PDO inhibit time shall be smaller than the PDO event time according to CiA-301. If this requirement is not fulfilled the behavior of the CANopen Library can be configured about the compiler-define CO_CONFIG_PDO_INHIBITTIME_RESEND.

#define CO_CONFIG_PDO_INHIBITTIME_RESEND:

The CANopen Library transmits the TPDO after the TPDO event time and the PDO inhibit time is elapsed.

#undef CO_CONFIG_PDO_INHIBITTIME_RESEND:

The CANopen Library ignores the transmission request after the PDO event time is elapsed during the PDO inhibit timer is still running. The TPDO will be sent by the next request from the TPDO event timer after the PDO inhibit time is elapsed.

The compiler-define can be configured by the Industrial Communication Creator.

PDO request via RTR

PDOs can be requested by other nodes via RTR. This request is handled by the CANopen Library. Before the transmit data are generated, the indication function rtrPdoInd() can be used to update the data at the object dictionary.

PDO consumer

PDO indication

The reception of PDOs is indicated with the function pdoInd(). All mapped data for this PDO are written to the object dictionary before this function is called. The behavior of the CANopen Library for the receipt of a PDO message with a wrong number of bytes is described in chapter 4.7.4.2.

The call of an application function can depend on the mapped objects. The current address of the mapped object can be queried by the function getMapObjAddr(). This is useful for dynamic PDO mapping. An example is given in Listing 14.

Listing 14: example for PDO indication

PDO with wrong length

If the received PDO contains too less bytes, the CANopen Library ignores the received data. If the received PDO contains too much byte, the CANopen Library saves the received data into the objects and ignores the excess bytes.

The application can be informed about this error event by the indication function pdoLenInd(). The call of the function is activated by the compiler-define CONFIG_PDO_BAD_LEN_INDICATION. The return value of the indication function pdoLenInd() determines the behavior of the CANopen Library, see Figure 22.

Figure 22: user interface for RPDOs with wrong length

The CANopen Library does not transmit an EMCY message with the error code 8210h or 8220h automatically.

PDO event time

For Receive PDOs the event timer can also be used. If the event timer is unequal zero it is restarted every time a PDO was received. If the timer is up the indication pdoTimerInd() is called. The application can now request the PDO.

PDO request via RTR

The PDO consumer can request the transmission of a PDO message from the PDO producer via RTR by calling the function readPdoReq().

MPDO usage

If the application has a lot of data with the same properties a special PDO type called a Multiplexed PDO (MPDO) can be used. MPDOs transmit with every CAN message the index and the sub-index of the given data. Therefore the maximum data length is only 4 bytes. The transmitted index and sub-index can be the index and the sub-index of the producers object dictionary (MPDO Source Addressing Mode) or the index and the sub-index of the consumers object dictionary (MPDO Destination Addressing Mode).

The CANopen Library uses the same functions for both modes. The initialization is done with the default PDO initialization function definePdo(). If dynamic mapping is used and a PDO is defined as a MPDO by the function definePdo() it cannot be (re-)configured as a normal PDO.

For writing MPDOs the function writeMPdoReq() has to be used. For the MPDO destination addressing mode the parameter node is not necessary and shall be 0.

If an MPDO is received the indication function mpdoInd() is called. It works just as the pdoInd() function.

The usage of MPDOs allows the transmission of several homogeneous PDOs with a minimum of mapping and communication parameter entries in the object dictionary. Since the mapping is not constant, a longer processing time is necessary for creating or analyzing the CAN messages.

Destination address mode

Figure 23: MPDO structure for destination address mode

In destination address mode index and sub-index refer to the consumer. This allows access to the consumers’ object dictionary in an SDO-like manner. When the destination node is 0 it allows a broadcasting to write into the object dictionary of more than one node simultaneously without sending a PDO for each single node.

MPDO producer

The MPDO producer in destination address mode requires the following entries in the object dictionary:

index

sub-index

description

value

18xxh

 

PDO communication parameters

 

1Axxh

0

number of PDO mapping entries

255

1Axxh

1

PDO mapping entry

manufacturer-specific

Table 25: objects for a MPDO producer in destination address mode

Transmitting MPDOs in destination address mode is done using the function writeMPdoReq().

MPDO consumer

The MPDO consumer in destination address mode requires the following entries in the object dictionary:

index

sub-index

description

value

14xxh

 

PDO communication parameters

 

16xxh

0

number of PDO mapping entries

255

Table 26: objects for a MPDO consumer in destination address mode

If a MPDO was received, the data will have been written into the received index and sub-index.

Source address mode

Figure 24: MPDO structure for source addess mode

In source address mode index and sub-index refer to the producer. The transmission type has to be either 254 or 255.

MPDO producer

The MPDO producer in source address mode requires the following entries in the object dictionary:

index

sub-index

description

value

18xxh

 

PDO communication parameters

 

18xxh

2

PDO transmission type

254 or 255

1Axxh

0

number of PDO mapping entries

254

1FA0h – 1FCFh

0 - 254

object scanner list

 

Table 27: objects for a MPDO producer in source address mode

The MPDO producer uses an object scanner list to configure which objects have to be sent.

Each scanner list entry has the following format:

MSB

 

LSB

bit 31 – 24

bit 23 – 8

bit 7 – 0

block size

index

sub-index

Table 28: structure of scanner list entry

Each scanner list entry describes an object that can be sent via MPDO. It is possible to describe consecutive sub-indices by setting the parameter block size to the number of sub-indices.

Transmitting MPDOs in source address mode is done using the function writeMPdoReq().

Only one MPDO producer of source address mode is allowed for each node.

MPDO consumer

The MPDO consumer in source address mode requires the following entries in the object dictionary:

index

sub-index

description

value

16xxh

0

number of PDO mapping entries

254

1FD0h – 1FFFh

0 – 254

dispatch entry

 

Table 29: objects for a MPDO consumer in source address mode

The MPDO consumer uses an object dispatcher list as a ’cross reference’ between the remote object of the MPDO producer and the local object dictionary.

Each dispatch entry has the following format:

MSB

 

 

 

 

LSB

63 – 56

55 – 40

39 – 32

31 – 16

15 – 8

7 – 0

block size

local index

local sub-index

producer index

producer sub-index

producer node-ID

Table 30: structure of dispatcher list entry

If a MPDO was received, and the node-ID of the producer, index and sub-index match an entry in the dispatcher list, then the data is written into the local object dictionary in the index and sub-index given in this entry.

The parameter "block size" allows the description of consecutive sub-indices to be used.

For example, if sub-index 1-9 of the MPDO producer shall be mapped to sub-index 11-19 of the local node, this range is defined by:

producer sub-index      =          1

local sub-index         =          11

block size        =          9

Non-configured entries shall have the value 0.

EMCY usage

Emergency (EMCY) messages serve for transmitting and receiving error messages. One EMCY producer and up to 127 EMCY consumers can be created in a device. The function defineEmcy() with the appropriate parameter initializes the emergency service for producer or consumer. If the EMCY consumer list in the object dictionary at index 1028h exists then all entries with a valid COB-ID are initialized automatically. If it does not exist the EMCY consumers can be added by the function setEmcyConsumerCobId().

Listing 15: example for EMCY initialization

EMCY messages on the CAN-bus are generated by the function writeEmcyReq(). The function writeEmcyReq() sets the general error bit in object 1001h automatically. If more than the general error bit in object 1001h shall be supported the application has to set the bits before writeEmcyReq() is called.

Listing 16: example for EMCY request

The function writeEmcyReq() automatically generates an entry in object 1003h (pre-defined error field), sets the general error bit at the object 1001h (error register), creates the EMCY message and forces the transmission.

Object 1003h (pre-defined error field) is an array of UNSIGNED32. writeEmcyReq() stores the error code in the two lowest bytes and two bytes of the additional information in the two upper bytes, see Figure 25.

Figure 25: EMCY message and pre-defined error field

Each error is saved in the pre-defined error field at index 1003h sub-index 1. All other already available errors are shifted automatically from one sub-index to the next sub-index. The sub-index 0 of the object 1003h always indicates the number of errors. If the pre-defined error field is full and a new error occurs then the oldest error in the pre-defined error field is cleared automatically. Writing in the sub-index 0 in the pre-defined error field is permitted only with the value 0. Thus all entries in the pre-defined error field are deleted with the help of the function eraseErr(). Resetting the general error bit and the other error-specific bits in object 1001h must reset in the application.

For transmitting EMCY messages an inhibit time can be specified. After each modification of this time the function setCommPar() has to be called in order to update the internal structures.

The reception of EMCY messages from other nodes in the network is indicated by the function emcyInd(). This function makes all data contained in the EMCY message available to the application. Storage of the data does not take place.

Listing 17: EMCY indication

The indication function is called only for EMCY messages, which have a valid COB-ID entry at the object dictionary list or was added by setEmcyConsumerCobId() before.

SYNC usage

The SYNC message serves for synchronous transfer of PDOs and synchronous execution of internal procedures in different nodes of the network. A node can either be the SYNC producer or the SYNC consumer. The type of service must be determined by the initialization of the function defineSync() or by setting the appropriate bit at index 1005h. Additionally, the SYNC communication cycle period has to be set for the SYNC producer in the object dictionary and the internal structures have to be updated with the function setCommPar().

Listing 18: initialization, configuration and start of SYNC service

If the SYNC producer bit is set the SYNC message is transmitted automatically according to the given communication cycle period. With the arrival or the transmission of the SYNC message the synchronous PDOs are assembled and transmitted.

Figure 26: SYNC process

Data that was received with the last SYNC are copied to the object dictionary. For each received PDO the indication function pdoInd() is called similar to the PDOs received asynchronously.

For the synchronization of the different nodes in the network two user functions are available: syncPreCommand() and syncCommand(). The first function is called immediately after the SYNC message was received or transmitted, and the second is called after all functionality for the SYNC process was done, see Figure 26.

Sending of SYNC messages can be started or stopped by setting the appropriate bit for the SYNC producer COB-ID at the object dictionary or by the function startSyncReq() or stopSyncReq().

Error control mechanisms

CANopen defines two error control mechanisms:

  • Heartbeat and

  • Node Guarding.

Each node has to provide at least one service. The Heartbeat service is preferable. Even if both services are implemented guarding has to be done with only one service. Only services that have been initialized can be used, see Listing 19. The initialization is included in the function init_Library() generated by the Industrial Communication Creator.

Listing 19: initialization of error control

Boot-up messages of all devices can be received from a Heartbeat consumer and from a Node Guarding master. It is not necessary to setup guarding service for any special device.

All events for Heartbeat and Node Guarding monitoring are signaled by the indication functions mGuardErrorInd() and those regarding the Node Guarding slave are signaled by sGuardErrorInd().

Heartbeat

The Heartbeat service allows each node to monitor every other node in the network. Each Heartbeat producer transmits cyclically its own Heartbeat. The monitoring can now take place from one or more Heartbeat consumers. Each node can be simultaneously Heartbeat producer and Heartbeat consumer.

The Heartbeat producer starts the cyclic transmission of its own Heartbeat message immediately if the entry in object 1017h is greater than 0. The Heartbeat consumer starts the monitoring automatically after the reception of the first Heartbeat message. Through the function mGuardErrorInd() the application is informed about each new state. This indication function is called with the arrival of the boot-up message, the start of Heartbeat messages, and if Heartbeat messages are lost.

The initialization of the Heartbeat consumer is carried out with the function defineHeartbeatConsumer(). All nodes of the Heartbeat consumer list in object 1016h (consumer heartbeat time) are initialized for Heartbeat guarding. Changes to Heartbeat parameters can be performed directly in the object dictionary. After each change the internal variables have to be updated with the function setCommPar().

Listing 20: configuration of Heartbeat consumer

Node Guarding

The Node Guarding protocol is based on a master/slave model. The Node Guarding master requests the current state of the Node Guarding slave cyclically with an RTR message. The Node Guarding slave answers this message with its state and an additional toggle bit. The Node Guarding is started on the Node Guarding master with the function startNodeGuardReq() and operates independently in the background. If the RTR message is not answered by the Node Guarding slave within the inquiry cycle, the function mGuardErrorInd() with the parameter CO_LOST_GUARDING_MSG is called. If the Node Guarding slave does not transmit responses according to adjusted lifetime factor, the guarding becomes inactive and the user is informed by the function mGuardErrorInd() and the parameter CO_LOST_CONNECTION.

The Node Guarding on the Node Guarding master can be started only if the guarding time and life time are larger than 0.

The guarding services are independent from NMT master services. Normally, the NMT master takes over the task of the Node Guarding master. That way the NMT master and the Node Guarding master are setup at the same time. For this purpose the function addRemoteNodeReq() is available. It can also be used to initialize the nodes that shall be guarded. Otherwise nodes can be added to the guarding service with the function addGuardingSlave(). In order to change guarding parameters the function setGuardTimePara() is available.

Likewise the Node Guarding slaves can monitor the queries of the Node Guarding master, called life guarding. The life guarding starts with the reception of the first RTR request from the Node Guarding master. If the RTR queries are missing, the function sGuardErrorInd() is called.

The application can determine which communication state the node shall have after calling this function. If the return value equals one, the communication state is changed to PRE-OPERATIONAL. Otherwise it is left in its current state.

NMT usage

The Network Management Service (NMT) serves for switching communication states of CANopen nodes. The service is based on a master/slave model. Only the NMT master is allowed to send NMT commands in the CANopen network.

The NMT master administers the communication states of all nodes in the network. Therefore the NMT master must create appropriate administrative structures with the function createNetworkReq(). Each node in the network where the NMT master will send NMT commands to has to be registered using the function addRemoteNodeReq(), see Listing 21.

Listing 21: example for adding remote nodes to the NMT masters network

The guarding functions Node Guarding and Heartbeat can be used independently from the NMT service.

NMT commands can be transmitted either for individual nodes or for the entire network. The functions startRemoteNodeReq(), enterPreOpStateReq(), stopRemoteNodeReq(), resetCommReq() and resetNodeReq() are available for this task. Node-ID 0 is used to address all CANopen nodes.

Listing 22: examples for initiation of NMT state transitions

The application is informed about required state changes into the states NMT/PRE-OPERATIONAL, NMT/OPERATIONAL and NMT/STOPPED by calling the function newStateInd() located in the module nmtslave.c. This information can be important, because a few communication services are not available in certain states. For example, the application receives process data via PDO and the NMT master forces the node to NMT/PRE-OPERATIONAL. Then PDOs are not allowed. The application can change to a safe state.

The module nmtslave.c also provides functions called for Reset Communication and Reset Application. Figure 27 shows the user interface functions in called order. The compiler-defines can be set by the Industrial Communication Creator.

Figure 27: user interface for Reset Application and Reset Communication

Nonvolatile memory usage

Every device needs some configuration data either for communication or application specific settings. This data has to be set at compilation time or after boot-up by a network configuration tool. It is substantially much more flexible to store configuration data in nonvolatile memory of the device. In order to do this the objects 1010h and 1011h are provided in the object dictionary. By writing a signature to these objects parts or the complete configuration data, as part of the object dictionary, can be stored in nonvolatile memory or restored from nonvolatile memory. Furthermore it is possible to load system values from ROM.

At power-on or after the NMT command Reset Communication all variable values in the object dictionary are reset to their default-value. This happens by restoring the variable entries of the object dictionary with values defined at compile time. Communication data depending on the node-ID, like COB-IDs of PDOs, are calculated by the CANopen Library according to the pre-defined connection set. In the next step the CANopen Library is calling the user function loadParameterInd(). The application has to read the stored data from nonvolatile memory and to restore corresponding object dictionary entries. The updated object dictionary data are then used to call the CANopen Library define-functions for the communication services (defineSdo(), ...) and the update-functions.

Data of the object dictionary can be written to nonvolatile memory via the object 1010h. Writing the 4 byte signature “save” to this object causes the indication function saveParameterInd() to be called. With the provided parameter sub-index the user can select which data, which part of the object dictionary should be stored. It is up to the application programmer to choose which data to store.

Figure 28: restoring of configuration data after reset

Restoring configuration data happens with a write access to object 1011h with the 4 byte signature “load”. The re-loaded data becomes valid and visible in the object dictionary after one of the NMT commands Reset Communication or Reset Application or a new boot-up.

LED usage

The LED functionality was implemented in the CANopen Library in the module led.c. The CANopen Library calls the functions ledInd() on occurrence of an error or event in order to switch the required CANopen LED on or off. The user has to add the hardware function to the function ledInd() for switching the LEDs. A template for the function ledInd() consists in the template file usr_303.c.

The functionality for the CANopen LEDs can be activated with the Industrial Communication Creator.

Listing 23: example for ledInd()

NMT startup manager usage

The CiA-302-2 provides a standardized way for booting and managing a CANopen network consisting of:

  • NMT master

  • mandatory NMT slaves, which are absolute necessary for the functionality of the network and

  • optional NMT slaves, without which the CANopen network can work.

Figure 29: NMT startup boot process

The NMT Startup process is divided into two sections:

  1. NMT Startup during system booting:

The NMT master manages all NMT slaves and itself during system booting.

  1. NMT slave startup during normal operation:

The NMT master monitors all NMT slaves after the system booting, process the error handler (see /CiA-302-2/) and reboots optional or mandatory slaves.

Figure 30: NMT startup process

Object dictionary of the NMT master

All parameters [VT1] for the NMT Startup process are defined in the object dictionary of the NMT master. The objects 1F80h and 1F81h define the behavior of the NMT slave nodes and the configuration of the CANopen network.

The optional objects 1F84h, 1F85h, 1F86h, 1F87h and 1F88h are needed for the identification of the NMT slave devices.

Object 1F89h is used for the time monitoring of the NMT startup process during system booting. This optional object is only active if there are mandatory NMT slaves in the network.

The NMT error control services shall be configured before the NMT Startup process is started. For Heartbeat monitoring the object 1016h and for Node Guarding the entries at 1F81h have to be setup. The configuration shall not be changed while the NMT startup process is running.

The object dictionary of the NMT master shall contain a client SDO Parameter object (1280h - 12FFh) for each NMT slave for parallel processing. The client SDO parameter objects are used continuously from object 1280h to 1280h + number of used NMT slaves.

NMT startup behavior

The NMT startup process can be started by calling the function nmtStartupReq() and it is finished after all mandatory slaves are started or the bootup time is over. If an error occurs for one of the mandatory slaves the NMT startup process stops immediately, but it can be restarted by calling nmtStartupReq() again.

During the NMT startup process the following steps are processed for each NMT slave:

  • detect the existence of NMT slave

All optional and mandatory slaves can be detected by starting a SDO read access on object 1000h. If an answer was received, the node is available.

  • check of the device type:

If the device type for the NMT slave at object 1F84h is unequal to zero, it must match the value that was read via SDO from the real device. Otherwise the startup procedure shall stop for this slave.

  • check of identity of the slave devices:

If the objects at index 1F85h to 1F88h exist and the values are unequal to zero, an SDO read access is performed and the received value must match the value from the object dictionary.

  • check and update of the software version:

This functionality has to be done by the application.

  • check of the NMT slave configuration:

If the objects at index 1F26h and 1F27h exist, an SDO read access is performed to read index 1020h in the object dictionary on the NMT slaves. If the received values do not match the entries at index 1F26h and 1F27h or the configuration cannot be checked, the application will be responsible to configure the NMT slaves.

  • start of error control:

This process depends on the supported error control mechanism and the values of the suitable NMT master error control objects 1016h, 1F81h and NMT slave error control objects 1017h, 100Ch, 100Dh. The error control mechanism will be started (if configured) and the NMT master waits until the first error control event occurs. If no error control message was received the startup process will be stopped for this NMT slave.

  • change of the NMT slaves into the communication state NMT/OPERATIONAL:

The behavior can be configured by the NMT master objects 1F80h and 1F81h. If all mandatory and all optional slaves are started successfully the NMT master sends the NMT command Start remote node for all nodes in the CANopen network. Otherwise each NMT slave will be set to state NMT/OPERATIONAL individually.

Figure 31: NMT slave startup process

The NMT startup manager has to execute further slave-independent processes for handling and monitoring the NMT startup during system booting:

  • reset handling:

The behavior can be configured by the NMT master objects 1F80h and 1F81h.

  • monitoring of the system booting:

This process is only executed if there are mandatory NMT slaves into the network.

  • change of the NMT master into the state NMT/OPERATIONAL:

The behavior can be configured by the NMT master object 1F80h.

NMT startup indication functions

The NMT startup process includes application-specific procedures which have to be executed outside the NMT startup process. The synchronization between the NMT startup process and the application is done by indication and request functions, see Table 31.

nmtStartupNetworkInd()

This indication is called from NMT master if the whole NMT Startup process has reached a new specific state.

nmtStartupMasterInd()

This function is called from NMT master if it has been reached a new state at the startup process.

nmtStartupSlaveInd()

The NMT master calls this function if a NMT slave-specific event is occurred.

nmtStartupContReq()

The application calls this function if the NMT Startup master can continue the NMT Startup process after application specific task has been done.

nmtStartupReq()

With this function the NMT startup process can be started by the application. If the NMT startup process has been finished with error it can be restarted by this function.

Table 31: overview of NMT startup request and indication functions

Listing 24: example for nmtStartupMasterInd()

The NMT startup process is always stopped if one of the mandatory slave bootup functions returns an error. It can be restarted by calling the function nmtStartupReq(). If all mandatory slaves are booted successfully, the NMT startup process continues the startup of the optional slaves until all slaves are successfully booted. Failure on optionally slaves doesn’t stop the NMT startup handler.

On the following events the startup process is interrupted until the application has called the function nmtStartupContReq():

  • The NMT master is ready to go into NMT/OPERATIONAL.

  • The software for a NMT slave shall be updated by the application.

  • The configuration for a NMT slave is not correct or not available and the application has to setup the actual configuration.

Table 32 gives an overview how the events are signaled and with which parameter the NMT startup process can be continued.

indication function

parameter

continue nmtStartupContReq with

nmtStartupMasterInd

NMT_MASTER_READY4START

NMT_CONT_START_MASTER

nmtStartupSlaveInd

NMT_SLAVE_UPDATE_SOFTWARE

NMT_CONT_UPDATE_SOFTWARE

nmtStartupSlaveInd

NMT_SLAVE_UPDATE_CONFIG

NMT_CONT_UPDATE_CONFIG

Table 32: overview of NMT startup continuous function parameter

Implementation

The chapter "How to make an application" is also valid for the implementation of the NMT startup process. Additional the following steps are necessary:

  • Extend the object dictionary of the NMT master by a client SDO parameter object (1280h - 12FFh) for each NMT slave. The SDO client objects have to be continuous from 1 to the number of used NMT slaves.

  • Extend the object dictionary of the NMT master by the objects 1F80h, 1F81h and optional 1F84h - 1F89h.

  • Initialize the NMT Startup process by the call of the function defineNmtStartup() during the initialization. This function is generated automatically if the Industrial Communcation Creator is used (see co_init.c).

  • Fill the indication functions nmtStartupNetworkInd(), nmtStartupMasterInd(), and nmtStartupSlaveInd() with application-specific actions.

  • Include the C modules nmtstart.c and usr_302.c into your project.

The delivered software contains the example m19 for a NMT master which supports the NMT Startup process.

Flying Master usage

The Flying Master module is provided in an extra package as an add-on to the CANopen Library.

When a device wants to participate in the Flying Master process the Flying Master functionality has to be initialized by the function defineFylingMaster(). This function is called in init_Library(), generated by the Industrial Communication Creator.

After initialization the application can start the Flying Master process according to Figure 7 by calling the function startFlyingMaster().

NMT master detection service

The application can call the function detectMasterReq() to execute the Flying Master service “NMT master detection”.

If a NMT master has answered the request the function flyingMasterInd() is called with the argument FLYMA_DETECT_MASTE_OK.

The CANopen Library also calls the function flyingMasterInd() if the NMT master detection timeout specified in object 1F91h/1 is elapsed. The argument is FLYMA_DETECT_CAPA_DEV_TIMEOUT.

Active NMT master detection service

The application can call the function activeMasterReq() to execute the Flying Master service “Active NMT master detection”.

If an unexpected NMT master has transmitted a response the function flyingMasterInd() is called with the argument FLYMA_BAD_MASTER. The CANopen Library executes the Flying Master service “Force NMT Flying Master negotiation” if the function flyingMasterInd() returns CO_TRUE.

The CANopen Library also calls the function flyingMasterInd() if the NMT master timeout specified in object 1F90h/1 is elapsed. The argument is FLYMA_DETECT_MASTER_TIMEOUT.

NMT Flying Master negotiation service

This Flying Master service is executed by the CANopen Library automatically when:

·         no active NMT master was found in the CANopen network

a NMT Flying Master negotiation request was received

Force NMT Flying Master negotiation

This Flying Master service is executed by the CANopen Library automatically when:

  • an unexpected NMT master was detected or

  • a NMT master with a lower priority was detected or

  • the multiple NMT master detect cycle time specified in object 1F90h/6 is elapsed and the validity of the NMT master shall be check by repetition of the service “NMT Flying Master negotiation”

Heartbeat monitoring

The loss of the active NMT master shall be detected by each NMT master capable CANopen device by monitoring the active NMT master via the Heartbeat service.

The CANopen Library calls the function flyingMasterInd() with the node-ID of the active NMT master, i.e. the node-ID is unequal 0, when the Heartbeat monitoring has to be started. The Heartbeat service has to be started by the application.

If the Heartbeat is lost a new NMT Flying Master negotiation process is started.

Configuration Manager

The configuration of nodes in CANopen networks is stored in form of object dictionary entries in device configuration files (DCF). Each node has its own DCF. The document CiA-302-3 describes how the information can be provided to a Configuration Manager including identification details like date, time of the current configuration of nodes. The Configuration Manager uses this information to synchronize the configuration of the DCF with the configuration of the node in the CANopen network. If any difference is detected the Configuration Manager will download the values to the device.

Figure 32: Configuration Manager process

The configuration for a node can be stored as DCF on the index 1F20h or as Concise DCF (compressed DCF) on index 1F22h.

Both objects (1F20h and 1F22h) are of type DOMAIN and need to be passed from the application to the CANopen Library with the functions: setDomainAddr() and setDomainSize() respectively.

For downloading the configuration to the nodes the object 1F22h is obligatory.

For each node version information of the configuration (date and time) is stored in object 1F20h. The values of this object are compared with the values of the remote node (object 1020h) and on difference the remote node is updated with the values from the configuration.

The function checkRemoteNodeConfig() starts the configuration verification. This function uses SDO accesses to obtain the current configuration of a remote node object 1F20h. The result of the verification is provided in the indication function cfgManagerInd().

The function updateRemoteNodeConfig() starts the configuration update. The data of object 1F22h is transmitted to the remote node without further checking. Special configuration sequences, e.g. when changing the PDO mapping, need to be followed in the DCF.

Afterwards the version information is written to the newly configured nodes. The function cfgManagerInd() provides information about success of the configuration process and occurred errors to the application.

Both steps can also be started with the function handleRemoteNodeConfig(). This function reads via an SDO access the current configuration of a node and starts an update of the configuration if necessary. The status of the configuration and occurred errors are passed to the application with the function cfgManagerInd().

Access to remote nodes is carried out with SDO read- and write accesses. The application has to provide the necessary service data objects in the object directory and needs to configure them.

Conversion to concise DCF

The function convertToConciseDcf() provides the facility to convert standard DCF files to the concise format. To ensure the required configuration sequences for the various objects (like changing PDO mapping) the function has to be called repeatedly with different arguments. On each call the complete DCF is scanned and the needed objects are determined.

Listing 25: concise DCF conversion

Afterwards the concise DCF data is available in the buffer conDcfBuf.

The conversion function requires rather much memory. Therefore it has to be enabled with the compiler directive

#define CONFIG_CFG_MANAGER_CONVERT 1.

The example m20 shows the usage of the functions. It works together with the example s2.

Application programming interface

checkRemoteNodeConfig()

read and check remote config

handleRemoteNodeConfig()

check and update remote node config

updateRemoteNodeConfig()

write concise dcf data to node

convertToConciseDcf()

convert standard DCF to concise DCF

cfgManagerInd()

Configuration Manager indication

Table 33: overview about concise DCF API

For each event detected by Configuration Manager functions the user indication function cfgManagerInd() is called.

values for parameter type

description

CFG_MANAGER_CFG_OK

Configuration is ok (up to date)

CFG_MANAGER_DATA_MISSING

DCF data length not correct

CFG_MANAGER_DATE_CHECK_FAIL

Configuration check time failed. Index or subIndex (1F27h) does not exist.

CFG_MANAGER_OK

Configuration ok

CFG_MANAGER_SDO_ABORT

SDO Abort received during writing configuration

CFG_MANAGER_SDO_ABORT_CFG_INFO

SDO Abort during writing to object

1020h of slave

CFG_MANAGER_SDO_ERROR

Error at SDO request

CFG_MANAGER_SDO_TIMEOUT

SDO timeout occurred

CFG_MANAGER_START_UPDATE

Configuration   automatic           update started

CFG_MANAGER_START_UPDATE_FAIL

Configuration start automatic update failed

CFG_MANAGER_TIME_CHECK_FAIL

Configuration check time failed. Index or subIndex (1F26h) does not exist.

CFG_MANAGER_WRITE_CFG_DATE_FAIL

Writing configuration date/time to object directory of Configuration Manager (local) failed. Index or subIndex does not exist.

Table 34: cfgManagerInd()

1.1.1        Notes for slave devices

The current version information is stored on slave devices in object 1020h. If this object does not exist the function checkRemoteNodeConfig() and handleRemoteNodeConfig() will stop and call the indication function with the value CFG_MANAGER_SDO_ABORT.

Configuration still can be continued with the function updateRemoteNodeConfig() to the desired nodes. At the end of the configuration process the indication function will be called with the value CFG_MANAGER_SDO_ABORT_CFG_INFO.

 

Network redundancy

The redundant communication is designed to fulfill the requirements of high reliable systems (e.g. maritime or medical applications). It is based on a communication using two separate physical CAN wires. The first line is called the Default-CANline and the second one Redundant-CANline. The communication starts on the Default-CANline. If the line is disturbed or fails the communication switches to the Redundant-CANline. If the Default-CANline has recovered from failure the communication will switch back to this line. A prerequisite of it is the active Heartbeat monitoring of all nodes on both lines in the network.

The usage of non-redundant nodes is possible too. This kind of nodes have to be connected only to one line.

The redundant communication is described in CiA-302-6.

Line switching

Line switching can be done automatically by the CANopen Library or by the application. Before the CANopen Library performs a line switching it calls the user indication function redundancyInd(). Within this function the user application can avert the automatic line switch by returning with a special return code.

Line negotiation at boot-up

After a power-on reset and after a Reset Communication a line negotiation is performed by the following steps:

  • A timer will be started.

  • If 3 Heartbeat messages are received from all redundant nodes on the default line then the Default-CANline will become the active line.

  • The timer is stopped, if an active line message was received.

  • If the timer expires then the Redundant-CANline will become the active line.

Figure 33: program flow after boot-up

Line monitoring

If the Default-CANline is active all other nodes will be monitored by Heartbeat. If the Heartbeat from one of the other nodes fails the user indication function redundancyInd() is called. If it returns with CO_TRUE then a switch to the Redundant-CANline will be performed. If the command active line is received on the Redundant-CANline a switch to this line is performed without calling the user indication.

The behavior when the default line is the active line is shown in Figure 34.

Figure 34: program flow when Default-CANline has errors

If the Redundant-CANline is active the CANopen Library checks for 3 error-free received Heartbeat from all redundant nodes on the Default-CANline. If this is the case, the user indication redundancyInd() is called and a switch back to the Default-CANline will be performed if the return value is CO_TRUE.

The behavior when the redundant line is the active line is shown in Figure 35.

Figure 35: program flow when Default-CANline is error-free

Message transmission

Message transmission depends on the used service, the active CAN line and the actual communication state of this line:

service

transmit on

condition

treatment

NMT

any

nothing

line depending

NMTErr

any

depends on line state

line depending

PDO

both

OPERATIONAL

both lines

EMCY

both

OPERATIONAL or PRE‑OPERATIONAL

both lines

TIME

both

OPERATIONAL or PRE‑OPERATIONAL

active line

SYNC

both

OPERATIONAL or PRE‑OPERATIONAL

active line

Server SDO

received line

OPERATIONAL or PRE‑OPERATIONAL

received line

Client SDO

one line

OPERATIONAL or PRE‑OPERATIONAL

 

Flying Master

active line

except force ResetComm, id master

 

 

received line

only id master response

 

 

both

only force ResetComm

 

Redundancy

active

 

 

Table 35: line-dependend message transmission

Transmission of PDO

Transmission of PDOs is monitored by the producer to avoid transmission of too old messages (waiting too long for transmission.) This is done by the driver. Furthermore an error counter for the first Transmit PDO is managed. It will be incremented by 4 for each erroneous transmission and decremented by 1 for each error-free transmission. If the configured error limit (index 1F60h, sub-index 5) is reached the transmission of Heartbeat is stopped until the error counter is decremented to 0.

Indication function

For each event detected by the redundant communication layer the user indication function redundancyInd() is called.

values for parameter event

description

REDUNCY_EVAL_TIMEOUT

evaluation time is up

REDUNCY_SWITCH_REDUNDANCY_LINE

switch to redundant line

REDUNCY_SWITCH_DEFAULT_LINE

switch to default line

REDUNCY_DEFAULT_LINE_OK

default line ok

REDUNCY_HB_ERROR

default line Heartbeat failure

REDUNCY_TPDO_FAILED

TPDO error counter max value reached

REDUNCY_TPDO_OK

error counter decremented to 0

Table 36: parameter values for redundacyInd()

The default reaction of the CANopen Library can be averted by returning the value CO_FALSE when leaving the indication function. The following CANopen Library reactions are supported:

event

return value

default reaction of CANopen Library

Eval-time is up

REDUNCY_EVAL_TIMEOUT

switch to redundant line

Switch to default line

REDUNCY_DEFAULT_LINE_OK

switch to default line

HB failure on default line

REDUNCY_HB_ERROR

switch to redundant line

PDO error counter reached

REDUNCY_TPDO_FAILED

switch off Heartbeat transmission

Table 37: return values of redundancyInd()

The redundancy communication can be tested using the examples s11 (redundancy slave) and m11 (redundancy master with Flying Master capabilities).

LSS usage

CANopen addressing depends on a node-ID (1-127, 255). Normally the node-ID is setup via DIP switches or rotary switches. Seldom it is hardcoded in the software. Some devices cannot provide DIP switches because they are completely sealed to be used in chemical applications or underwater. With the means of the Layer Setting Services (LSS) CANopen such devices can be identified and configured without external switches. LSS services are based on a master/slave model. In order to define LSS services the function defineLss() have to be called. This function is called in init_Library(), generated by the Industrial Communication Creator.

Within a CANopen network only one LSS master is allowed to exist. All other devices can be configured as LSS slaves. All data for identifying an LSS slave is taken from the identity object 1018h. Object 1018h contains the unique LSS address. Every sub-index of object 1018h has to be filled. The serial number has to be unique.

LSS distinguishes two states:

  • LSS/WAITING and

  • LSS/CONFIGURATION.

Switching between these states can be done globally for all nodes or selectively for just a single LSS slave.

After initialization the node changes automatically into the state LSS/WAITING. Switching into the state LSS/CONFIGURATION can be carried out independently of the current NMT state. If the node-ID was set and the device is set to the state LSS/WAITING again the CANopen Library will automatically call Reset Communication to activate the new node-ID and the COB-IDs are recalculated according to the pre-defined connection set.

LSS master

Communication is always initiated by the LSS master. The CANopen Library provides the following request function for the LSS services:

LSS service

usage by CANopen Library

Switch state global

request function: writeLssSwitchModeReq()

This function changes the LSS state of all LSS slaves. The vendor argument has to be set to value 0.

Switch state selective

request function: writeLssSwitchModeReq()

This function changes the LSS state of one LSS slave selected by the given LSS address.

Configure node-ID

request function: writeLssConfigNodeIdReq()

This function writes a new node-ID to the selected LSS slave but does not activate the new node-ID. The LSS slave must be in the state LSS/CONFIGURATION.

Configure bit timing parameters

request function: writeLssConfigBitrateReq()

This function writes a new CAN bit rate to the selected LSS slave but does not activate the new CAN bit rate. The LSS slave must be in the state LSS/CONFIGURATION.

Activate bit timing parameters

request function: writeLssActivateBitrateReq()

This function activates a new CAN bit rate for the CANopen network. The LSS slaves must be in the state LSS/CONFIGURATION.

Store configuration

request function: writeLssStore()

This function initiates the nonvolatile storage of network parameter(s) in the selected LSS slave. The LSS slave must be in the state LSS/CONFIGURATION.

Inquire LSS address

request function: writeLssInquiryReq()

The LSS master can inquire the LSS address of the selected LSS slave. The LSS slave must be in the state LSS/CONFIGURATION.

Inquire node-ID

request function: writeLssInquiryReq()

The LSS master can inquire the node-ID of the selected LSS slave. The LSS slave must be in the state LSS/CONFIGURATION.

Identify remote slave

request function: writeLssIdentityReq()

The LSS master searches for a LSS slave with the given LSS address.

Identify non-configured slave

request function: writeLssIdentNonCfgReq()

The LSS master requests all unconfigured LSS slaves to identify themselves.

Fast scan

request function: writeLssFastScan()

The LSS master searches for unconfigured LSS slaves. All LSS slaves shall be in the state LSS/WAITING at the beginning of the LSS Fast scan procedure.

Table 38: LSS request functions

The LSS master calls the function lssMasterCon() when it receives a response from LSS slave(s). A template for the function lssMasterCon() consists in the template file usr_305.c.

The LSS master monitors the communication with the LSS slaves. The timeout time can be configured using the Industrial Communication Creator tool from version 6.2.*. During runtime the LSS timeout can be read by function coLssGetTimeout() and can be written by function coLssSetTimeout().

LSS slave

The LSS slave calls the function lssSlaveInd() when it receives a LSS request from the LSS master. The application has to manage received new network parameters or the activation of a new CAN bit rate. A template for the function lssSlaveInd() consists in the template file usr_305.c.

Safety

Object dictionary

All SRDO communication parameters are stored in the object dictionary. The CANopen Library ensures that no safety relevant data is changed in the state NMT/ OPERATIONAL. Therefore access to this data is only allowed in the state NMT/PRE-OPERATIONAL. Every access to SRDO communication settings resets the internal configuration of SRDO, so no SRDO communication is possible until the SRDO configuration is validated again.

Before SRDO parameters are valid, a checksum is calculated over the desired parameters of the object dictionary. This checksum is compared to the checksum stored in the object dictionary. If the two checksums are not equal, then SRDO communication is not allowed.

When changing mapping data of an SRDO the number of entries, i.e. sub-index 0, has to be set to 0. Consistency is checked when writing mapping data.

SRDO initialization

In order to use SRDOs they have to be initialized. With the function defineSrdo() the necessary internal structures and settings for the CAN-Controller are made. This function is called in init_Library(), generated by the Industrial Communication Creator.

SRDO communication

Transmission and reception of SRDOs is only possible in the state NMT/OPERATIONAL. On transition to this state the consistency of the SRDO data in the object dictionary is checked. If the configuration valid bit is not set SRDOs are not enabled for sending or receiving. But the transition is still executed. If the configuration valid bit is set but there are other inconsistencies the transition to NMT/OPERATIONAL is aborted.

Transmission of SRDOs

Before sending SRDOs the CAN message has to be assembled according to the mapping. The user can use the function mapSrdoInd() to realize this.

When a SRDO shall be sent the CANopen Library calls mapSrdoInd() and transmits the user assembled CAN message afterwards. The function writeSrdoReq() sends an additional SRDO if it is necessary to do so.

Figure 36: user interface for SRDO producer

Reception of SRDOs

After reception of an SRDO the CANopen Library calls srdoInd() where the data can be processed. The user has to check the integrity of the data, i.e. comparison of not inverted and inverted data, and for the adherence to timing restrictions. The following has to be checked:

  • CAN message in correct order

  • adherence of the Safeguard cycle time (SCT)

  • adherence of the Safety relevant object validation time (SRVT)

It is recommended to use a separate timer in order to realize the part of the safety completely in the application.

When all checks are done data can be saved into in the object dictionary.

Figure 37: user interface for SRDO consumer

Solution for SRDO reception

Problems:

  • execution time of indication function

  • priority distribution on the bus (SRDO1 received, then reception of higher priority SRDO, then SRDO2)

  • retain the driver concept without changes

  • accurate timeout detection

  • if many SRDOs (64) needed - i.e. 128 CAN messages

Possible solutions:

a)       retain current concept and evaluation in the callback function

b)      assign time stamps in ISR

c)       usage of priorities within the buffer handling

d)      calling of the callback function directly from the ISR

e)      SRDO is valid after 1st and 2nd CAN message was received, i.e. timeout timer has to be reset only after the inverted SRDO was received.

Figure 38: timeout causes of SRDO

Virtual objects

Usually all data is stored in the object dictionary data structure of a device. However, for special applications it may be necessary to support additional or temporarily available objects besides the “real” objects. In the CANopen Library these objects are called virtual objects.

Virtual objects are entries in the object dictionary that have no physical entry in the object dictionary e.g. attributes and physical address are unknown to the CANopen Library. Instead these objects are entirely managed by the user application and data necessary for communication is forwarded to the CANopen Library via special indication function.

Virtual objects do not have to be created in the Industrial Communication Creator but it is recommend for documentation. They are usually placed in the manufacturer or device profile segment of the object dictionary as normal and marked with the “virtual object” option. Virtual and real objects can be created in any order but a virtual object cannot be appended to a real object (e.g. in a record or array).

The Industrial Communication Creator will not create declarations or initializations for virtual objects, instead the user is responsible for checking the data and value ranges, and providing the necessary memory space.

In order to use virtual objects the compiler directive CONFIG_VIRTUAL_OBJECTS has to be set. Both SDO and PDO access to virtual objects is possible.

SDO access

Access to real objects in the object dictionary is done via SDO access and follows the attributes specified. If an object cannot be found in the object dictionary data structure, access to a virtual object is assumed and the functions getVirtualObjAddr() and getVirtualObjAttr() are called. These functions will take over providing the necessary information about this object to the CANopen Library.

Figure 39: SDO access to virtual objects

The application decides whether access to the virtual object with the given index and sub-index is permitted. If the access is allowed then the pointer to the data and the size of the virtual object has to be provided by the application. If access is denied then an SDO abort is generated depending on the return value of the function getVirtualObjAddr(). Further processing takes place in the same manner as for real objects.

Templates for the functions getVirtualObjAddr() and getVirtualObjAttr() are located in the template file usr_301.c.

PDO access

Process data transmitted and received via PDO. If objects mapped to a PDO cannot be found in the object dictionary, access to a virtual object is assumed and the function coUserVirtualTpdoInd() or coUserVirtualRpdoInd() is called. The application has:

  • for TPDO: to copy the data for transmission from application variables to the buffer for the TPDO or

  • for RPDO: to copy the received data from the buffer for the RPDO to the application variables.

The data must be copied to the byte in the PDO buffer as specified in the PDO mapping.

Figure 40: TPDO access to virtual objects

Figure 41: RPDO access to virtual objects

The CANopen Library needs to have full knowledge about the PDO mapping to handle the data correctly. The PDO mapping can be changed as usual. The virtual objects which shall be mappable must have the object attribute CO_MAP_PERM.

Note: Special configurations added to CANopen Library V4.5.15 are still available.

Object callbacks

Sometimes an application has to react on an access of an object regardless of whether the access was via a PDO, a MPDO or an SDO. For such application behavior the CANopen Library provides the ability to attach application-specific callback to an object, named object-specific callback. Object-specific callbacks are always called from the CANopen Library when the object is accessed independent on the used CANopen service.

The object-specific callback must have the following function prototype:

Listing 26: function prototype for object-specific callback

The name of the object-specific callback can be freely assigned by the user. In the example in Listing 26 the name of the object-specific callback is foo.

The parameter reason gives information to the trigger conditions for the call of the object-specific callback. The structure CO_OBJ_CB_TYPE_T summarizes the following trigger conditions:

Listing 27: structure CO_OBJ_CB_TYPE_T

The functionality for object-specific callbacks has to be activated by the compiler-define CO_CONFIG_ENABLE_OBJ_CALLBACK. Each desired CANopen service and sample point can be selected by a compiler-defines. The compiler-defines are configurable by the Industrial Communication Creator, see Figure 42.

Figure 42: settings for object-specific callbacks in the Industrial Communication Creator

The name of the object-specific callback function shall be entered in the entry field “C Callback” for the associated objects, see Figure 43.

Figure 43: specification of object-specific callback function in the Industrial Communication Creator

If the application needs to set or reset an object callback at run-time the function setObjFuncPtr() can be used. The prototype of the function is:

If the application wants to disable this callback, the new function pointer shall be set to NULL.

SDO read access

The calling of the user interface functions for SDO read accesses is shown in Figure 44. The virtual object handling is described in chapter 4.21.1.

Figure 44: object-specific callbacks for SDO read accesses

SDO write access

The calling of the user interface functions for SDO write accesses is shown in Figure 45. The virtual object handling is described in chapter 4.21.1.

Figure 45: object-specific callbacks for SDO write accesses

PDO/MPDO read access

The calling of the user interface functions for PDO/MPDO read accesses is shown in Figure 46. The virtual object handling is described in chapter 4.21.2.

Figure 46: object-specific callbacks for PDO/MPDO accesses

PDO write access

The calling of the user interface functions for PDO read accesses is shown in Figure 47. The wrong PDO length handling is described in chapter 4.7.4.2. The virtual object indication is described in chapter 4.21.2.

Figure 47: object-specific callback for PDO write accesses

MPDO write access

The calling of the user interface functions for PDO read accesses is shown in Figure 48. The wrong MPDO length handling is described in chapter 4.7.4.2.

Figure 48: object-specific callback for MPDO write accesses