Canopen Library User Manual: © Port GMBH 2014
Canopen Library User Manual: © Port GMBH 2014
User Manual
V4.5
Copyright
© 2014 port GmbH
Regensburger Straße 7
D-06132 Halle
Tel. +49 345 - 777 55 0
Fax. +49 345 - 777 55 20
E-Mail [email protected]
Internet http://www.port.de
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . 9
1.1. Applicability of the Documentation . . . . . . . . . . . . . . 9
1.2. Product Overview . . . . . . . . . . . . . . . . . . . 9
1.3. System Requirements . . . . . . . . . . . . . . . . . . 9
1.4. Additional Tools . . . . . . . . . . . . . . . . . . . . 10
1.5. Installation . . . . . . . . . . . . . . . . . . . . . . 10
1.6. Support by port . . . . . . . . . . . . . . . . . . . . 11
2. CANopen Communication Model . . . . . . . . . . . . . . . 13
2.1. Object Dictionary . . . . . . . . . . . . . . . . . . . . 13
2.2. Service Data Objects . . . . . . . . . . . . . . . . . . . 14
2.3. Process Data Objects . . . . . . . . . . . . . . . . . . . 16
2.4. Emergency Objects . . . . . . . . . . . . . . . . . . . 21
2.5. SYNC Objects . . . . . . . . . . . . . . . . . . . . . 21
2.6. Time Stamp Objects . . . . . . . . . . . . . . . . . . . 21
2.7. Error Control Mechanisms . . . . . . . . . . . . . . . . . 21
2.7.1. Node Guarding . . . . . . . . . . . . . . . . . . . . 21
2.7.2. Heartbeat . . . . . . . . . . . . . . . . . . . . . . 22
2.8. Boot-up Message . . . . . . . . . . . . . . . . . . . . 22
2.9. Network Behavior . . . . . . . . . . . . . . . . . . . 22
2.10. CANopen Device Profiles . . . . . . . . . . . . . . . . . 25
3. CANopen Library . . . . . . . . . . . . . . . . . . . . 27
3.1. CANopen Library Concept . . . . . . . . . . . . . . . . . 27
3.2. Design Flow . . . . . . . . . . . . . . . . . . . . . 31
3.3. CANopen Library Structure . . . . . . . . . . . . . . . . 33
3.3.1. Object Dictionary . . . . . . . . . . . . . . . . . . . 36
3.3.2. CANopen Library Configuration . . . . . . . . . . . . . . 40
3.3.2.1. Configuration Header . . . . . . . . . . . . . . . . . 40
3.3.2.2. Coding of 64-bit Values . . . . . . . . . . . . . . . . 41
4. Using the CANopen Library . . . . . . . . . . . . . . . . . 43
4.1. Service Definition Interface . . . . . . . . . . . . . . . . 43
4.2. Service Request Interface . . . . . . . . . . . . . . . . . 43
4.3. Service Indication/Confirmation Interface . . . . . . . . . . . . 44
4.4. Configuration Interface . . . . . . . . . . . . . . . . . . 45
4.5. Timer Usage . . . . . . . . . . . . . . . . . . . . . 46
The documentation of the CANopen Library by port consists of a user and a reference
manual. The user manual serves as an introduction for using the CANopen Library. The
procedure to use this CANopen Library and the process of integration into the customer’s
application are described here. This document and the reference manual describe the
properties of all distributions of the CANopen Library. The CANopen Library source
code is delivered in different configurations for multi or single CAN lines, master/slave or
slave. Both user and reference manual are available as HTML documents.
The version/revision number of the user manual and the reference manual correlates to
the version/revision of the CANopen Library software.
port is a member of the CAN in Automation (CiA). Our engineers are involved in the
standardization activities in many of the Special Interest Groups of the CiA.
With this knowledge, port ensures that all CANopen products are conform to CiA stan-
dards. Because CiA does not certify software but rather CANopen devices, ask our sup-
port team for a reference of certified custom CANopen devices.
The CANopen Library by port has been developed with respect to the following points:
• CANopen functionality for both master and slave
• scalability to use only the kind and numbers of services the application needs
• independence of hardware and operating systems
• support of more than one CANopen network (up to 255 CANopen network lines)
• easy application interfaces
• very high portability and full ANSI-C conformity
All provided CANopen functionality fulfills the standards of CiA e.V., but not all optional
functions are supported. Please contact our sales team for detailed information, see chap-
ter 1.6.
The CANopen Library has been written in ANSI-C with a high degree of portability in
mind. Therefore it is possible to compile the sources with any ANSI-C compliant com-
piler. The CANopen Library was tested with a lot of various compilers. The functions of
the CANopen Library run on any system which guarantees:
• an interrupt handling for CAN, or available CAN device drivers
• hard- or software timer
For applications using an active CAN interface or providing CAN operating system driv-
ers, a CAN interrupt handling is not necessary.
The usage of the CANopen Library is support by the following tolls from port:
• CANopen Design Tool for the configuration and optimization of the CANopen
Library, the configuration of desired hardware and the design of the object dictio-
nary,
• CANopen Device Monitor for starting of CANopen communication in a CANopen
network and
• CAN-REport for the analyzation of the CAN bus.
Demo versions of these tools are available on port’s web-page. The user manuals of
these tools provides more details. The usage of the CANopen Design Tool is very recom-
mended.
1.5. Installation
source
drivers shar_inc
atcandos
cpcwin
<layer2_xy>
....
examples s1
s2
....
user templates
user_man
ref_man
Set the shift-width to 4 and tab-stop to 8 in your editor to get best performance while
viewing the CANopen Library C files.
CANopen is a set of existing and emerging profiles and was originally based on CAN
Application Layer (CAL). CAL was the first available open application layer specifica-
tion for CAN. Because CAL specifies a variety of data objects and services, the usage of
these services was not easy. The CANopen Communication Profile comprises a concept
to configure and communicate real-time-data as well as the mechanisms for synchroniza-
tion between devices. Basically the CANopen Communication Profile describes how a
subset of CAL services is used by devices. The restriction to a subset hereby reduces the
amount of needed program memory to implement an open application layer.
Now all CANopen mechanisms and services are completely defined in the CANopen
Application and Communication Profile.
The CANopen Device Profile describes the functionality of a particular device type and
the communication with this device.
Two data types with different characteristics are dominating most automation networks
and also CANopen. There are separate messages for process and service data. Further-
more CANopen defines an interface for data access. All data and parameter of a device,
which should be visible from CAN, can be reached via the object dictionary.
All device parameters are stored in an object dictionary. This object dictionary contains
the description, data type and structure of the parameters as well as the address from
others point of view. The address is being composed of a 16 bit index and an 8 bit sub-
index and guarantees therefore compatibility with existing device profiles (e.g. DRIVE-
COM). Only the CANopen specific entries have no correlation with other profile defini-
tions. The sub-index refers to the elements of complex data types e.g. arrays and records
(table 1).
UNSIGNED8 NumberOfEntries;
UNSIGNED16 BaudRate;
UNSIGNED8 NumberOfDataBits;
} RS232_T;
The object dictionary is organized in different sections (table 2).
Index Object
0000h not used
0001h − 009F h Data Type Definitions
00 A0h − 0FFF h reserved
1000h − 1FFF h Communication Profile Area (CiA-301)
2000h − 5FFF h Manufacturer Specific Profile Area
6000h − 9FFF h Standardized Device Profile Area
(CiA-4xx), can be divided in in eight
sections 800h each, each containing
objects of a different device profile
A000h − FFFF h reserved
Table 2, Object Dictionary Structure
There is a range of mandatory entries in the dictionary which ensures that all CANopen
devices of a particular type show the same behavior. The object dictionary concept serves
for optional device features which means a manufacturer does not have to provide certain
extended functionality on his device, but if he wishes to do so he has to do it in a pre-
defined manner. Additionally, there is sufficient address space for truly manufacturer
specific functionality. This approach ensures that the CANopen device profiles are future
proof.
Service Data Messages, in CANopen called Service Data Objects SDO, are used for read
and write access to all entries of the object dictionary of a device. Main usage of this
type of messages is the device configuration. Besides reading and writing of the parame-
ters and data, it is possible to download whole programs to the devices. SDOs are typi-
cally transmitted asynchronously. The requirements towards transmission speed are not
as high as for PDOs. The SDO message contains information to address data in the
device object dictionary and the data itself. Most existing profiles use 3 bytes to address
objects, divided in two bytes for an index address and one byte for the sub-index address.
Using the same scheme and considering one byte for the protocol four bytes remain for
parameter data. Therefore a SDO transfer consists of a CAN message to initiate and per-
form data transfer and a CAN message for handshake.
SDO Request
SDO Telegram SDO
Request Indication
Object Object
Dictionary Dictionary
SDO SDO
Confirmation SDO Response Response
Telegram
Figure 2 shows the communication between two devices. There are two variants for SDO
usage. The first one is a write access and the second one a read access to the SDO server
object dictionary. The SDO client initiates a write service with a SDO write request. The
SDO server indicates the message, writes the value to the object dictionary and gives a
response to the CAN network. The client gets a confirmation of that service. At a read
request the confirmation message contains the data read. If it is necessary to transfer
more than 4 byte, e.g. arrays or files, a sequence of segmented messages will follow the
initiate transfer message, each one acknowledged by the data server. See figure 3 for the
SDO protocol.
Multiplexor
Initiate/Expedited
domain 8 bit
Transfer
protocol
16 bit index
sub-index
4 bytes data
(parameter <= 4 bytes)
Segmented
domain
Transfer protocol 7 bytes data
(parameter > 4 bytes)
Contrary to the PDOs the SDOs get low priority CAN identifiers. There are two device
types for SDO handling. The first is the SDO server. These devices can not initiate a
SDO service request. They can only react to a SDO indication. Such reactions are wri-
ting or reading values to/from the local object dictionary. The COB-IDs for the first
server SDO are predefined and can not be changed in order to ensure the connection to
the device. The COB-IDs are built like follow:
COB − IDTX = 1408 + <node-ID> (1)
Process Data Messages in CANopen called Process Data Objects PDO are used to per-
form the real-time data transfer between different automation units. PDOs have to be
transmitted quickly, without any protocol overhead and within a predefined structure.
source target(s)
1. event driven
SYNC
source target(s)
3. synchronised
source target(s)
4. timer driven
The communication parameter of a PDO resides in the object dictionary. The indexes for
PDOs are calculated as follows:
index RPDO−comm− par = 1400h + (<RPDO number> − 1) (5)
The content of the PDO is encoded in the PDO mapping entries. A PDO can contain up
to 64 single data elements from the object dictionary (in the case of 64 of the data are
bits). The data are described via its index, sub-index and length. The mapping parameter
of a PDO resides also in the object dictionary. The mapping indexes are built like follow:
index RPDO−map− par = 1600h + (<RPDO number> − 1) (7)
The entries from sub-index 1 contain a logical reference to the variables, which are to be
transmitted/received (table 8). The date is described by its index and sub-index and its
length. The length value represents the data’s length in bits. Therefore it is possible to
transmit only the relevant range of the data i.e. 3 bits of a C char value.
A special case of mapping is the so called dummy mapping. With this kind of mapping,
it is possible to blind out irrelevant data. This feature is used for a 1:n communication,
where each receiver utilizing only a part of the PDO. For dummy mapping the indexes
1-7 are used. These indexes are only references to data types. These entries are only
space holders with the type corresponding size (table 9).
The mapping for the PDO can be static or changeable. If the mapping can be changed, it
is called dynamic PDO mapping. Changing of mapping can be done in the state PRE-
The Emergency Message (EMCY) is a service, which signals internal fatal device errors.
The error types are defined in the communication profile and the device profiles. The
EMCY is transmitted with highest priority. CANopen defines EMCY producer and
EMCY consumer. The producer transmits EMCYs and the consumers receive them. The
EMCY telegram consists of 8 bytes. It contains an emergency error code, the contents of
object 1001h and 5 byte of manufacturer specific error code. Additionally an error han-
dling exists. Each transmitted error code and the first two bytes of the manufacturer spe-
cific code will be pushed in the predefined error field on index 1003h . This field can con-
tain up to 255 error entries. The value of sub-index 0 shows the current number of
entries. The most recently occurred error will be always inserted on the top of this field
(sub-index 1). All older entries will be moved down. Are there no more errors on the
device, an EMCY with error code 0 will be sent.
The SYNC object is a network wide system clock. It is the trigger for synchronous mes-
sage transmission. The SYNC has a very high priority and contains no data in order to
guarantee a minimum of jitter.
The Time Stamp object provides a common time reference. It is transmitted with high
priority. The time is encoded in the type Time of Day. This data type contains the mil-
liseconds since midnight and the number of days since January 1, 1984.
For node monitoring two different mechanisms are defined. They are called Node
Guarding and Heartbeat. Each device has to provide one of the error control mecha-
nisms.
The Node Guarding (Life Guarding) is the periodical monitoring of certain network
nodes. Each node can be checked from the NMT master with a certain period ( guard
time, 100C h ). A second parameter ( life time factor, 100D h ) defines a factor when the
connection should be applied as lost.
The resolution of the guarding time is 1 ms. The condition for Node Guarding on a slave
device is that guard time and life time factor are not zero. Guarding is started with the
2.7.2. Heartbeat
Heartbeat is an error control service without need for remote frames. The Heartbeat pro-
ducer transmits cyclic a Heartbeat message. One or more Heartbeat consumers receive
this message and monitoring this indication. Each Heartbeat producer can use a certain
period ( Heartbeat producer Time, 1017h ). Heartbeat starts immediately if the Heartbeat
producer Time is greater zero.
The Heartbeat consumer has to monitor the Heartbeat producer. For monitoring the
Heartbeat consumer has an entry for each Heartbeat producer at its own object dictionary.
The Heartbeat consumer Time (1016h ) can be different for each Heartbeat producer but
should be greater than the Heartbeat producer Time. Usually the Heartbeat will be con-
figured by the network configuration manager.
The resolution of the Heartbeat times is 1 ms.
➥ Heartbeat has a big influence on network load - but in effect, the half of the load of
the Node Guarding monitoring!
After a CANopen node has finished its own initialization and entered in the node state
PRE-OPERATIONAL it has to send the Boot-up Protocol -Message. This message indi-
cated that the slave is ready for work (e.g. configuration). This protocol uses the same
identifier as the error control protocol (Node Guarding or Heartbeat).
Another simplification for CANopen is the definition of a minimal boot-up procedure for
devices, shown in the state diagram in figure 6.
Initialisation
Power-On
INITIALISATION
12 2 9
PRE-
OPERATIONAL
7
5
STOPPED
3 4 6
8
OPERATIONAL
Devices with the minimal boot-up procedure contain only three states PRE-OPERA-
TIONAL, STOPPED and OPERATIONAL. The difference between master and slave
devices is the initiation of the state transitions. The master controls the state transitions
of each device in the network. After power-on a device is going to be initialized and set
in the state PRE-OPERATIONAL automatically. In this state reading and writing to its
object dictionary via the service data object (SDO) is possible. The device can now be
configured. That means setting of objects or changing of default values in the object dic-
tionary like preparing PDO transmission. Afterwards the device can be switched into the
OPERATIONAL state via the command Start Remote Node in order to start PDO com-
munication. PDO communication can be stopped by the network master by simply
switching the remote node back to PRE-OPERATIONAL by using the Enter Pre-Opera-
tional State command. Via the Stop Remote Node command the master can force the
slave(s) to the state STOPPED. In this state no services besides network and error control
mechanisms are available. The command Reset Communication resets the communica-
tion on the node. All communication parameters will be set to their defaults. The
In order to reduce configuration effort for simple networks a mandatory default identifier
allocation scheme is defined not only for NMT messages, also for the other services.
These identifiers are available in the PRE-OPERATIONAL state directly after initializa-
tion (if no modifications have been stored) and may be modified by means of dynamic
identifier distribution or SDO access (default way). A device has to provide the corre-
sponding identifiers only for the supported communication objects.
The pre-defined master/slave connection set supports one emergency object, one server
SDO, at maximum 4 Receive PDOs and 4 Transmit PDOs and the error control objects.
The COB-ID is built from a function code, representing the object type, and the 7 bit
module or node-ID. Table 12 shows a simplified version of what you can find in
CiA-301.
A device profile defines a standard device. For these standard devices a basic functionali-
ty has been specified, which has to exhibit every device within a class. The CANopen
Device Profiles ensure a minimum of identical behavior for a kind of devices.
The layers of a device profile is shown in figure 7.
1 The table has to be seen from the devices point of view.
Modes of Operation
CAN
Each device has to fulfill the requirements on the behavior i.e. the implemented applica-
tion state machine. Further it has to support all mandatory objects. These objects are
parameter and data for the device. Additionally the manufacturer can decide about sup-
ported optional objects. All parameters and data, which are not covered by the standard-
ized device profiles can be realized as manufacturer specific objects (2000h - 5FFF h ).
The constantly growing list of actual available profiles can always be found at port’s web-
page.
Implementation of these device profiles can be done very easy by using the CANopen
Design Tool. That tool provides databases with all objects for many of the standardized
device profiles. Furthermore source code for realizing the CiA-401 and other functions
are available.
Implementation of missing device profiles can be done very easy by using the CANopen
Design Tool as data entry tool.
The CANopen Library is offered at different configuration levels. All configuration lev-
els are built upon one another. The functionality of the lower level is contained in the
higher one.
Line n
standard CANopen services
Line 1
Line 1
minimum CANopen services
Driver Package
Not all services can be divided into master and slave services. Therefore some services
are contained in the master and in the slave version.
The handling of services is the same for master and slave, so that a master can contain
also slave functionalities. This means that a device, which is conceived as an I/O device
can provide NMT master services in the network at the same time.
Table 13 shows the service attributes supported in the various configuration levels of the
CANopen Library.
The CANopen Library is only one component in the design flow of the CANopen system
development. The development of CANopen systems consists of the two tasks, imple-
mentation and integration. In the context of the CANopen Library the implementation
task must always be done.
Implementation Tasks Integration Tasks
Design Tool
If the target system is not yet available i.e. hardware is still under development, a cross
development can be done. For that purpose a host development environment, using Win-
dows™ or Linux has been developed. Under this system the whole application can be
written without any hardware dependence. If no Linux system is available a common
4 For detailed information see User Manual CANopen Design Tool.
CANopen Device
5 The CANopen LINUX Starter Kit can be offered for that purpose.
The structure of the CANopen Library is shown in figure 11. The CANopen Library con-
sists of a hardware-dependent and an hardware-independent section. The two sections
are coupled together by message buffers (CAN receive and CAN transmit buffer).
hardware dependent
CANopen Driver Package Timer
Interrupt-
handling
2
CAN Driver
1 Object Dictionary
Global Flags
CANopen Service
Definitions
The object dictionary is the data interface between the user’s application and the
CANopen Library. It contains all variables that are necessary for the CANopen services
and the application-specific variables that should be accessible over the network.
The implementation of the object dictionary by port consists of an array of element head-
ers for each used index (figure 13).
...
Number of Number of
variable entries variable entries
Pointer to Pointer to
Variable Element 1 Variable Element 1
Variable Variable
Description of ...
Variable Element 2
Variable Element n
...
Description of
Variable Element n
The description for each variable is an C-language record. It contains entries for the
value ranges, the default value, the size, read/write permission flags, numeric and domain
identification and PDO mapping permission.
With the multi CAN line version an object dictionary is available at each line. In this
case all object dictionaries will be managed by an object dictionary manager. This man-
ager is an array of pointers to the implemented object dictionaries (figure 15).
...
It is possible to define an interface for one’s own variables, structures and arrays. The
index is the logical reference to one of these data containers. The elements of structures
and arrays are reached via the sub-index. For simple variables the sub-index is always 0.
If the size of the structures or arrays is bigger than 255 bytes (limit of sub-index), the user
must split them. This means more than one index is needed to describe the struc-
ture/array within the object dictionary. The type LIST_ELEMENT_T is the element
header. An array of this type, sorted by the index, is the object dictionary. The descrip-
tion of the variables is an array of the type VALUE_DESC_T. Each array entry describes
the properties of the corresponding sub-index.
typedef struct
{
UNSIGNED8 *pObj;
VALUE_DESC_T *pValDesc;
UNSIGNED16 index;
UNSIGNED8 numOfElem;
#ifdef CO_CONFIG_ENABLE_OBJ_CALLBACK
CO_OBJ_CB_T pObjCallback; /* obj function pointer */
#endif /* CO_CONFIG_ENABLE_OBJ_CALLBACK */
} LIST_ELEMENT_T;
typedef struct
{
UNSIGNED8 *pDefaultVal;
#ifdef CONFIG_LIMITS_CHECK
LIMIT_U8_T *pLimits;
#endif
UNSIGNED8 varType;
UNSIGNED16 attribute;
} VALUE_DESC_T;
Name Description
pDefaultVal pointer to the default value of the variable, it will be used to ini-
tialize the variable after a reset (hard reset or communication
reset)
it depends on the variable type (see varType)
pLimits pointer to the lower and upper limits of the variable value
it depends on the variable type (see varType)
varType type of variable (table below)
attribute attributes of value (table below)
Table 15, Variable’s Properties Description
The pointers to the default value and to the limit structure are always pointers to the real
data type of the variable and must be casted at VALUE_DESC_T type.
The CANopen Library does not interpret float values except if limit check is enabled.
Please ensure that the initialization values are in the right order.
The CANopen Library can be used for many different hardware and compiler platforms.
Furthermore the CANopen Library can be configured to reduce code size and run faster.
Due to the complexity of this process, the interactive is available for both Microsoft Win-
dows and UNIX-machines® to support the creation of the configuration file cal_conf.h.
The entries of the file cal_conf.h determine the kind of compilation. All configuration
compiler-define-directives used in that file have the prefix CONFIG_.
The user can compile the CANopen Library code for a CANopen network master or for a
slave application.
For the multi-line version the number of CAN lines can be configured. Additionally the
multi-line functionality can be switched off. This means all functions do not use the line
select function parameter canLine. In this way the CANopen Library can be used for sin-
gle line systems additionally without the multi line overhead.
Furthermore it is possible to reduce the code size by selecting parts of the code by com-
piler #define directives. Every CANopen service can additionally be separated into
client/consumer or into server/producer functionality. If the user needs only one func-
tionality, he only has to define one of these e.g. CONFIG_SDO_SERVER.
Furthermore the size of the CAN message buffer can be adjusted and the usage of Full-
CAN properties in hardware can be enabled, if the CAN controller is a Full-CAN type.
For compilers (processors) which do not support a byte alignment of data in the memory,
an alignment definition CONFIG_ALIGNMENT has to be set in order to ensure a correct
access to structures and arrays of the object dictionary.
➥ For a detailed description of the compiler #defines see Appendix 4.
Please never edit the cal_conf.h by hand !
Some entries at the object dictionary are of type UNSIGNED64. At the moment, not all
compilers provide this data type. In this case a special type can be used.
typedef struct {
char val[8];
} UNSIGNED64;
The initialization in this case is done by the following macro:
#define SET_U64(b1, b2, b3, b4, b5, b6, b7, b8) \
{ b8, b7, b6, b5, b4, b3, b2, b1 };
For all compilers providing this data type the initialization is done by:
#define SET_U64(b1, b2, b3, b4, b5, b6, b7, b8) \
{ b1<<56|b2<<48|b3<<40|b4<<32|b5<<24|b6<<16|b7<<8|b8 };
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.
The picture below illustrates the naming scheme for functions that use CANopen ser-
vices.
Client/Producer Ser ver/Consumer
Request Indication
Confirmation Response
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 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(), writePdoReq(),...).
The second kind of requests result in a response or confirmation from another node in the
network. Here the request can only be instructed e.g. readSdoReq(), readPdoReq(),...
because an interaction with another node in the network is necessary. The application can
determine the completion of the request, e.g. the reception of a response, using the confir-
mation 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, among other things, also on the current bus load.
With the reception of certain CAN messages, error conditions (e.g. Heartbeat message is
missing, Timeout occurred) and other events (e.g. completed request) the user is informed
by the CANopen Library by indication or confirmation functions also referred to as call-
back -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 indica-
tion and "Con" e.g. sdoRdCon() as abbreviation for confirmation. The function prefixes
of the indication and confirmation have the same meaning as in the request interface
description.
The receive principle for the service indication/confirmation is shown in figure 17.
Service Indication
CAN Message
Service Confirmation
SYNC Indication
If a function listed above is called a message was received or an event had occurred. The
corresponding values in the object dictionary had been updated before the call. Some of
the functions require certain conditions to be met. These conditions are described in the
following chapters.
Most of the CANopen service functions use predefined COB-identifiers for communica-
tion. These predefined COB-identifiers are determined on the basis of the own node-ID.
For high flexibility the CANopen Library uses a function to determine the node-ID.
Within the function getNodeId() the user determines the node-ID, e.g. by reading out
some DIP switches. The CANopen Library calls this function once from initCANopen()
and once from the resetCommInd() function.
The CANopen Library uses an internal timer concept that can be used for application spe-
cific purposes, too. As a basis a hardware timer is used. It is included by the driver and
increments a variable in an 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 0xffff * length or 0xffffffff * 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 struc-
ture has to be provided of 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. After the time has run out the indication function userTimerEvent() is
called, in which the user can specify further actions. Furthermore it is possible to use the
timer as a cyclic timer. The following functions provide the programming interface to the
timer.
Name Function
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 19, Timer Functions
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 remove-
TimerEvent() can be called. All timer functions expect as first parameter a pointer to the
data structure of the timer. This structure has to be provided as static data from the call-
ing function. The structures are modified by the timer functions. Therefore the user pro-
gram must not alter the data of the static timer structures.
The second parameter specified the timer interval in 1/10 of msec. And the third parame-
ter is the timer type. For application specific timers it should be set to
CO_TIMER_TYPE_USERSPEC. For cyclic timers additional the attribute
CO_TIMER_TYPE_CYCLIC has to be set.
...
SDO transfers are always 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 the servers
object dictionary. 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 it can be a server, client or both.
There are three different transfer modes possible: Expedited Transfer, Segmented Trans-
fer and Block Transfer. The CANopen Library selects automatically the best mode for
each transfer.
If the node permits the access to its own object dictionary, it must 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 should have access to its object
dictionary. If the node wants to access the object dictionary of other nodes it has to ini-
tialize a
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() (List-
ing 2).
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
should be set and validated using the function setCobId() (Listing 2).
4.6.1. SDO-Server
The SDO server permits access to the own 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 should 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 own object dictionary are
indicated by the sdoRdInd() and sdoWrInd() functions.
A read access from any other node in the network to the own object dictionary is indi-
cated 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 is sent
back to the originator (the read service requester).
Error codes are generated automatically by the CANopen Library, see appendix 5.
RET_T sdoRdInd(
UNSIGNED16 index, /* index to object */
UNSIGNED8 subIndex /* index to object */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /* number of CAN line 0..CONFIG_MULT_LINES-1 */
#endif
)
{
/* increment the counter before send back the value */
actual_u32++;
return(CO_OK);
}
A write access to the own object dictionary is indicated by the function sdoWrInd() (fig-
ure 18).
SDO Write SDO Response SDO Response
Indication Error Success
n
limits and attribut
OK?
testSdoValue() n
OK ?
sdoWrInd() n y
RetValue = RetValue =
Split Indication ? OK?
finish
sdoInd
RET_T sdoWrInd(
UNSIGNED16 index, /* index to object */
UNSIGNED8 subIndex /* sub-index to object */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /* number of CAN line 0..CONFIG_MULT_LINES-1 */
#endif
)
{
actual_u32++;
/* Look if index 0x2000 = setpoint */
if ((index == 0x2000) && (subIndex == 0)) {
actual_u32 = setpoint_u32;
}
return(CO_OK);
}
4.6.2. 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 s are disabled by
default. To enable these SDOs the COB-IDs must be set according to the server COB-
IDs - which should be contacted - with setCobId() (Listing 2).
Read and write access to the object dictionary of another node is started with readSdo-
Req() 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 transmis-
sion 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 suc-
cessful transmission. It means only that the transfer is initiated by saving the first data
...
default:
printf("Error: abort dom transfer reason %lX", errorFlag);
break;
}
}
If an SDO server does not respond to the request from the SDO client within a deter-
mined period of time the SDO client can abort the transfer with an Abort Domain
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 indi-
cation function sdoRdCon() or sdoWrCon() about this event.
A domain in CANopen is unstructured data, which can have a size up to 232 bytes.
Domains can be whole application programs or large data structures, e.g. pictures. The
application is always responsible for the interpretation of the domain content.
Domains can only be transferred by SDO. In order to handle such large data some excep-
tions to the common CANopen objects are necessary. All objects with domain entries
have the type DOMAIN_T. This type is a pointer to void and is initialized with NULL
in objects.h generated by the CANopen Design Tool. The data type DOMAIN_T is a
basic data type and can be used as variable, in arrays and in records.
DOMAIN_T man_domain_var = { NULL };
DOMAIN_FIELD2_T man_domain_array = { 0x2, { NULL, NULL }};
DOMAIN_DATA_T domain_data[] = { 0, 0, 0 };
UNSIGNED8 defaultVal_U8 = { 2 };
VALUE_DESC_T man_updown_domain_desc[1] = {
{ (UNSIGNED8 *)&domain_data[0],
CO_TYPEDESC_DOMAIN,
CO_READ_PERM | CO_WRITE_PERM }
};
VALUE_DESC_T test_desc[3] = {
{ &defaultVal_U8[0],
CO_TYPEDESC_UNSIGNED8
CO_READ_PERM | CO_WRITE_PERM | CO_NUM_VAL },
{ (UNSIGNED8 *)&domain_data[1],
CO_TYPEDESC_DOMAIN,
CO_READ_PERM | CO_WRITE_PERM },
{ (UNSIGNED8 *)&domain_data[2],
CO_TYPEDESC_DOMAIN,
CO_READ_PERM | CO_WRITE_PERM }
};
main()
{
/* assign address space to domain from objects.h with
* index DOMAIN_INDEX and sub-index DOMAIN_SUB */
In order to manage remote data area from a node, some functions have been introduced
for manipulating the start address and the domain size. This is useful for building ring
buffers and other segmented buffer structures e.g. for drive interpolation data. Further-
more certain segments of a domain can be uploaded e.g. for program debugging.
The manipulation functions are listed below:
• setDomainAddr()
• getDomainAddr()
• setDomainSize()
• getDomainSize()
Listing 8, Functions for Manipulating Domain Variables
Domain transfers can be started by normal 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 indication function
after a defined block of transferred data is necessary, because the receive buffer is not
large enough or the data should 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 pas-
sive part. Therefore the indication size for the SDO server must be setup at compile time.
It can be done by the CANopen Design Tool. 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.
RET_T sdoDomainInd(
UNSIGNED8 *pData, /**< pointer the domain buffer */
UNSIGNED32 actSize, /**< number of Bytes to flash */
UNSIGNED8 overSize /**< number of Bytes to buffer */
)
{
/* temporary flash buffer */
UNSIGNED8 flashBuffer[CONFIG_DOMAIN_INDICATION_SIZE];
/* flash data */
return(CO_OK);
}
/* flash data */
return(CO_OK);
}
switch(index) {
case 0x1f50:
case 0x1f51:
if ((subIndex == 1) && (p301_prog_control[1] == 1)) {
firmware_prog();
}
if ((subIndex == 2) && (p301_prog_control[2] == 1)) {
load_config();
}
break;
}
return CO_OK;
switch(cmd) {
// .....
case CMD_SDO_WRITE:
sdoConError = 0xff;
if (writeSdoReq(sdo,index,subIndex,pBuf,size) != CO_OK) {
printout("-- error writeSdoReq(sdo %d, index 0x%x..)\n",
sdo, index);
return 1;
}
/* wait for finished sdo transfer
* the variable sdoConErr can be set in sdoWrCon()
*/
while (sdoConError == 0xff);
if (sdoConError == 0) {
printout("OK\n");
return(0);
} else {
return 1;
}
break;
// .....
}
}
SDO transfers are based on the client-server model with a handshake after each transfer.
For a larger block of data this will take a large amount of time. Therefore a new SDO
mode has been defined. It is called SDO block transfer.
Using the block transfer a sequence of blocks can be transmitted without a large overhead
of handshake each 8 bytes. Each block is a sequence of up to 127 segments (e.g. CAN
telegrams) containing only a sequence number and the data.
Each block transfer starts with an initialization phase, where the server and the 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 client and server can
For configuration tools, analysis tools or HMIs with very intelligent configuration set-up
it can be necessary to have several SDO connections to different nodes from time to time
in the network. Therefore dynamic SDO connections can be used.
The SDO Manager manages all SDO connections in the network. It can dynamically
establish new connections between SRDs (SDO Requesting Device) and a slave (SDO
server). Therefore it has an SDO connection table where all established connections are
stored.
For each dynamic SDO connection an unused COB-ID from the system is necessary. The
SDO Manager also requires information about the COB-IDs that are free in the system.
This is configured in the SDO Manager’s COB-ID table.
Before an SRD can request dynamic SDO connections it has to be registered at the SDO
Manager. This is done with the service "Dynamic SDO Request". If the SDO Manager
has received such a request, it scans all nodes for the requested device by reading the
object dictionary for all non registered devices. If it has found the requested node a con-
nection between the SDO Manager as server and the SRD as client is established. After
that an error control mechanism (Node Guarding or Heartbeat) between the SDO Man-
ager and the SRD is started. If the error control mechanism fails at any time all
6 CANopen Design Tool Light is delivered with the CANopen Library.
SDO connections are always connections between one server and one client. If more
than one node should be connected to another node the connection can not be static.
When using dynamic SDOs a node has to be an SDO Requester. Each SRD (SDO
PDOs serve for transferring real time data without overhead. Contents of the data which
should be transmitted must be determined before - this is called mapping. The mapping
can be set at compile time (static mapping) or at run time (dynamic mapping).
With dynamic mapping, memory is reserved for the maximum mapping by the initializa-
tion.
The mapping can take place bit-wise or byte-wise. The bit-wise mapping is necessary for
variables unequal to 8, 16 or 32 bit (i.e. bit variables) and without holes at the CAN trans-
mission. If variables are to be mapped bit-wise, the define CONFIG_BIT_ENCODING
must be set. This requires, however, larger code blocks and a longer processing time for
PDO than the byte-wise mapping.
Before usage all PDOs must be defined. A maximum of 512 Receive PDOs and 512
Transmit PDOs with a maximum mapping of 64 entries for each direction are possible.
Initialization is done with the function definePdo() (Listing 13).
definePdo(5, CONSUMER, CO_FALSE); // define PDO 5 as consumer
/* deactivate mapping */
mapCnt = 0;
putObj(0x1600, 0, &mapCnt, 1, CO_TRUE); // set value to object dict.
setCommPar(0x1600, 0); // set internal values
/* validate mapping */
mapCnt = 2; // two mapping entries
putObj(0x1600, 0, &mapCnt, 1, CO_TRUE); // set value to object dict.
setCommPar(0x1600, 0); // set internal values
/* enable pdo */
setCobId(0x1400, 1, 0x220); // set cob-id
PDOs are transmitted with high priority. To avoid blocking of the CAN communication
by high priority PDOs an inhibit time parameter can be defined. The inhibit time is a
minimum time between the 2 consecutive transmissions of a PDO. If the inhibit time has
not elapsed yet, the function writePdoReq() returns an error code. The application can try
to send it later or is waiting until the inhibit time is elapsed (Listing 16).
do
{
ret = writePdoReq(1);
FlushMBox(); // do other CANopen tasks
} while (ret == CO_E_INHIBITED)
Of course, this loop should not block the whole application. Please consider that the
inhibit time can be set via network from a configuration tool and is therefore not deter-
mined by the application. It can last more than 6 sec as maximum.
7 Please refer to the document CiA-AN802 - "CANopen statement on the use of RTR-messages" for use of
RTR messages.
PDO with n
dynamic Mapping ?
getMapObjAdr()
== y
User Reaction
address of trigger
variable ?
End
If the application has a lot of data with the same properties a special PDO type can be
used. It is called a Multiplexed PDO (MPDO). MPDOs transmit with every CAN mes-
sage the index and the sub-index of the given data. Therefore the maximum data length
can be 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(). For writing MPDOs the func-
tion writeMPdoReq() has to be used. For the MPDO destination addressing mode the
parameter node is not necessary and should 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 min-
imum 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 analy-
zing the CAN messages.
MPDO MPDO
Producer Consumer(s)
0 1 3 4 8
request indication(s)
Sub
Node Index Data Object
Index
8 Byte
4.7.1.1.1.
Entries in the object dictionary:
Index Sub-Index Description Value
18xx h communication parameter
1 Axx h 0 number of mapping entries 255
1 Axx h 1 mapping entry application specific
Table 24, Objects for an in Destination Address Mode
Function:
writeMPdoReq( pdoNumber, dest.-node, dest.-index, dest.-subIndex)
4.7.1.1.2.
Entries in the object dictionary:
Index Sub-Index Description Value
14xx h communication parameter
16xx h 0 number of mapping entries 255
Table 25, Objects for an in Destination Address Mode
If an MPDO was received, the data will have been written into the received index and
sub-index.
MPDO MPDO
Producer Consumer(s)
0 1 3 4 8
request indication(s)
Src Sub
Src-Index Data Object
Node Index
8 Byte
4.7.1.2.1.
Entries in the object dictionary:
Index Sub-Index Description Value
18xx h communication parameter
18xx h 2 transmission type 254 or 255
1 Axx h 0 number of mapping entries 254
1FA0h − 1FCF h 0-254 object scanner list
Table 26, Objects for an in Source Address Mode
The producer uses an object scanner list to configure which objects have to be sent.
Each scanner list entry has the following format:
MSB LSB
31-24 23-8 7-0
Block Size Index Sub-Index
Table 27, Entry in Scanner List
Each table entry describes an object that can be sent via MPDO. It is possible to describe
consecutive sub-indexes by setting the parameter block size to the number of sub-indexes.
Function:
writeMPdoReq( pdoNumber, 0, src-index, src-subIndex)
Only one producer MPDO of this type is allowed for each node.
4.7.1.2.2.
Entries in the object dictionary:
4.8. Emergency
Emergency messages serve for transmitting and receiving error messages. The initializa-
tion can take place for one producer and up to 127 consumer. The function defineEmcy()
with the appropriate parameter initializes the emergency service for producer or con-
sumer. If the emergency 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 emer-
gency consumers can be added by the function setEmcyConsumerCobId().
// consumer
retVal = defineEmcy(CONSUMER);
// add node 35
retVal = setEmcyConsumerCobId(35, 0x1a3);
manuErr[0] = 0x1;
manuErr[1] = 0x2;
manuErr[2] = 0x3;
manuErr[3] = 0x4;
manuErr[4] = 0x5;
The SYNC telegram 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 initial-
ization of the function defineSync() or by setting the appropriate bit at index 1005h .
Additionally, the SYNC cycle time has to be set for the SYNC producer in the object dic-
tionary and the internal structures have to be updated with the function setCommPar().
// define sync producer
retVal = defineSync(PRODUCER);
// start sync
startSyncReq();
syncPreCommand()
syncCommand()
4.10. Error-Control-Mechanisms
CANopen defines two error control mechanisms. These mechanisms are called Node
Guarding and Heartbeat. Each node has to provide at least one service. Even if both ser-
vices are implemented guarding has to be done with only one service. Sending of guard-
ing messages and guarding of other nodes with the Heartbeat service is possible for mas-
ter and slave devices. Guarding with the Node Guarding service is possible as NMT mas-
ter device. Only services that have been initialized can be used.
// init node only for heartbeat usage
createNodeReq(CO_FALSE, CO_TRUE);
The Node Guarding protocol is based on a master slave relationship. The master requests
the current state of the slave cyclically with an RTR telegram. The slave answers this
telegram with its state and an additional toggle bit. The Node Guarding is started on the
master with the function startNodeGuardReq() and operates independently in the back-
ground. If the RTR telegram is not answered by the slave within the inquiry cycle, the
function mGuardErrInd() (Listing 23) with the parameter CO_LOST_GUARD-
ING_MSG is called. If the slave does not transmit responses according to adjusted life-
time factor, the guarding becomes inactive and the user is informed by the function
mGuardErrInd() (Listing 23) and the parameter CO_LOST_CONNECTION (Listing
24).
void mGuardErrorInd(
UNSIGNED8 nodeId, /* Node-Id of error source */
ERROR_SPEC_T kind /* kind of error */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /* number of CAN line
0..CONFIG_MULT_LINES-1 */
#endif
)
{
switch(kind) {
case CO_LOST_GUARDING_MSG:
printf("LOST_GUARDING_MSG node %u\n",(unsigned int)nodeId);
break;
case CO_LOST_CONNECTION:
printf("LOST_CONNECTION node %u\n",(unsigned int)nodeId);
break;
case CO_LOST_HEARTBEAT:
printf("LOST_HEARTBEAT node %u\n",(unsigned int)nodeId);
break;
case CO_HB_STARTED:
printf("HB_STARTED node %u\n",(unsigned int)nodeId);
break;
case CO_BOOT_UP:
printf("BOOT_UP node %u\n",(unsigned int)nodeId);
break;
}
}
UNSIGNED8 sGuardErrorInd(
ERROR_SPEC_T kind /* kind of error */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /* number of CAN line
0..CONFIG_MULT_LINES-1 */
#endif
)
{
switch(kind) {
case CO_LOST_GUARDING_MSG:
return 0;
case CO_LOST_CONNECTION:
return 1;
default:
return 0;
}
}
4.10.2. Heartbeat
The Heartbeat service allows each node to monitor every other node in the network.
Each Heartbeat producer transmits cyclically its own Heartbeat (Heartbeat producer).
The monitoring can now take place from one or more nodes (Heartbeat consumer). Each
node can be simultaneously producer and consumer.
The Heartbeat producer starts the cyclic transmission of its own Heartbeat message
immediately if the entry in the object directory 1017h is greater than 0. The Heartbeat
consumer starts the monitoring automatically after the reception of the first Heartbeat
Furthermore there is the function newStateInd(). This function informs the user applica-
tion about each transition of the communication state machine. This information can be
important, because a few communication services are not available in certain states. For
example, the application transmits error codes via PDO and the master forces the node to
PRE-OPERATIONAL. Then PDOs are not allowed.
If the device can not change to the state OPERATIONAL it can signal this by the return
value. In this case the node stays in the current state.
The reset behavior is a property only for slaves. Each slave can receive a Reset Applica-
tion or a Reset Communication command from the master. The module nmtslave.c con-
tains function templates for resetApplInd() and resetCommInd(). Within these functions
an individual reset of the application data and states can be carried out. In the function
for the communication reset the device can change the CAN bit rate (only for single
device networks) or the node-ID.
The flying master principle was original specified for maritime applications in the stan-
dard CiA-307. Now some more services are defined, they can be performed only from
one node in the network. In most cases the CANopen master has to realize this function-
ality. A loss of the CANopen master can be fatal for the whole network.
For this reason the flying master principle was moved to the CiA-302 as a common ser-
vice.
The flying master principle is based on Heartbeat monitoring of all master capable
devices in the network. If the active master fails a new negotiation is started automati-
cally, depending on a priority of nodes and the node number of the master capable
devices. The master negotiation is won by the node with the highest priority (prior = 0)
and the lowest node-ID.) The active master monitors the network cyclically for other
active masters and starts a new master negotiation if necessary.
All Flying Master devices have to implement index 1F80h where bit 0 and 5 is set. Oth-
erwise they can not participate in the master negotiation process.
Detection of active
CANopen master Send ResetComm
y n
y master Id
received ?
n Priority of active
Force Flying Master Negotiation master > own priority send own master id
L=0
COB-ID = 71h
indication(s) response
Priority Node-Id
0 1 2 Only the
active master
0 1 2 indication
Priority Node-Id
COB-ID = 71h
0 1 2
Priority Node-Id
COB-ID = 2041
0 1 2
Priority Node-Id
COB-ID = 2041
Reset Start MID MID MID MID MID MID MID MID MID
Comm. Trigger Node Node Node Node Node Node Node Node Node
Timeslot 1 2 127 1 2 127 1 2 127
time
- The active CANopen master cyclically asks for other active masters. When the mas-
ter receives a reply a new master negotiation is forced.
L=0
L=0
0 1 2
indication(s) Priority response
Level Node ID
COB-ID = 74h
Function Description
defineFlyingMaster() Flying Master initialization
startFlyingMaster() start Flying Master usage
detectMasterReq() Detecting Master Capable Devices
activeMasterReq() Detection of a active system master
forceCommResetReq() force Communication Reset from active master
flyingMasterInd() indication function for Flying Master events
Table 30 , API for the Flying Master Functionality
The redundant communication is designed to fulfill the requirements of high reliable sys-
tems (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 con-
nected only to one line.
The redundant communication is described in CiA-302.
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 func-
tion redundancyInd(). Within this function the user application can avert the automatic
line switch by returning with a special return code.
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.
3 HB of all y
redundant devices
received ?
n
set default line y
as active set default line as active
received ?
n
y
Timer ellapsed ?
n
Figure 30, Program Flow after Boot-up
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.
n y
set redundant line y
as active set redundant line as active
received ?
n
Figure 31, Program Flow when Default CAN Line 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.
3 HB of all y redcyInd n
redundant devices switching ok ?
received ?
n y
Message transmission depends on the used service, the active CAN line and the actual
communication state of this line:
Transmission of PDOs is monitored by the producer to avoid transmission of too old mes-
sages (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 Heart-
beat is stopped until the error counter is decremented to 0.
For each event detected by the redundant communication layer the user indication func-
tion 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 32, Parameter Values for redundancyInd()
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 reac-
tions are supposed:
Every device needs some configuration data either for communication or application spe-
cific 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.
Boot-up ResetComm
Save Parameter
(write to object 0x1010)
getNodeId() getNodeId()
saveParameterInd()
clearParameterInd()
resetCommInd()
CANopen addressing depends on a node-ID (1-127). Normally the node-ID is setup via
DIP switches or rotary switches. Some devices can not provide DIP switches because
they are completely sealed to be used in chemical applications or underwater. With the
means of the Layer Setting Services CANopen devices can be identified and configured
without external DIP switches. LSS services differentiate between and devices. In
order to use LSS services it has to be initialized with a call to the function
defineLss(kind).
LSS
CONFIGURATION
LSS
WAITING
Switching into the CONFIGURATION mode can be carried out independently of the cur-
rent NMT state. If the node-ID was set and the device is set to WAITING mode again the
CANopen Library will automatically call Reset Communication to verify the new COB-
IDs for the Predefined Connection Set.
Communication is always started by the , except for the Identify Non Configured Mode
command, that can be issued by a , too, without order of the . This can happen when no
valid node-ID was found. The sends its commands always with COB-ID 2021. After
completion of a command the function
lssMasterCon(mode, parameter_1, parameter_2)
is called.
s always respond with COB-ID 2020. After reception of new parameters, like node-ID or
bit rate, the function
lssSlaveInd(mode, parameter_1, parameter_2);
is called.
cmd data
COB-Id 2021
0 1 8
cmd data
COB-Id 2020
Globally switching from WAITING mode into CONFIGURATION mode is done uncon-
firmed with a single command. Switching a single node into the opposite mode requires
sending the vendor-ID, product code, revision number and serial number of the desired
device by the . If the slave exists in the CANopen network it responds to this request.
The programming interface for globally switching or selectively switching is the same.
lssSwitchMode(mode, vendor, product, revision, snr);
Parameter Description
mode LSS_CONFIG_MODE, LSS_WAITING_MODE
vendor 0 - global, != 0 vendor-ID; 1018h sub 1
product product number; 1018h sub 2
revision revision number; 1018h sub 3
snr serial number; 1018h sub 4
Table 34, Parameter lssSwitchMode
LSS provides the configuration of the devices’ node-ID and bit-timing without use of DIP
switches or SDO transfer. The has to confirm the reception of the new parameter. On
the the function
lssSlaveInd(mode, parameter_1, parameter_2);
is called on reception of a new parameter. Within this function the user can influence the
return value within the LSS response.
Prior to this the node has to be set into configuration mode with the function writeLssS-
witchModeReq(). Activation of the new node-ID takes place during the transition from
CONFIGURATION to WAITING mode. This is done with a call to the function "Reset
Communication".
Setting the bit-timings is done with a bit-timing table. This mechanism provides the pos-
sibility to use manufacturer specific timings. This bit-timing table has to be created by
the programmer. The default bit-timing table of CANopen is supported.
writeLssConfigBitrateReq(table, tableIndex);
Parameter Description
0 standard bit-timing table
1..127 reserved
128..255 manufacturer specific bit-timing table
Table 35, Parameter writeLssConfigBitrateReq
After changing the bit-timing it is only allowed to use LSS for configuring the bit-timing,
activate bit-timing and switch to another mode.
Index Bit Rate
0 1000 kbit/s
1 800 kbit/s
2 500 kbit/s
3 250 kbit/s
4 125 kbit/s
5 100 kbit/s
6 50 kbit/s
7 20 kbit/s
8 10 kbit/s
Table 36, Default Bit-Timings
On LSS slaves the steps for bit rate changing are indicated by the function
lssSlaveInd(mode, parameter_1, parameter_2);
Inquiry services are used to find nodes in a CANopen network or to select nodes. For this
all data of the object 1018h of the are requested. Every , that matches the requested data
responds to the . With this method the can determine which slaves are connected to the
network. If there is at least one node with the requested data, then the master is informed
with the function lssMasterCon(). All data is requested with the same function.
writeLssInquiryReq(mode);
Mode Description
LSS_VENDOR search for vendor-ID
LSS_PRODUCT search for product code
LSS_REVISION search for revision number
LSS_SNR search for serial number
LSS_NODEID search for node-ID
Table 37, Parameter writeLssInquiryReq ()
The master can request all data of object 1018h to identify a single node. By requesting
particular ranges the exact data of nodes can be determined. With the function
lssIdentify(vendor, product, rev_low, rev_high, snr_low, snr_high);
FastScan service can reduce the time of a network scan for the following reasons:
- master sends only one instead of six remote identification messages
- it is possible to identify devices although skipping LSS numbers, e.g. the serial
number may be ignored
- it is possible to identify vendor-id and product code
The fastScan service can be started by the LSS master by calling the function
writeLssFastScanReq(vendor, product, revision, snr);
The parameters vendor, product, revision and snr are 32 bit coded values, indicating the
relevant bits for the fastScan compare with LSS slaves. All not used bits (reset bits) for
vendor, product, revision and snr have to be zero at the LSS slaves identification object.
The fastScan service detects only one LSS slave for each cycle. It is always finished by
the
lssMasterCon(mode, par1, par2)
For safety critical communication Safety Relevant Data Objects (SRDO) are used, that
are mapped similar as PDOs. SRDOs are sent periodically. To increase safety, the data
of an SRDO is transmitted twice. The second time the data is sent inverted. All SRDOs
have their own COB-ID.
4.16.2. Implementation
All SRDO communication parameters are stored in the object dictionary. The CANopen
Library ensures that no safety relevant data is changed during OPERATIONAL state.
Therefore access to this data is allowed only in state PRE-OPERATIONAL. Every
access to SRDO communication data resets the configuration of SRDO. Then 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.
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.
Before sending SRDOs the CAN message has to be assembled according to the mapping.
The user can use the function mapSrdo() to realize this.
When a SRDO should be sent the CANopen Library calls mapSrdo() and transmits the
user assembled CAN message afterwards.
The function writeSrdoReq() sends an additional SRDO if it is necessary to do so.
After reception of an SRDO the CANopen Library calls srdoInd() where the data can be
processed. The user has to check for integrity of the data, i.e. comparison of not inverted
and inverted data, and for the adherence of timing restrictions. The following has to be
checked:
- CAN message in correct order
SRDO Indication
y
TimeOut ?
y n
message 1 last message
received ? = message 2
n y
n
last message
= message 1
time between n
message 1 and 2
ok ?
data valid
save at OD
return Error
Problems:
- execution time of indication function
- priority distribution on the bus (SRDO1 received, then reception of higher priority
SRDO, then SRDO2)
Ok
TimeOut Indication
TimeOut Indication
TimeOut Indication
The CiA-303-3 provides a standardized way for state indication of a CANopen device.
There is an error LED and a run LED. It is also possible to use only one of the two LEDs
or instead of two single color LEDs a bicolor LED.
The run LED is green and indicates the CANopen state. The error LED is red and shows
errors of the physical layer.
(*) Should be optional, if there are CAN controllers available which do not indicate the
warning level.
(**) Not supported
4.17.1. Implementation
The LED functionality was implemented in the CANopen Library module led.c. The
calls internal functions on occurrence of an error or event. Switching the LED on or off
has to be done in the indication function
ledInd (led, action)
in module usr_303.c.
The CANopen LED can be activated with the CANopen Design Tool. LED functionality
is controlled with the compiler directives:
Define Description
CONFIG_CO_LED activate led.c module
CONFIG_CO_RUN_LED RUN LED is present
CONFIG_CO_ERR_LED ERR LED is present
CONFIG_CO_BOTH_LED both LEDs are present
CONFIG_CO_BICOLOUR_LED bicolor LED is present
Table 41, Compiler Directives for CANopen LED
Normally all data have to be stored in the object dictionary of a device. However, for
special applications it may be necessary to support additional or temporarily available
objects besides the real objects. This objects are called virtual objects. Virtual objects
are entries in the object dictionary that are managed by the user and have no physical
entry in the object dictionary, i.e. have not been created with the CANopen Design Tool.
They are placed in the manufacturer segment of the object dictionary and can only be
accessed via SDO. Within the manufacturer segment virtual and real objects can be cre-
ated in any order. A virtual object can not be appended to a real object.
The user is responsible for checking the data, value ranges and providing the necessary
memory space.
In order to use virtual objects the compiler directive CONFIG_VIRTUAL_OBJECTS has
to be set. Access to real objects in the object dictionary is done via SDO access and fol-
lows the attributes specified. If an object can not be found in the object dictionary access
to a virtual object is assumed and the function getVirtualObjAddr() is called.
y object in
object dictionary
object in n
manufacturer area
getObjVirtualAddr()
(set pointer to virtual object data
and virtual object size)
continue
SDO work
user function n
testSdoValue()
returns
CO_OK ?
user function
sdoWrInd()
y
returns
CO_SDO_IND_BUSY ?
user function
sdoWrInd() n restore data from SDO Response
returns object address Abort
CO_OK ?
SDO Response
successful
call
finishSdoWrInd() n
with
CO_OK ?
user function
y sdoRdInd()
returns
CO_SDO_IND_BUSY ?
user function
sdoRdInd() y read data from SDO Response
returns object address with data
CO_OK ?
SDO Response
Abort
call
finishSdoRdInd() y
with
CO_OK ?
4.18.3. User-Functions
4.18.3.1. getVirtualObjAddr
The object specific callback function has the type CO_OBJ_CB_T , which is defined in
co_acces.h.
typedef RET_T (*CO_OBJ_CB_T)(UNSIGNED16 /*index*/,
UNSIGNED8 /*subIndex*/,
CO_OBJ_CB_TYPE_T
CO_COMMA_LINE_PARA_DECL);
So if the user wants to use its own callbacks, the prototype of the function has to look
something like this:
RET_T foo( UNSIGNED16 index, UNSIGNED8 subIndex,
CO_OBJ_CB_TYPE_T reason CO_COMMA_LINE_PARA_DECL );
If an callback is called the CANopen Library passes an parameter to the callback. With
this parameter the callback knows the service number and the reason for the call. The
type of this parameter is CO_OBJ_CB_TYPE_T and is descripted below.
typedef struct
{
UNSIGNED16 reason;
UNSIGNED16 serviceNbr;
}CO_OBJ_CB_TYPE_T;
The member serviceNbr contains the service number e.g. PDO number or SDO num-
ber. The member reason contains the reason why this callback is called. It could have
the following states:
CO_OBJ_CB_TYPE_PRE_SDO_READ
CO_OBJ_CB_TYPE_POST_SDO_READ
CO_OBJ_CB_TYPE_PRE_SDO_WRITE
CO_OBJ_CB_TYPE_POST_SDO_WRITE
CO_OBJ_CB_TYPE_PRE_PDO_READ
CO_OBJ_CB_TYPE_POST_PDO_READ
CO_OBJ_CB_TYPE_PRE_PDO_WRITE
CO_OBJ_CB_TYPE_POST_PDO_WRITE
If the application needs to set or reset an object callback at runtime the function setOb-
jFuncPtr can be used. The prototype of the function is descripted below.
RET_T setObjFuncPtr( UNSIGNED16 index, CO_OBJ_CB_T pNewFunc
CO_COMMA_LINE_PARA_DECL);
If the application wants to disable this callback, the new function pointer should be set to
NULL.
5. Driver Interface
This chapter describes the driver interface of the CANopen Library. It shows how to
build one’s own driver. The CANopen Library Target Driver Interface consists of two
modules. These are a CAN driver (can<x>.c) and a CPU- or RTOS driver (cpu<y>.c).
A driver module is necessary for using the CANopen Library. The user is responsible for
CANopen Application
Target Selector
The hardware abstraction layer (HAL) realization is shown in figure 43. The example
module main.c calls the HAL functions e.g. initCAN(). These functions are defined in
the target specific initialization file i.e. init_xc164.c. The functions from this file call the
functions from the driver modules i.e. can_twincan.c. The driver module uses a general
include file i.e. can_twincan.h, which contains all CAN controller specific constants.
The module examples.h which is delivered with the CANopen Library, is only necessary
to compile the examples from the delivery. It is not necessary for the end user project,
although some parts may be useful.
If a customized driver module is not available, the user has the option to design it himself.
A generic driver is available for a quick start. In this way the user can tailor the functions
to his specific hardware properties8.
8 Please have a look at the next chapters for programming one’s own drivers.
#define CONTROL_REG 0
drivers/shar_inc #define STATUS_REG 1
can_<controller_xy>.h
Hardware
access
#include <cal_conf.h>
#include <can_controller_xy.h>
Init_CAN(bitRate,address,output)
drivers/shar_src {
....
}
can_<controller_xy>.c
init_<target_xy>.c
#include co_drv.h
Application
main() #define CAN_ACCESS_IO_MAP
{
examples/s<xx> initCAN(125);
}
main.c cal_conf.h
The HAL is not necessary when only one target is supported by the user application. In
this case the driver functions can be called directly from the user’s main routine. The
driver modules used should be organized in the following manner (figure 44).
user’s application
Overwritten
canopen by
Update
drivers
shar_src
shar_inc
user’s target 1
user’s target n
A directory structure like this ensures that your driver will not be overwritten if a
CANopen Library update is installed. Additionally the user is able to make the adapta-
tions, which fit his needs best e.g. removal of unused functionality.
The following points give an overview of the driver requirements.
Figure 45 shows several CAN events to which the drivers has to react.
The driver has to process receive, transmit and error events on the CAN bus. These
events can be initiated by the CAN controller or system messages from an operating sys-
tem driver. The timer interrupt is responsible for updating the internal time base. It is
used for all time based services, like Heartbeat, Node Guarding, synchronous services,
for inhibit time and timeout checks. The reaction to the events mentioned above are
shown in figure 45. Each event sets a global flag when it is triggered. These flags are
evaluated by the CANopen Library. No CANopen Library function is called directly by
the driver. This means the CANopen Library has to be called cyclically in the main loop.
➥ All driver functions are part of the user application. Only a few functions are called
directly by the CANopen Library. The interface between the CANopen Library and
the driver can not be changed. Its functions are described in the following para-
graphs.
The prepared driver structure is shown in figure 46. It consists of a hardware independent
and a hardware dependent part. Hardware independent are the receive (RX) and transmit
(TX) buffers and their access mechanism. All of these functions are coded in
drivers/shar_src/cdriver.c.
Define_COB()
COB List
definePdo() Set_COB_ID()
TX INT
Transmit_COB()
writePdoReq() TX Buffer CAN_WRITE()
CANopen
Library TX Buffer Overflow
RX Buffer Overflow
RX INT
pdoInd() FlushMbox()
RX Buffer CAN_READ()
pdo.c
cdriver.c can_twincan.c
usr_301.c
Initialization
Init_CAN()
The parameters of the function Init_CAN() are depending on the CAN controller
and its hardware access. The CAN controller is initialized but left in the state
stopped.
getBitTiming()
Returns a pointer to an entry of the bit-timing table for the bit rate that was passed
as argument.
Set_Baudrate()
Initializes the CAN controller for the given bit rate. The CAN controller is left the
state stopped.
CAN Bus Status
Start_CAN()
Turns the CAN controller from state stopped into state running and enabled the
CAN interrupt.
Stop_CAN()
Turns the CAN controller into state stopped.
Clear_busoff()
After a bus-off this function turns the CAN controller into state running. If this is
successful is not sure. The state change can last some time (128x11 recessive Bits).
Communication Objects (COB)
Communication objects are used for administration of static information of CAN mes-
sages. They are of data type COB_T (see chapter "CAN Driver Basics").
Define_COB()
A new communication object is created. In the TwinCAN driver the helper func-
tion createCob() takes over the biggest part of the functionality. For Full-CAN con-
troller like the TwinCAN hardware message objects are initialized, too. This is
mainly done in the function initChannel().
Set_COB_ID()
Sets a new COB-ID for an existing communication object. The type (RX, TX) of
the communication object can change. It might as well be deactivated. Setting the
COB-ID in a hardware message object in the TwinCAN driver is mostly done in the
function initChannel().
getCanDriverState()
Returns the current state of the CAN driver. (e.g. CANFLAG_ACTIVE,
CANFLAG_BUSOFF).
Interrupts
CAN_int()
This is the interrupt function. In many drivers all interrupts are handled in just one
function.
➥ Please have a look at the Reference Manual for detailed function descriptions.
The CAN driver is the interface for reception and transmission of messages. In general
message queues are used for all messages received (pRX_Buffer[]) and transmitted
(pTX_Buffer[]).
For error messages and timer events a group of global flags ( coLibFlags,
coCanFlags) are defined. The flags can be set by the CAN and the timer interrupt. In
the function flagIdentification() the flags are evaluated. It is called within the function
FlushMbox() located in the module cdriver.c or in a cpu specific module.
Received messages are processed by the function msgIdentification(). The argument
passed to this function is of the type CAN_MSG_T. It is defined in the module co_stru.h
and contains the CAN message. Assembling the CAN message into a variable of type
CAN_MSG_T and the call to msgIdentification() is done in the function FlushMbox()
from the module cdriver.c.
struct CAN_MSG
{
COB_KIND_T cobType; /* COB Type */
COB_IDENT_T cobId; /* COB Id */
UNSIGNED8 pData[8]; /* data */
UNSIGNED8 length; /* if bit CO_RTR_REQ
* is set -> RTR */
};
The type COB_KIND_T stores the information about the use of the message object, i.e.
receiving, sending, receiving RTR or sending RTR messages. This is the main task. In
addition the CANopen service like PDO, SDO can be specified too.
Bit 7 6 5 0
service bits
Direction bit
RTR bit
Disable bit
Figure 47,
➥ Note: The concrete position of the bits are subject to change. Only use the symbolic
names of the CANopen Library.
Type Remarks
CO_COB_RX receive message
CO_COB_TX transmit message
CO_COB_RX_RTR receive message, which can be requested by the local device
(a receive message that can send an RTR request)
CO_COB_TX_RTR transmit message, which can be requested by remote devices
(a transmit message, which can receive an RTR request)
Table 44, Type of CAN Message
CAN error handling covers hardware and software errors, like CAN passive or buffer
overflow. All CAN errors are reported by setting a flag in the global variable coLibFlags.
The concrete error cause is set in the global variable coCanFlags. The function flagIden-
tification() checks the variables coLibFlags and coCanFlags and calls the appropriate
CANopen Library function or a user indication function.
The definition of the CAN error flags and the timer flags is shown in table 46.
The default implementation of the flag set/reset macros are located in co_flag.h and
co_drv.h.
#define SET_COLIB_FLAG(FLAG) (GL_ARRAY(coLibFlags) |= (FLAG))
#define RESET_COLIB_FLAG(FLAG) (GL_ARRAY(coLibFlags) &= ˜(FLAG))
#define SET_CAN_FLAG(FLAG) GL_ARRAY(coCanFlags) |= (FLAG)
#define RESET_CAN_FLAG(FLAG) GL_ARRAY(coCanFlags) &= ˜(FLAG)
Changes are possible by a user specific setting in the cal_conf.h. A good working change
is an additional atomic command or anything alike.
An example change could be
#define SET_CAN_FLAG(FLAG) do{\
DISABLE_CPU_INTERRUPTS();\
GL_ARRAY(coCanFlags) |= (FLAG);\
RESTORE_CPU_INTERRUPTS();\
}while(0)
This example uses 10 entries separately in the send and receive buffer. The data in the
buffers are of type BUFFER_ENTRY_T.
typedef enum { EMPTY, FULL } MEM_STAT_T;
struct BUFFER_ENTRY
{
VOLATILE MEM_STAT_T eStat;
COB_KIND_T eType;
COB_IDENT_T cobId;
UNSIGNED8 bLength;
UNSIGNED8 pData[8];
UNSIGNED8 bChannel;
};
exists.
BUFFER_INIT_PTR(direction, action)
BUFFER_READ(direction,source)
Read from buffer
BUFFER_WRITE(direction,destination,data)
Write data to the buffer
CHECK_BUFFER_READ (direction)
Checks if the buffer contains a "full" entry and if a message can be read from this
buffer. If the check is true the following code block is executed.
CHECK_BUFFER_READ(RX)
{
/* read from the Buffer */
...
}
CHECK_BUFFER_WRITE (direction,error)
Checks if the buffer contains an "empty" entry and if a message can be written to
this buffer. If the check is true the following code block is executed. Otherwise an
error condition is signaled and the following code block is ignored.
CHECK_BUFFER_WRITE( TX, CANFLAG_TXBUFFER_OVERFLOW)
{
/* write to the Buffer */
...
}
/* buffer full? */
CHECK_BUFFER_READ(RX)
{
/* read from the buffer */
length = BUFFER_READ(RX, bLength);
...
/* release buffer */
BUFFER_ENTRY_INCR( RX , Read , EMPTY);
}
}
In cdriver.c there are more functions that support this buffer handling.
void clearTxBuffer(void)
void clearRxBuffer(void)
Marks all entries in one buffer RX/TX as empty. Messages that are in buffers of the
CAN controller remain unchanged.
BUFFER_INDEX_T getNumberOfTxMessages(void)
BUFFER_INDEX_T getNumberOfRxMessages(void)
Returns number of RX/TX messages in the buffer.
➥ Please have a look at the Reference Manual for detailed function descriptions.
n n n
Transmit Interrupt Receive Interrupt State Interrupt
y y y
y SYNC y n
transmit queue set SYNC flag CAN error ?
empty ? received ?
n n y
RETI
For systems which do not use a CAN interrupt e.g. PCs using active CAN cards or sys-
tems which get the CAN message via operating system drivers, it is not necessary to put
the incoming messages into a queue, because all messages are typically buffered in the
operating system driver or in the memory of active CAN cards. The interpretation can be
done directly via msgIdentification() (see above). The reception flow checks two kinds of
messages. The first is the CANopen SYNC telegram. The classification of SYNC has to
be the first in order to guarantee a minimum of jitter. All other messages are put into a
queue which decouples the CAN interrupt service routine from the CANopen Library.
CAN-ISR Management
• SetIntMask()
• ResetIntMask()
• Init_CAN_Interrupts()
• Enable_CAN_Interrupts()
• Disable_CAN_Interrupts()
• Restore_CAN_Interrupts()
For the CAN-ISR management the functions for enabling/disabling CAN interrupts are
mandatory. These functions ensure that the values of the message queue read and write
pointers remain consistent. For active CAN modules these functions are empty. The
functions for the setting and resetting of the CAN-ISR to/from interrupt vector tables are
not implemented for active modules.
5.1.6.1. Basics
The TwinCAN controller has 32 configurable hardware message objects. The number of
hardware message objects allows to support 3 different software modes in the driver. The
modes are enabled in the file cal_conf.h.
SoftwareModes
without define
The CAN controller is used in Basic-CAN mode. All messages are received. In
this mode the number of CANopen services is only limited by RAM of the CPU.
CONFIG_CAN_FULLCAN_SOFT_RTR
The CAN controller is used in Full-CAN mode. The hardware filtering of the CAN
controller is used. RTR messages are processed by the CANopen Library and not
by the CAN controller. The number of CANopen services is limited.
CONFIG_CAN_FULLCAN_SOFT_RTR
CONFIG_CAN_ONLY_ONE_TRANSMIT_CHANNEL
This is an extension of the Full-CAN mode. It increases the number of CANopen
services for the Full-CAN mode. All send objects that do not use RTR use one
hardware message object. To efficiently use this setting support for RTR should be
avoided. This is achieved by setting bit 30 (PDO_NO_RTR_ALLOWED_BIT) in a
COB-ID of a TPDO.
AccessModes
CONFIG_CAN_ACCESS_MEM_MAP
The CAN controller is located in memory address range of the CPU. Access to the
CAN controller can be carried out by pointer.
CONFIG_CAN_ACCESS_IO_MAP
The CAN controller is addressed via I/O functions. It is also possible to use SPI for
access. Access by pointer is not allowed.
Register Layout
Register layout of the CAN controller can be defined with the following macros.
CONFIG_BIG_ENDIAN
Access with a Big Endian machine (CPU is Big Endian)
CONFIG_CAN_REGISTER_OFFSET
Address offset between to consecutive registers
Macros for Accessing the CAN Controller
Access to the CAN controller is carried out by a number of access macros. In access
mode CONFIG_CAN_ACCESS_MEM_MAP the variable addr is a pointer to an address in
the CAN controller. Unlike in the access mode CONFIG_CAN_ACCESS_IO_MAP the
variable addr is a value of a data type, e.g. UNSIGNED16, that is supported by the I/O
functionality. The use of macros for accessing the CAN controller simplifies adaption of
a driver to a different CPU.
CAN_ADDR_T
Data type for accessing the CAN controller e.g. (UNSIGNED8 *)
void CAN_INIT_BASE_PTR(addr)
Initializes address pointer to the CAN controller to address of addr.
CAN_ADDR_T CAN_ADDR(reg)
Returns the absolute address of a register reg.
UNSIGNED8 CAN_READ(reg)
UNSIGNED16 CAN_READW(reg)
UNSIGNED32 CAN_READL(reg)
➥ Note: The drivers support only one access method to the CAN controller like byte,
word or long access.
can_twincan.h
CAN_ADDR_T ptwincan;
Init_CAN(pBaseAddr, bitrate)
{
drivers/shar_src ptwincan = pBaseAddr;
}
void CAN_int(void)
{
bChannel = CAN_READ(CAN_InterruptRegL);
}
can_twincan.c
initCAN(bitRate)
{
drivers/xc164 Init_CAN(CONFIG_CAN_ADDR, bitRate);
}
init_xc164.c
#define CONFIG_CAN_ACCESS_MEM_MAP
#define CONFIG_CAN_REGISTER_OFFSET 1
#define CONFIG_CAN_ADDR (void far *)0x200200
examples/s<xx>
cal_conf.h
is needed.
CAN_INIT_OBJ_PTR(channel)
Access to hardware message object channel of the CAN controller. This macro has
to be invoked every time before a hardware message object is accessed.
CAN_READ_OBJ(channel, reg)
Read register reg of hardware message buffer channel.
CONFIG_CAN_ACCESS_MEM_MAP
UNSIGNED8 * pChannel;
/* Access to Messagebuffer 1 */
CAN_INIT_OBJ_PTR(1);
/* read mode register */
mode = CAN_READ_OBJ(1, modereg);
UNSIGNED16 pChannel;
/* calculate address of messagebuffer 1 */
pChannel = io_start_+mb_1_startaddress;
/* read by i/o function */
mode = read_io(pChannel + modereg_offset);
CONFIG_CAN_ACCESS_IO_MAP
The bit-timing table of the driver has to be customized to the used hardware. This is nec-
essary because the values in this table depend on the CAN clock of the CPU. For some
preselected CAN clocks the table is filled with values. The bit-timing tables are located
in the header file of the CAN driver in question.
For the TwinCAN driver they are defined in drivers/shar_inc/can_twincan.h. The
selection of the appropriate table is done in the hardware settings menu of the CANopen
Design Tool. The CANopen Design Tool generates the following in the header file
cal_conf.h:
#define CONFIG_CAN_T_CLK 20
This enables the bit-timing for a CAN clock of 20 MHz in the driver header file. If there
is no table for the specific CAN clock a new table has to be defined. The table shall not
be defined in the generic header files so that changes are not overwritten with a driver
update. An adequate place for the new table is an application header file. This can be
setup in the CANopen Design Tool which in turn generates an include statement in the
header file cal_conf.h. All CANopen bit rates have to be defined in the bit-timing table.
To simplify the generation of a new bit-timing table there is an internet form that calcu-
lates bit-timing values for a given CAN clock. The internet address is:
http://www.port.de/engl/canprod/sv_req_form.html
The CAN clock is the clock before the prescaler.
The bit-timing table is an array for the different bit rates which is used by the function:
The table is located in a driver source file. In case of the TwinCAN it is located in the file
can_twincan.c. For the TwinCAN controller with a CAN clock of 20 MHz the following
values are valid. These are located in the header file can_twincan.h:
# define CAN_BTR0_10K 0 /* Not possible */
# define CAN_BTR1_10K 0 /* Not possible */
# define CAN_BTR0_20K 0x31
# define CAN_BTR1_20K 0x2f
# define CAN_BTR0_50K 0x18
# define CAN_BTR1_50K 0x1c
# define CAN_BTR0_100K 9
# define CAN_BTR1_100K 0x2f
# define CAN_BTR0_125K 9
# define CAN_BTR1_125K 0x1c
# define CAN_BTR0_250K 4
# define CAN_BTR1_250K 0x1c
# define CAN_BTR0_500K 1
# define CAN_BTR1_500K 0x2f
# define CAN_BTR0_800K 0
# define CAN_BTR1_800K 0x7f
# define CAN_BTR0_1000K 0
# define CAN_BTR1_1000K 0x2f
Between CAN controllers the implementation of the RTR support differs. This is one
reason that the CiA recommends to implement devices without RTR support. On the CiA
web site a document is available on this subject (see Application note 802). In general a
device should not answer a Remote Request in every case. The CANopen Library needs
to have the complete control about the messages a device sends. With the new CANopen
Library version Remote Requests are only answered by software. For CAN controllers
that can only answer by hardware, RTR support is not possible. The CANopen Library
uses the RTR settings from the object dictionary of the delivered device. It is possible to
set the RTR not allowed bits to disable the RTR support.
Timer Interrupt
coTimerTick++
End
The functionality of the Timer_int() can also be integrated into a user defined timer func-
tion which is called cyclically.
The prepared timer functionality uses Timer 4. It is used as overflow timer with a timer
period of 26.2 ms. This time base is used by the CANopen Library in the constant
coTimerPulse in the unit of 1/10 ms. In the CANopen Design Tool this value is specified
in the input field "Timer Period". The value is used in the define
#define CONFIG_TIMER_INC 262.
If a user defined timer should be used then the define CONFIG_COLIB_TIMER shall not
be set. The user timer interrupt service routine only needs to increment the global vari-
able coTimerTicks and set a global flag with
SET_COLIB_FLAG(COFLAG_TIMER_PULSED);
to signal the CANopen Library that the Timer interrupt was triggered.
CANopen Design Tool
#define CONFIG_COLIB_TIMER
#define CONFIG_TIMER_INC 262
examples/s<xx>
cal_conf.h
#ifdef CONFIG_COLIB_TIMER
void Timer_int(void)
drivers/shar_src {
coTimerTicks++;
...
}
#endif
cpu_166.c
Within many implementations no timer resource is free, especially the timer used in the
default implementation. The CANopen Library needs only a function that is called with
a constant period. It is also possible to use an already used timer interrupt. Within this
periodic called function the variable coTimerTicks must be incremented and the
CANopen Library must be informed by calling
coTimerTicks++;
SET_COLIB_FLAG(COFLAG_TIMER_PULSED);
➥ Note: Please have a look in the delivered default implementation of the timer inter-
rupt or the code fragment within the generic driver implementation.
• Init_CPU_Interrupts()
• Enable_CPU_Interrupts()
• Disable_CPU_Interrupts()
• Restore_CPU_Interrupts()
These functions influence the CPU interrupt.
➥ Note: Locking of CPU interrupts and CAN interrupts can be carried out nested.
Compilers support different memory models. For the CANopen Library a memory model
has to be chosen that allows access of a generic data pointer (unsigned char *) similarly
to
- global variables (e.g. canMsg),
- object directory (possibly in Flash memory),
- object directory description structures (possibly in Flash memory),
The CAN controller of the XC164CS is outside of the addressable area of the often used
memory model LARGE. In order not to use a bigger memory model access to the CAN
controller is carried out with a far pointer. For this purpose compiler dependent defini-
tions are used in the header file drivers/shar_inc/co_keil.h.
#define FAR far
#define NEAR near
Some compiler require special constructs when a constant has to be linked into flash
memory. This is not necessary for the XC164. It is sufficient to define
#define CO_CONST const.
➥ Note: Additional hints about the default implementation of different drivers are
placed in the README files within the drivers directories.
The hardware dependent adjustments to the driver are located in the directory driv-
ers/xc164. This makes it possible to overwrite the actual driver due to an update in the
directory drivers/shar_inc and drivers/shar_src without carrying out the adjustments
again.
Hints for the initial operation of the prepared CAN driver. It is assumed that
• the hardware has been initialized
• the bit-timing table has been adapted,
• access macros have been selected correctly or adapted respectively.
The emphasis of this chapter lies on checking of the adjustments.
The CANopen Design Tool provides the possibility to enable debug settings for testing
the adjustments. Debug settings are activated by the option "Debug Settings". This
enables the option "Send a test message after Init". If this option is activated the follow-
ing definitions are generated in the header file cal_conf.h:
#define CONFIG_EXPERIMENTAL 1
#define CONFIG_CAN_TX_TEST 1
This option causes that within the function Init_CAN() a message is sent with the COB-
ID 100 and one data byte that has the value AAh . It is sent with the chosen CAN bit rate.
No interrupts are used.
➥ Note: After this test the options has to be deactivated again.
This chapter describes the usage of the CANopen Library on multi-tasking systems.
Multi-tasking systems include multi-tasking operating systems but also interrupt driven
applications without any operating system i.e. application with timer triggered control
loop.
Prepared solutions of the security mechanism for shared resources of the object dictio-
nary are shown. Furthermore possible communication variants are discussed.
CAN Driver
Read/Write Read/Write
Object Dictionary
protected resource
CANopen Task
Receive Message
Distributor
Signal or
Event
The advantage of using a message distributor is the decoupling of application tasks from
the CANopen Library. Only the message distributor programmer needs CANopen and
the CANopen Library knowledge. All other application programmers can work with the
commonly used mechanisms.
A further advantage is the easy switching to another communication system by replacing
the distributor. So it is possible to support more then one field bus with one application
software. The message distributor is a process which uses the interprocess communica-
tion mechanism of the operating system to inform the application about new messages
(figure 54). For that purpose the application can read the new value from the object dic-
tionary or the value can be sent via a queue mechanism. For data transmission the appli-
cation task sends a message to the distributor. The distributor is responsible for the
CANopen Task
Transmit Message
Distributor
For resource protection many mechanisms are prepared within the CANopen Library by
port. The following macro defines can be used to adapt the protection mechanism to your
application and operating system needs.
• CO_NEW_RX_MSG(CO_LINE)
• CO_COM_PART_ALLOC(CO_LINE)
• CO_COM_PART_RELEASE(CO_LINE)
• CO_APPL_PART_ALLOC(CO_LINE)
• CO_APPL_PART_RELEASE(CO_LINE)
The macros listed above use a #define for the currently number of the used CAN line.
For the single line version the CO_LINE define is empty. The task of the
CO_NEW_RX_MSG macro is to inform the communication task that a new CAN message
or a new error message is in the receive queue (waking up of CANopen task).
The other macros are necessary for allocating and releasing the object dictionary. The
#define CO_APPL_PART_ALLOC(canLine) \
if(canLine == 0) \
os_wait(K_MBX+CO_SEMA_L0,0,NULL) \
else \
os_wait(K_MBX+CO_SEMA_L1,0,NULL)
#define CO_APPL_PART_RELEASE(canLine) \
if(canLine == 0) \
os_send_token(CO_SEMA_L0) \
else \
os_send_token(CO_SEMA_L1)
void resetActualVelocity(void)
{
/* allocate od application part */
CO_APPL_PART_ALLOC(0);
/* reset velocity value (CAN line 0)*/
l0_actual_velocity = 0;
/* release od application part */
CO_APPL_PART_RELEASE(0);
}
#define CO_NEW_RX_MSG(canLine) \
if(canLine == 0) \
os_send_token(CO_SEMA_L0); \
else \
os_send_token(CO_SEMA_L1);
while (1)
{
/*
* sleep while no new message on line 0
*
* CANopen task should be waken up:
* - if a new message is received
* - if the CANopen timer is expired
* in order to check all CANopen timers
*/
os_wait(K_MBX+CO_SEMA_L0,0,NULL);
/*
* interpret message for line 0
* or handle CANopen timers
*/
FlushMbox(0);
}
There are no prepared mechanisms of resource protection within the functions of the
CANopen Library. The user is responsible for ensuring that these functions are not inter-
rupted.
One relatively simple way to make a CANopen Library thread-safe is to create a single
mutex, lock it upon each entry to the library, and unlock it upon each exit from the
CANopen Library.
For single tasking systems, which use the same resources within the application and the
interrupt service routines, equivalent protection mechanism have to be used. The easiest
way is to disable the interrupt(s) in the allocation macros.
This chapter describes the properties of port’s multi-line version. With this version a sin-
gle process application can access more than one CAN network (CAN line). So it is pos-
sible to implement CANopen for multiple CAN lines on target platforms without an oper-
ating system, with a single-tasking operating system or a multi-tasking operating system
with a reduced resource protection mechanism. Such applications can be devices, which
use an internal and an external CANopen network e.g. production cells, robots etc. Fur-
thermore it is possible to build gateways between several networks. The CANopen net-
work functionality (master/slave) can be different for each CAN line. Other typical appli-
cations are data loggers, monitoring systems and global network masters.
➥ An easy way to build a multi-line system is to use a PC with more than one CAN
card or multi-port CAN cards.
A multi-CAN line device has <number of CAN lines> object dictionaries (Figure 56).
This means that the device behavior can be different for each line.
There are two special defines for the multi line usage:
CONFIG_MULT_LINES define for maximum number of CAN lines
CO_MAX_CAN_LINES is used for actual number of CAN lines
User’s Application
If a device variable should be accessible by two or more lines, the address references in
the object dictionary of all lines have to point to the same variable (Listing 35). The
object dictionary index of this variable can be different on every line.
/* values line 1 */
UNSIGNED32 l1_p301_device_type = 0x00000000UL;
UNSIGNED8 l1_p301_error_register = 0x00;
OBJDIR_T objDirLine0[] = {
{ (UNSIGNED8 *)&l0_p301_device_type,
l0_p301_device_type_desc,
0x1000, 1 }
,{ (UNSIGNED8 *)&l0_p301_error_register,
l0_p301_error_register_desc,
0x1001, 1 }
, ...
,{ (UNSIGNED8 *)&myInterLineValue,
l0_myInterLineValue_desc,
0x2200, 1 }
}
/* definition of object dictionary line 1 */
OBJDIR_T objDirLine1[] = {
{ (UNSIGNED8 *)&l1_p301_device_type,
l1_p301_device_type_desc,
0x1000, 1 }
,{ (UNSIGNED8 *)&l1_301_error_register,
l1_p301_error_register_desc,
0x1001, 1 }
, ...
/* link to variable of line 0 */
,{ (UNSIGNED8 *)myInterLineValue,
l1_myInterLineValue_desc,
0x4200, 1 }
/* end of link to variable of line 0 */
,{ (UNSIGNED8 *)&l1_otherVal,
l1_otherVal_desc,
0x5001, 1 }
}
The data flow within a multiple CAN line device is shown in figure 57.
The figure shows the software layers and the inter-line communication of the multi-line
version. Every CAN line has its own CAN driver module. For identical hardware on
each line the same module can be used. In this case only the CAN controller address has
to be switched and the received message put into the corresponding receive buffer.
The chosen driver concept ensures that the CAN controller can be different on every line.
If all CAN controllers are equal, code size can be saved. Furthermore an inter-driver
communication is possible. The reason for a communication like this is to realize a con-
figuration gateway. Such a gateway is the basis for configuration of all nodes in all con-
nected networks by one network participant. Usually the gateway has to have a shadow
object dictionary of each node to parameterize these nodes (see inter-line communica-
tion). If any object dictionary is changed the gateway shadow dictionary has to receive an
update. An update means a new configuration of the gateway (device must be pro-
grammable) or new compilation of the software (not practicable).
The condition for doing this is to have one on the side which has to be configured and
one server SDO (default) on the side of the configuration software. A SDO connection
has to be established via a control word which contains the line number and the node-ID.
It has to be ensured that this connection is only possible in the PRE-OPERATIONAL
state in order to prevent application errors in a certain CAN line. In this bypass mode
received server messages are transmitted as client messages and all client messages
received are transmitted as server answers to the originator. The easiest way to do this is
to copy the data from the receive buffer of the one line to the transmit buffer of the other
line. After the configuration, the bypass mode should be exited.
➥ All functionality which is coded into the driver is hardware dependent and mostly
not portable. Such message handling is only an exception for weak performance
This chapter describes the design flow for a CANopen device by using the CANopen
Library provided by port. The way to built a NMT master and a NMT slave application
will be shown by the delivered examples s1 for the NMT slave and parts of m1 for the
NMT master. Both examples are located in the example directory.
The design is separated in the following steps:
• decision about the kind of device (master/slave)
• pre-definition of the CANopen services (number, properties)
• decision about the target system (hardware/operating system)
After that the user knows the device properties and can start with the coding of the com-
munication part of his application. The necessary steps are listed below:
• preparation
• configuration of the hardware
• building up the object dictionary
• coding of the main routine
• coding of the reset behavior
• coding of the indication behavior
• optimization
8.1. Preparations
The easiest way to start programming of a new project is to use an existing example
delivered by the CANopen Library. All examples are located at the directory examples.
The Readme file there shows the main features for all available examples. Furthermore
the directory examples/template contains skeletons for master and slave applications and
for all indication functions. The user only has to fill these function bodies with his own
needs. The names of the needed files for your application are shown in table 48.
For the first step we suggest using a slave example s1. This example can be compiled
within its directory with the delivered make and project files.
The next step is to build a make file or project file. Within this file all dependencies of
your project files should be set9 .
Furthermore the search paths for #include files of your makefile or development envi-
ronment are to be set to:
• your working directory
to ensure that the cal_conf.h there is included first before all other include files
• canopen/include
• drivers/shar_inc
• drivers/<target>
The configuration of the hardware can be done by using the CANopen Design Tool. All
settings are saved at the header file cal_conf.h as compiler defines.
The CANopen Design Tool simplifies the configuration of the CANopen Library and the
creation of the object dictionary. It generates header files (cal_conf.h,objects.h) for the
CANopen Library, an initialization file (co_init.c), an Electronic Data Sheet(EDS) and a
9
The dependencies of the CANopen Library files are listed in the appendix.
The menu point General Settings contains the main options for the CANopen node. Here
you have to define the type of the node (master or slave) and other general settings. A
detailed online help for each #define is in the CANopen Design Tool help menu "List
of Compiler directives" available.
Here you can import an existing configuration or specify a new. In the sub-menu Debug
Settings #defines for development and debugging are defined. Using it will generate
additionally debugging code for the CPU and the can driver. See the source code or the
Context-Help in CANopen Design Tool for further information and be careful if you use
it.
The sub-menu CPU settings contains the available CPU driver modules. All CPU spe-
cific settings can be set here.
The sub-menu Compiler Settings contains settings to specify the used compiler. Further
the alignment can be set here.
The sub-menu CAN Settings contains the available can driver modules. Further options
that have to be set are the mode of operating for Full-CAN controller, the access type for
the CAN controller, the CAN controller address and the CAN controller buffer size.
For multi-line configurations the CAN settings have to be configured for each line.
The #defines to enable and to configure the CANopen services are derived from the
object dictionary. There the used number of CAN lines must be created and the Commu-
nication Segment of each line must be filled. The fastest way to fill the Communication
Segment is to import the objects from the CiA-S301 profile database. Select the Commu-
nication Segment in the object tree, click on "Import Data from File" and select the file
profile301.pro.
➥ There is no need to configure the remaining sections, if the CANopen Design Tool
Light is used.
After the configuration is done save it in a project file (.can) and start the generation of
the file cal_conf.h.
#ifndef __CAL_CONF_H
#define __CAL_CONF_H
#define CONFIG_DESIGNTOOL_VERSION 0x0202
/* active configuration : 0 */
#define CONFIG_USE_TARGET_0 1
/*
* General Settings
*/
#define CONFIG_CAN_ERROR_HANDLING 1
#define CONFIG_FAST_SORT 1
#define CONFIG_SLAVE 1
#define CONFIG_CAN_OBJECTS 8
/*
* Hardware configuration 0: 0
*/
/*
* Code Maturity Level Options
*/
/*
* CPU Setup
*/
#ifdef CONFIG_USE_TARGET_0
#define CONFIG_COLIB_TIMER 1
#define CONFIG_CPU_FAMILY_HCS12 1
#define CONFIG_CPU_TYPE_HCS12 1
#define CONFIG_TIMER_INC 28
# ifdef DEF_HW_PART
# include <cpu_hcs12.h>
# endif /* DEF_HW_PART */
#endif /* CONFIG_USE_TARGET_0 */
/*
* CAN Controller Setup
*/
#ifdef CONFIG_USE_TARGET_0
#define CONFIG_CAN_FAMILY_MSCAN 1
#define CONFIG_COLIB_BUFFER 1
#define CONFIG_COLIB_FLUSHMBOX 1
#define CONFIG_RX_BUFFER_SIZE 10
/*
* Compiler Setup
*/
#ifdef CONFIG_USE_TARGET_0
#define CONFIG_ALIGNMENT 1
#define CONFIG_BIG_ENDIAN 1
#define CONFIG_COMPILER_CW_HC12 1
# include <co_codewarrior.h>
#endif /* CONFIG_USE_TARGET_0 */
/*
* CANopen Services
*/
#define CONFIG_HEARTBEAT_PRODUCER 1
#define CONFIG_MAPPING_CNT 2
#define CONFIG_PDO_CONSUMER 1
#define CONFIG_SDO_SERVER 1
/*
* Additional CANopen Settings
*/
#define CONFIG_CONST_OBJDIR 1
#endif /* __CAL_CONF_H */
For this example listing, all hardware specific defines are set for a HCS12 board.
The settings have to be adapted for the specific hardware.
The object dictionary has to be filled with the necessary variables for the CANopen com-
munication profile and for the user’s application or device profile. Its structure is
described in chapter 3. For each variable the user has to define:
• the index number
• the number of elements (structure or field members)
The listing 38 shows the implementation of the user variables and the PDO parameters.
The object dictionary implementation contains a definition part (the #define
DEF_OBJ_DIC has to be set before objects.h is included) and a declaration part. In the
definition part all variables are defined. The object dictionary consists of three kinds of
data. The first are the user application and the second kind are CANopen communication
variables. For each of these variables there is a description (<variable name>_desc).
The third kind is the object dictionary objDir. This contains references to all variables
and their descriptions.
The PDO mappings for the first TPDO and the first RPDO are set to the variables
p301_n1_transmit_pdo_mapping and p301_n1_receive_pdo_mapping. Therefore it is
very easy to see the assignment of application variables to the PDO. In general the appli-
cation knows nothing about the communication variables.
/*
* objects.h - generated object dictionary for a CANopen device
*
*-----------------------------------------------------------------------------
*/
/**
* \file objects.h
* \author port GmbH, Halle (Saale)
* $Revision: 1.14 $
* $Date: 2012/05/11 10:18:44 $
*
* This file contains the selected objects for a CANopen device.
* It was generated by the CANopen Design Tool V2.3
* by port GmbH, Halle.
* Generation: 01-19-2006 12:29
*
10 A variable can be a common variable, a structure or an array.
/* Default values */
UNSIGNED8 l0_default0_0005[12] = { 0,4,2,3,254,2,2,0,0,2,0,0 };
UNSIGNED16 l0_default0_0006[2] = { 0x3e8,0x0 };
UNSIGNED32 l0_default0_0007[10] = { 0x20191,0x34,0x0,0x0,0x0,
0x600,0x580,0x200,0x62000108,0x62000208 };
STRING_DATA_T l0_string_data[1] = {{0x23, 0x23}};
OBJDIR_T objDir[] = {
{ (UNSIGNED8 *)&p301_device_type,
(VALUE_DESC_T *)p301_device_type_desc,
0x1000, 1 }
Listing 38,
Parts of the Object Dictionary Implementation for Example s1
/*
* CAN_START_BIT_RATE = 0 : read bit timing from init file
* CAN_START_BIT_RATE = bitRate : use local bitRate variable
*/
ret = initCan(CAN_START_BIT_RATE);
PRINTRET("initCan: %02x\n", (int)ret);
/*
* timer is needed for inhibit time and
* host life guarding (if life guarding is supported)
*/
initTimer();
SetIntMask();
Start_CAN();
ENABLE_CPU_INTERRUPTS();
}
/* Inititialization of CANopen
* defines also the Network control Object -- NMT
* resets communication
*/
RET_T init_Library(void)
{
commonRet = initCANopen();
PRINTRET("initCANopen: %02x\n", (int)commonRet);
During the function initCANopen() all entries of the object dictionary are set to their
default values, and all COB-IDs are set according to the predefined connection set, in-
depend the saved entries at objects.h. If the application needs other values it can be set
by defining INIT_USER_SETTINGS() as macro or as function.
The design of the application is the user’s task. He has to ensure that the CAN message
buffer is read continuously or event driven. The easiest way to perform this is an endless
loop from which the buffer read function and the application functions are called cycli-
cally. (listing 40).
while(1)
{
/* read and interpret CAN message */
FlushMbox();
/* application function */
application();
}
The implementation of the shutdown behavior is only necessary if the CANopen Library
can be left during the run time of the application i.e. if running on a operating system.
The called functions will free the allocated system resources. The following steps are to
be made for this:
• stop all nodes stopRemoteNodeReq() (only master)
• deactivate the ISRs for CAN and timer
• de-initialize CAN controller, timer and their ISR’s
• delete the node entries removeRemoteNodeReq() (only master)
• delete the local node deleteNodeReq()
• delete the node management list (network) deleteNetworkReq() (only master)
• de-initialize the CANopen Library leaveCANopen()
main()
{
....
/*
* Application really ends
*
* release all resources.
*/
releaseTimer();
ResetIntMask();
deleteNodeReq();
/* leaves CANopen */
leaveCANopen();
The file co_init.c, generated by the CANopen Design Tool contains the function
deinit_Library() that does all necessary steps to shutdown the CANopen Library.
The reset behavior is a property only for slaves. Each slave can receive a Reset Applica-
tion or a Reset Communication command from the master. In the module nmtslave.c the
user will find the functions resetApplInd() and resetCommInd(). Within these functions
an individual reset of the application data and states can be implemented. In the function
for the communication reset the CAN bit rate12 or node-ID can be changed.
Furthermore there is the function newStateInd(). This function informs the user’s appli-
cation about each transition of the communication state machine. This information can
be important, because a few communication services are not available in certain states.
For example, the application transmits error codes via PDOs and the master forces the
node to PRE-OPERATIONAL. Then PDOs are not allowed.
For each received CANopen message an indication function is called. Templates for
these functions can be found in the module template/usr_301.c. The task of these func-
tions is to start an error handling or additional post-processing or pre-processing for
object dictionary entries or to initiate a reaction. There are three kinds of errors which
can be handled with the indication functions. The first kind are errors in the CAN con-
troller and CAN driver message queues. The function canErrorInd() informs the applica-
tion about error of the CAN controller e.g. "Bus-Off", "Error passive" and about the over-
flow of the receive and transmit buffer since the last call to canErrorInd(). The current
state of the CAN controller can be queried by getCanDriverState().
If an emergency message is received, the function emcyInd() is called at the EMCY con-
sumer. There the user can handle fatal errors of remote devices.
The second kind of errors are the Node Guarding errors. In the case of a lost connection
between master and slave the function mGuardErrorInd() is called at the master and the
function sGuardErrorInd() at the slave.
The other functions of the module are for the common data service handling. For each
received PDO the function pdoInd() is called. Within this function the user can define
reactions which should be initiated by certain PDOs.
/*****************************************************************
*
12 Please ensure that all devices in the network use the same CAN bit rate.
void pdoInd(
UNSIGNED16 pdoNr /* nr of PDO */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /**< number of CAN line
0..CONFIG_MULT_LINES-1 */
#endif
)
{
switch(pdoNr) {
case 1:
/* we have a fixed PDO mapping.
* Therefore we know that the two sub-indices of 0x6200
* are mapped. The content now in the object directory
* has to be transferred to the two hardware ports 1 and 2.
*/
set_outputs(1);
set_outputs(2);
break;
}
}
The server SDO services are divided into read and write access functions. For every kind
there is a function sdoWrInd() for write access and sdoRdInd() for read access. It is pos-
sible to initiate reactions or to manipulate values i.e. unit transformations with these func-
tions.
RET_T sdoWrInd(
UNSIGNED16 index, /* index to object */
UNSIGNED8 subIndex /* sub-index to object */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /**< number of CAN line
0..CONFIG_MULT_LINES-1 */
#endif
)
{
if (index == 0x6200) {
/* write request to the digital output 8-bit ports */
set_outputs(subIndex);
}
return CO_OK;
/*****************************************************************
* sdoRdInd - indicates the occurrence of a SDO read access
*
* \retval CO_OK success
* \retval CO_E_xxx error
*
*
*/
RET_T sdoRdInd(
UNSIGNED16 index, /* index to object */
UNSIGNED8 subIndex /* index to object */
#ifdef CONFIG_MULT_LINES
,UNSIGNED8 canLine /**< number of CAN line
0..CONFIG_MULT_LINES-1 */
#endif
)
{
return CO_OK;
}
8.7. Optimization
This chapter describes possible error situations. If you have trouble with the CANopen
Library, please read the following error descriptions first.
If you do not find a solution for your problem in this chapter, you can request support, see
chapter 1.6, or see the other appendixes for more description of internal behavior.
Please check the following points:
- Have you checked the return values of the functions?
- Are the #defines in cal_conf.h set correctly for the services used?
- Have you checked the order of function calls?
- Have you included the associated objects.h and cal_conf.h?
- Have you recompiled the sources after changing objects.h and cal_conf.h?
- Do you have an overview which functionalities should be made on your local device
and which on the remote device(s)?
Detailed error situation descriptions are listed in table 50.
Description Error Reason
no transmission of PDOs node is not in state OPERATIONAL
is possible PDO disabled, see PDO parameter
PDO is only a RTR PDO
#define CONFIG_PDO_PRODUCER is not set
no reception of PDOs is node is not in state OPERATIONAL
possible PDO disabled, see PDO parameter
#define CONFIG_PDO_CONSUMER is not set
value of TPDO contents of dynamic mapping was not carried out
remote device is wrong your compiler does not support byte alignment and
#define CONFIG_ALIGNMENT is not set
variable PDO mapping is mapping flag not set for selected variable (objects.h)
not possible on remote at RPDO: selected variable is read only (objects.h)
device (Abort Domain at TPDO: selected variable is write only (objects.h)
Transfer) #define CONFIG_DYN_PDO_MAPPING was not set
#define CONFIG_MAX_DYN_MAP_ENTRIES was
not set or their value is too low
variables contains wrong your compiler does not support byte alignment and
values #define CONFIG_ALIGNMENT is not set or has
wrong value
you have included the wrong object dictionary
object dictionary variables are parameterized incorrectly
This appendix contains an overview of all header files for the CANopen Library. The
location mentioned in the tables is the location of the headers within the installation path.
There are 4 kinds of header files for the CANopen Library compilation.
1. project specific headers
2. shared driver headers
3. example driver headers
4. CANopen Library interface headers
Location: drivers/shar_inc
Name Description
cdriver.h constants for all CAN controllers
cpu_xxx.h constants for CPU driver part
can_xxx.h constants for CAN driver part
co_xxx.h constants for special compilers
Table 52, Shared Driver Headers
Location: drivers/<hardware>
Name Description
examples.h adaptations to use our examples
Table 53, Example Driver Headers
Location: canopen/include
Name Description
co_acces.h access to the object dictionary
This appendix describes the basic data types of the CANopen Library. All atomic data
types are defined within the header file co_type.h. In general this file is part of the
CANopen Library interface headers, but some development environments define these
types, too. Therefore it is necessary to overload this file by a co_type.h in your project
include directory.
➥ The compiler’s search path has to contain your project include directory path before
the CANopen Library include path.
Then your co_type.h file (or any other name used) is the project specific data type header
file.
The following table describes the types. Using only the type definition BOOL_T,
UNSIGNED<x> and INTEGER<x> in own applications is recommended.
Type Description
BOOL_T boolean type
UNSIGNED8 unsigned 8 bit value
UNSIGNED16 unsigned 16 bit value
UNSIGNED32 unsigned 32 bit value
UNSIGNED64 unsigned 64 bit value
INTEGER8 signed 8 bit value
INTEGER16 signed 16 bit value
INTEGER32 signed 32 bit value
LOOPCNT_U8 unsigned 8 bit value - register variable (only Keil C51)
LOOPCNT_U16 unsigned 16 bit value - register variable (only Keil C51)
REAL32 float 32 bit value
VIS_STRING_T unsigned char
OCT_STRING_T unsigned char
The SDO Abort Transfer is a negative conformation of a SDO request. This service con-
tains a code, which specifies the kind of the abort. The CANopen Library by port sup-
ports the following SDO abort codes:
In the context of the CANopen Library there are many useful tools available for software
implementation and system integration.
All tools are available via the web page of port . 〈http://www.port.de〉 Without a
valid license file the tools can be used in demo mode.
The CANopen Design Tool makes the configuration of the CANopen Library and the cre-
ation of the object dictionary possible. This tool generates source code file in C for the
CANopen Library, electronic device descriptions and various documentations.
The CANopen Server is one of the more comprehensive examples for the use of the
CANopen Library. The CANopen Server realizes a complete Class 3 CANopen manager
node according to the CiA specification CiA-309-3.
With its additional console interface it is possible to test one’s own application.
The CANopen Device Monitor of port is a tool for the graphical inspection and configura-
tion of CANopen devices in a CANopen network. The embedded scripting ability makes
it possible to access the implemented CANopen services and to write test or control
applications with a minimum of effort.
The CAN-REport is a monitoring tool for CAN traffic. It is useful for message recording
and interpretation.
The chapters describing the modifications made against the previous one. This should
help upgrading older projects to the latest CANopen Library version.
For unified function names the following function names has been changed:
- New header- and c-file concept - divide all functionality depending the services
- New indications added for boot-up and start Heartbeat
- If emergency is supported, the emergency entry in the object dictionary is manda-
tory
- Inhibit Time for emergency supported
- Multiplexed PDO for destination address mode and source address mode available
The define CONFIG_COLIB_MALLOC enables our common customized simply memory allocation.
All defines in the CANopen Library are changed to CANopen compatible names
SDO transfer for block transfer adapted - function waitForSdoRes() and abort condition
for time out changed
10.6.5.3. Structures
10.6.5.4. Tools
Add new features (SDO block transfer, multi-CAN controller) to the ConfigTool.
- CANopen Library is now compatible with the CANopen Standard CiA-301, V4.0
- All CAL dependencies are removed
- All interrupt functions are modified
CANopen functionality is no longer carried out within the interrupt routines. Within
the ISR only flags are set. These flags are valued by the function FlushMbox() and
the corresponding function is called. This is why you have to call the function
FlushMbox() regularly in the main loop.
- Some of the user functions have been changed.
- The object dictionary can be stored in ROM.
- A lot of the structures have been optimized.
- For a better understanding some of the defines have changed. (There are no longer
defines with _NO_.)
Please have a look at the reference manual for a detailed description of the functions.
The following structures have been optimized (especially for byte alignment on 8 bit con-
trollers):
typedef struct
{
UNSIGNED8 *pObj; /* pointer to data */
VALUE_DESC_T *pValDesc; /* value description */
UNSIGNED16 index; /* index of object */
UNSIGNED8 numOfElem; /* number of elements */
} LIST_ELEMENT_T;
typedef struct
{
UNSIGNED32 defaultVal; /* default value or size of domains */
#ifdef CONFIG_LIMITS_CHECK
UNSIGNED32 minRange; /* min. range of object element */
UNSIGNED32 maxRange; /* max. range of object element*/
#endif
INTEGER8 size; /* size of element in Bytes
if size negative object is value
a signed type*/
UNSIGNED8 attribute; /* domain type = 1, short desc = 2,
reserved = 4, num_val = 0x10,
read permitted = 0x20,
write permitted = 0x40,
write permitted = 0x40,
pdoMAPPING allowed = 0x80 bit-coded ! */
} VALUE_DESC_T;
-W-
writeEmcyReq() 70
writeLssStoreParameterReq() 93
writeMPdoReq() 66–67
writePdoReq() 63
writeSdoReq() 51
writeSrdoReq() 96