3. Software Integration

3.1. Network Timing

Interaction between application and EtherCAT network

EC-Master has no internal tasks, the operation is fully controlled by the user’s application. The benefits of this design are:

  • No synchronization issues between application and EC-Master

  • Consistent process data without using any locks

  • Various network timings driven by the application possible

  • Cyclic part may run within Interrupt Service Routine (ISR)

  • Easy to integrate

From the application perspective, EC-Master behaves like a driver that is controlled by the emExecJob() function with additional parameters, so-called EC_T_USER_JOB.

Typical sequence of EC_T_USER_JOB for emExecJob() to be called cyclically by the application:

Symbol_CycJob-P Refresh Inputs

EC_T_USER_JOB::eUsrJob_ProcessAllRxFrames: Process all received frames

Symbol_CycJob-S Write Outputs

EC_T_USER_JOB::eUsrJob_SendAllCycFrames: Send cyclic frames to update process output data.

Symbol_CycJob-MT Administration

EC_T_USER_JOB::eUsrJob_MasterTimer: Trigger master and slave state machines.

Symbol_CycJob-AS Send acyclic datagrams/commands

EC_T_USER_JOB::eUsrJob_SendAcycFrames: Transmit pending acyclic frame(s).

When a process data update is initiated by calling emExecJob(eUsrJob_ProcessAllRxFrames) new input data are read from the received frames and copied into the process data image. After the function returns the application can process the inputs, calculate the outputs and update the values in the process image. With calling emExecJob(eUsrJob_SendAllCycFrames) the output data are read from the process data image and stored in Ethernet/EtherCAT frames prior to sending them to the Link Layer. When this call returns all output process data values are stored in Ethernet/EtherCAT frames which are then processed by the network controller.

If only one single thread is both writing into the process data image and calling emExecJob(eUsrJob_SendAllCycFrames) no further output process data synchronization is necessary. The application is responsible to (cyclically) calling the function emExecJob() with the appropriate parameters.

EtherCAT frames are divided into two categories:

  1. Cyclic frames
    • Contain process output and input data

    • Distributed Clocks (DC): Contain datagram to distribute network time

    • Typically sent by master in every cycle

    • Defined by the configuration tool (which data to read and to write)

  2. Acyclic frames
    • Asynchronous, event triggered communication

    • Mailbox communication (CoE, FoE, EoE)

    • Status requests (e. g. read slave state information)

    • Raw EtherCAT datagrams requested by application

3.1.1. Standard Timing: Short output dead time

Cyclic frames

Application has to perform:

/* Job P: Process data are saved in the process data image */
emExecJob(dwInstanceId, eUsrJob_ProcessAllRxFrames, &oJobParms);

/* App. Task */

/* Job S: Send updated process data. 
   Outputs are updated in slaves and input data is collected to be present for the next cycle. 
   The process data image is saved during eUsrJob_ProcessAllRxFrames */
emExecJob(dwInstanceId, eUsrJob_SendAllCycFrames, EC_NULL);

/* Job MT: Trigger master state machines. 
   Required to perform any status changes or internal administration tasks */
emExecJob(dwInstanceId, eUsrJob_MasterTimer, EC_NULL);

Cyclic and acyclic frames

Application has to perform:

/* Job P: Process data are saved in the process data image */
emExecJob(dwInstanceId, eUsrJob_ProcessAllRxFrames, &oJobParms);

/* App. Task */

/* Job S: Send updated process data. 
   Outputs are updated in slaves and input data is collected to be present for the next cycle. 
   The process data image is saved during eUsrJob_ProcessAllRxFrames */
emExecJob(dwInstanceId, eUsrJob_SendAllCycFrames, EC_NULL);

/* Job MT: Trigger master state machines. 
   Required to perform any status changes or internal administration tasks */
emExecJob(dwInstanceId, eUsrJob_MasterTimer, EC_NULL);

/* Job AS: Transmission of the acyclic commands from the queue. 
   These may have been queued by the application or by the internal administration task (eUsrJob_MasterTimer) */
emExecJob(dwInstanceId, eUsrJob_SendAcycFrames, EC_NULL);

Cyclic frames with DC

Application has to perform:

/* Job P: Process data are saved in the process data image */
emExecJob(dwInstanceId, eUsrJob_ProcessAllRxFrames, &oJobParms);

/* App. Task */

/* Job S: Send updated process data. 
   Outputs are updated in slaves and input data is collected to be present for the next cycle. 
   The process data image is saved during eUsrJob_ProcessAllRxFrames */
emExecJob(dwInstanceId, eUsrJob_SendAllCycFrames, EC_NULL);

/* Job MT: Trigger master state machines. 
   Required to perform any status changes or internal administration tasks */
emExecJob(dwInstanceId, eUsrJob_MasterTimer, EC_NULL);

3.1.2. Alternative Timing: Short Input dead time

Application has to perform during startup:

emInitMaster(dwInstanceId, &oInitMasterParms);

/* create event for "cyclic frame received" and register RX callback function */
{
    EC_T_CYCFRAME_RX_CBDESC oCycFrameRxCallbackDesc;

    S_pvCycFrameReceivedEvent = OsCreateEvent();

    /* setup callback function which is called after RX */
    OsMemset(&oCycFrameRxCallbackDesc, 0, sizeof(EC_T_CYCFRAME_RX_CBDESC));
    oCycFrameRxCallbackDesc.pfnCallback = CycFrameReceivedCallback;
    oCycFrameRxCallbackDesc.pCallbackContext = S_pvCycFrameReceivedEvent;

    emIoCtl(dwInstanceId, EC_IOCTL_REGISTER_CYCFRAME_RX_CB, &oCycFrameRxCallbackDesc, sizeof(EC_T_CYCFRAME_RX_CBDESC), EC_NULL, 0, EC_NULL);
}
/* create cyclic process data Thread */
S_pvtJobThread = OsCreateThread((EC_T_CHAR*)"EcMasterJobTask", EcMasterJobTask, CpuSet,
    JOBS_THREAD_PRIO, JOBS_THREAD_STACKSIZE, (EC_T_VOID*)pAppContext);

Application has to perform inside job task:

/* Job S: Send updated process data.
   Outputs are updated in slaves and input data is collected to be present for the current cycle.
   The process data image is saved after receiving the response frame within the interrupt service thread */
emExecJob(dwInstanceId, eUsrJob_SendAllCycFrames, EC_NULL);

/* wait until cyclic frame is received */
OsWaitForEvent(S_pvCycFrameReceivedEvent, dwCycleTime);

/* App. Task */

/* Job MT: Trigger master state machines.
   Required to perform any status changes or internal administration tasks */
emExecJob(dwInstanceId, eUsrJob_MasterTimer, EC_NULL);

/* Job AS: Transmission of the acyclic commands from the queue.
   These may have been queued by the application or by the internal administration task (eUsrJob_MasterTimer) */
emExecJob(dwInstanceId, eUsrJob_SendAcycFrames, EC_NULL);

For closer details find an example project Examples/EcMasterDemoSyncSm

3.2. Example application

The example application EcMasterDemo will handle the following tasks:

  • Showing basic EtherCAT communication

  • Master stack initialization

  • Start (set all slaves into OPERATIONAL state)

  • “Out of the box” solution for different operating systems, see Operating Systems (OS)

  • Thread with periodic tasks and application thread already implemented

  • The output messages of the demo application will be printed on the console as well as in some files. The following log files will be created:
    • ecmaster0.log all messages

    • error0.log application error messages (logged via LogError function)

3.2.1. File reference

The EC-Master Demo application consists of the following files:

EcDemoMain.cpp

Entrypoint for the different operating systems

EcDemoPlatform.h

Operating system specific settings (taskpriorities, timer settings)

EcDemoApp.cpp

Initialize, start and terminate the EtherCAT master

EcDemoApp.h

Application specific settings for EcDemoApp

EcDemoParms.cpp

Parsing of command line parameters

EcDemoParms.h

Basic configuration structs and parameters (EtherCAT master parameter)

EcSelectLinkLayer.cpp

Common Functions which abstract the command line parsing into Link Layer parameters

EcNotification.cpp

Slave monitoring and error detection (function emNotify() )

EcSdoServices.cpp

CoE object dictionary example

EcSlaveInfo.cpp

Slave information services (bus scan, slave properties, getting information of slaves connected to the EtherCAT bus)

EcLogging.cpp

Message logging functions

EcTimer.cpp

Start and monitor timeouts

3.2.2. Master lifecycle

This chapter provides a brief overview of starting and stopping the EC-Master. Basically the operation of the EC-Master is wrapped between the functions:

and

The EC-Master is made ready for operation and started with the first two functions mentioned. During this preparation, a thread is set up and started that handles all the cyclic tasks of the EC-Master. The last function stops the EC-Master and clears the memory.

An overview of the complete life cycle as a sequence diagram:

skinparam monochrome true
skinparam SequenceMessageAlign direction
hide footbox

participant EcDemoMain
participant EcDemoApp
participant EcMaster as "EC-Master"
participant EcMasterJobTask
participant EcTimingTask

activate EcDemoMain
EcDemoMain->EcDemoMain : ParseCommandLine()
EcDemoMain->EcDemoMain : InitLogging()
EcDemoMain->EcTimingTask : CreateTimingTask(pvJobTaskEvent)
activate EcTimingTask
EcDemoMain->EcDemoApp : EcDemoApp()

activate EcDemoApp
EcDemoApp->EcDemoApp : InitNotificationHandler()
EcDemoApp->EcMaster : emRasSrvStart()
activate EcMaster
EcDemoApp<--EcMaster
deactivate EcMaster
EcDemoApp->EcMaster : emInitMaster()
activate EcMaster
EcDemoApp<--EcMaster

EcDemoApp->EcMasterJobTask : CreateJobTask()
activate EcMasterJobTask
par
    loop
        EcTimingTask->EcTimingTask : sleep()
        EcTimingTask->EcMasterJobTask : OsSetEvent(pvJobTaskEvent)
        activate EcMasterJobTask
    end
else
    EcMasterJobTask->EcMaster : emExecJob(ProcessAllRxFrames)
    EcMasterJobTask<--EcMaster
    EcMasterJobTask->EcMasterJobTask : myAppWorkPd()
    EcMasterJobTask->EcMaster : emExecJob(SendAllCycFrames)
    EcMasterJobTask<--EcMaster
    EcMasterJobTask->EcMaster : emExecJob(MasterTimer)
    EcMasterJobTask<--EcMaster
    EcMasterJobTask->EcMaster : emExecJob(SendACycFrames)
    EcMasterJobTask<--EcMaster
    deactivate EcMasterJobTask
else
    EcDemoApp->EcMaster : emConfigureMaster()
    EcDemoApp<--EcMaster
    EcDemoApp->EcMaster : emScanBus()
    EcDemoApp<--EcMaster
    EcDemoApp->EcDemoApp : PrintSlaveInfos()
    EcDemoApp->EcMaster : emSetMasterState(eEcatState_OP)
    EcDemoApp<--EcMaster
    EcDemoApp->EcDemoApp : idle()
    EcDemoApp->EcMaster : emSetMasterState(eEcatState_INIT)
    EcDemoApp<--EcMaster
    EcDemoApp->EcMasterJobTask : shutdownJobTask()
    deactivate EcMasterJobTask
end

EcDemoApp->EcMaster : emUnregisterClient()
EcDemoApp<--EcMaster
EcDemoApp->EcMaster : emRasSrvStop()
EcDemoApp<--EcMaster
EcDemoApp->EcMaster : emDeinitMaster()
EcDemoApp<--EcMaster
deactivate EcMaster

EcDemoMain<--EcDemoApp
deactivate EcDemoApp
EcDemoMain->EcTimingTask : shutdownTimingTask()
deactivate EcTimingTask
EcDemoMain->EcDemoMain : DeinitLogging()

A more detailed description of the functions:

EcDemoMain()

A wrapper to start the demo from the respective operating system. In addition to initializing the operating system, parsing command line parameters, and initializing logging, it also starts the timing task.

EcDemoApp()

Demo application. The function takes care of starting and stopping the master and all related tasks. In between, the function runs idle, while all relevant work is done by the EcMasterJobTask().

EcMasterJobTask()

Thread that does the necessary periodic work. Very important here is myAppWorkPd() between eUsrJob_ProcessAllRxFrames and eUsrJob_SendAllCycFrames. Application-specific manipulations of the process image, which must be synchronous with the bus cycle, can be carried out here.

EcTimingTask()

Timing Thread. This thread sets the timing event that triggers the EcMasterJobTask for the next cycle.

emInitMaster()

EC-Master API function: Prepare the master for operation and set operational parameters, e.g. used Link Layer, buffer sizes, maximum number of slaves, … .

emConfigureMaster()

EC-Master API function: Loads the configuration from the ENI (XML file).

emSetMasterState()

EC-Master API function: Startup the EtherCAT master and switch the bus to the different states from INIT to OPERATIONAL.

emDeinitMaster()

EC-Master API function: Clean up.

3.2.3. Synchronization

This chapter puts the tasks or functions, which run in the “tEcJobTask()”, into relation with timing and communication on the EtherCAT bus. See Picture.

Application

Shown are the tasks/jobs (1) through (4) which must be done by the application every single cycle. The details of the individual tasks are described below. When the application is done with the jobs, it waits for the next cycle. (period between (4) and (1)).

In buffer

Shown are the contents of the input section of the process image. The contents are not valid while the EtherCAT master updates the data (1).

Out buffer

Shown are the contents of the output section of the process image. The contents are not valid while the application updates the data (1).

EtherCAT bus

Shown are the timing positions, when the EtherCAT master does cyclic and acyclic communication on the EtherCAT bus. Besides the timing position of the start for the cyclic frames, the shown positions may vary, depending on the number of frames.

In the “EcDemoApp()” application the tasks/jobs (1) through (4) shown in the picture are managed and scheduled by the “tEcJobTask()”. Here a more detailed description:

Job 1

The job "eUsrJob_ProcessAllRxFrames”works on the frames and data received with previous bus activity. This includes cyclic as well as acyclic frames. The received frames are analysed for new input data and the local process image is updated. During this process the input data section of the process image is invalid.

cycle

In the current myAppWorkpd(): Call ELxxxx() slave functions. This is the spot where a user defined application can manipulate the process image. The application has updated input information (from Job 1 above), can do calculations and manipulation, and write new data to the output section of the process image.

Job 2

This function triggers the transmission of all cyclic frames on the EtherCAT bus.

Job 3

The job "eUsrJob_MasterTimer”has administrative charater and are basically necessary to run the timeout timers. There is no interaction with the process image during these calls nor does this call trigger any bus traffic. It is not necessary to run this function with every bus cycle, especially on systems with short cycle times < 1 msec. But it is recommended to run this function with a 1 msec period.

Job 4

With the job "eUsrJob_SendAcycFrames”call, the acyclic frames are scheduled for transmission.

idling

Currently implemented as waiting for the next cycle (triggered by the timing event).

3.2.4. Event notification

The EtherCAT master provides event notification for a great number of events. These events are for example:

  • Bus state change

  • Link state change

  • Working counter errors

Any thread can register for these events to be notified. This is achieved by calling the API function

EC_T_DWORD emRegisterClient(EC_T_DWORD dwInstanceID, EC_PF_NOTIFY pfnNotify, EC_T_VOID *pCallerData, EC_T_REGISTERRESULTS *pRegResults)

In case of the EcMasterDemo the class CEmNotification is provided. It implements the complete framework to catch and handle the EC-Master notifications. The class is instantiated once and registered at the EC-Master with the call emRegisterClient() shown above. The class implements the method ecatNotify() as major entry point (or callback function) for events.

There are two different ways events can be handled. The method of handling an event is primarily determined by the time required to handle the event and the processing context in which the event is to be handled. The methods are described below.

3.2.4.1. Direct notification handling

Smaller events can be handled directly in the context in which they are detected. A possible example of such an event is the detection of a false work counter (WKC). The procedure is as follows:

skinparam monochrome true
skinparam SequenceMessageAlign direction
hide footbox

participant EcMasterJobTask
participant EcMaster as "EC-Master"
participant EcNotification

activate EcMasterJobTask
EcMasterJobTask->EcMaster : emExecJob(ProcessAllRxFrames)

activate EcMaster
EcMaster->EcMaster : Receive Frames
EcMaster->EcMaster : Process Frames
EcMaster->EcMaster : Detect Errors
activate EcMaster
EcMaster->EcNotification : invoke EcMasterNotifyCallback()

activate EcNotification
EcNotification->EcNotification : ecatNoitfy()
EcNotification->: Error Log Message
return

deactivate EcMaster
return

EcMasterJobTask->EcMasterJobTask : myAppWorkPd()

The event handling is reduced to simply issuing a log message, which is not time critical. The event is handled directly within the context of the emExecJob() ( eUsrJob_ProcessAllRxFrames) function.

3.2.4.2. Postponed notification handling

Events that require more time-consuming processing cannot be handled directly in the context in which they are detected. The handling or processing of the event must be postponed. This is accomplished through a queue, which is also readily implemented using the CEmNotification class. The procedure is as follows:

skinparam monochrome true
skinparam SequenceMessageAlign direction
skinparam SequenceBoxBorderColor transparent
hide footbox

participant EcDemoApp
participant EcMasterJobTask
participant EcMaster as "EC-Master"
box
    participant EcNotification
    database Notifications
end box

activate EcDemoApp
activate EcMasterJobTask
EcMasterJobTask->EcMaster : emExecJob(ProcessAllRxFrames)

activate EcMaster
EcMaster->EcMaster : Receive Frames
EcMaster->EcMaster : Process Frames
EcMaster->EcMaster : Detect Errors
activate EcMaster
EcMaster->EcNotification : invoke EcMasterNotifyCallback()

activate EcNotification
EcNotification->EcNotification : ecatNotify()
activate EcNotification
EcNotification->Notifications : EnqueueJob()
deactivate EcNotification
return

deactivate EcMaster
return
deactivate EcMasterJobTask
...
EcDemoApp->EcNotification : ProcessNotificationJobs()
activate EcNotification
EcNotification->Notifications : DequeueJob()
EcNotification<--Notifications
activate EcNotification
EcNotification->EcNotification : Process()
deactivate EcNotification
return

By calling periodically CEmNotification::ProcessNotificationJobs(), the application checks and handles all queued notifications.

Important

The call of CEmNotification::ProcessNotificationJobs() shall NOT be executed in the EcMasterJobTask(). As the CPU time consumption may be high, this would have a high impact to the real-time behavior of the cyclic operation.

3.2.5. Logging

The EcMasteDemo examples demonstrate how log messages can be processed by the application, see Examples/Common/EcLogging.cpp. The messages processed by EcLogging.cpp are of different types, e.g. EC-Master log messages, application messages, DCM messages and are logged to the console and/or files. Identical messages are skipped automatically by default.

Note

With some operating systems, logging in files is deactivated, e.g. because a file system is not available.

3.2.5.1. Parameters

The verbosity of the EcMasteDemo is specified as a -v command line parameter. It is used to determine the log level of the application, see EcDemoMain.cpp. For performance reasons the EC-Master automatically filters log messages according to EC_T_LOG_PARMS::dwLogLevel. EcLogging.cpp has various parameters beside the log level, like Roll Over setting, log task prio and affinity, log buffer size, etc. See EcMasteDemo for reference.

3.2.5.2. Configure EC-Master logging

The EC-Master logging is configured on initialization, see EC_T_INIT_MASTER_PARMS::LogParms in emInitMaster(). The application can provide customized log message handlers of type EC_PF_LOGMSGHK if the default handler in EcLogging.cpp does not fulfill the application’s needs.

Note

The callback is typically called from the EcMasterJobTask’s context and should return as fast as possible.

3.3. Master startup

The master stack has to be initialized once when the application is starting. After this one-time initialization one or more clients may register with the master. Finally, after all clients are registered the master can be started. Starting the master means that all slaves will be set into the operational state. Every time the state of the master has changed the clients are notified about this state-change.

3.3.1. Asynchronous (deferred) startup

skinparam monochrome true
skinparam SequenceMessageAlign direction
hide footbox

activate Client
Client->"EC-Master" : emInitMaster()
activate "EC-Master"
return

Client->Client : Create Job Task

Client->"EC-Master" : emConfigureMaster()
activate "EC-Master"
return

autonumber "<b>(<u>##</u>)"
Client->"EC-Master" : emRegisterClient()
activate "EC-Master"
autonumber stop
return

autonumber resume
Client->"EC-Master" : emSetMasterState(EC_NOWAIT, eEcatState_OP)
activate "EC-Master"
"EC-Master"->Client : return

"EC-Master"->"EC-Master" : INIT
"EC-Master"->Client : emNotify()
autonumber stop
"EC-Master"->"EC-Master" : PREOP
"EC-Master"->Client : emNotify()
"EC-Master"->"EC-Master" : SAFEOP
"EC-Master"->Client : emNotify()
"EC-Master"->"EC-Master" : OP
autonumber resume
"EC-Master"->Client : emNotify()
deactivate "EC-Master"

  • Client calls emInitMaster() (…)

  • Client creates Job Task. See Master lifecycle

  • Client calls emConfigureMaster() (…)

  • Client calls emRegisterClient() (…) (See “1” )

  • Client calls emSetMasterState() (…) with a timeout parameter EC_NOWAIT (See “2” )

  • Function emSetMasterState() (…) returns immediately ( EC_NOWAIT) (See “3” )

  • Inside emSetMasterState() (…) the master startup procedure will be initiated (See “4” )

  • The master initializes all slaves until all slaves reach OPERATIONAL state

  • After every state change the client will be notified (See “5” )

  • After reaching the OPERATIONAL state the system is ready (See “6” )

3.3.2. Synchronous startup

skinparam monochrome true
skinparam SequenceMessageAlign direction
hide footbox

activate Client
Client->"EC-Master" : emInitMaster()
activate "EC-Master"
return

Client->Client : Create Job Task

Client->"EC-Master" : emConfigureMaster()
activate "EC-Master"
return

autonumber "<b>(<u>##</u>)"
Client->"EC-Master" : emRegisterClient()
activate "EC-Master"
autonumber stop
return

autonumber resume
Client->"EC-Master" : emSetMasterState(<Time-out>, eEcatState_OP)
activate "EC-Master"
"EC-Master"->"EC-Master" : INIT
"EC-Master"->"EC-Master" : PREOP
"EC-Master"->"EC-Master" : SAFEOP
"EC-Master"->"EC-Master" : OP
return

  • Client calls emInitMaster() (…)

  • Client creates Job Task. See Master lifecycle

  • Client calls emConfigureMaster() (…)

  • Client calls emRegisterClient() (…) (See “1” )

  • Client calls emSetMasterState() (…) with an appropriate timeout value (See “2” )

  • Inside emSetMasterState() (…) the master startup procedure will be initiated (See “3” )

  • The client is blocked until the whole startup has finished(See “7” )

  • The master initializes all slaves until all slaves reach OPERATIONAL state(See “3-6” )

  • After reaching the OPERATIONAL state the system is ready (See “6” )

  • emSetMasterState() (…)returns(See “7” )

3.4. Process data update and memory

The main task of the EC-Master is the exchange of process data objects between the client and the EtherCAT slaves. All mapped process data objects of the slaves are copied by the master into a process data memory image. New input values received from the slaves are written to the input process data image. New output values to be sent to the slaves are read from the output process data image.

The EC-Master uses two separate buffers where process data input values and process data output values are stored. The buffers used may either be always the same (fixed buffers) or be changed on every process data transfer cycle (dynamic buffers).

The EC-Master has different options for how the process data memory is provided.

  1. EC-Master provides process data memory (fixed buffers)

  2. User application registers an external memory provider with fixed buffers

  3. User application registers an external memory provider with dynamic buffers

3.4.1. EC-Master as process data memory provider

If the application does not register a memory provider, the EC-Master internally allocates the required memory needed to store input and output process data values during emConfigureMaster(). The EC-Master always uses the same buffers for reading/writing process data.

skinparam monochrome true
skinparam  SequenceBoxBorderColor transparent
hide footbox

participant Client
box
participant "EC-Master"
database "PD-Memory"
end box

activate Client

Client->"EC-Master" : emExecJob(eUsrJob_ProcessAllRxFrames)
activate "EC-Master"
"EC-Master"->"EC-Master" : Receive Frames
"EC-Master"->"PD-Memory" : Write Input
return
|||
Client->"EC-Master" : emGetProcessImageInputPtr()
activate "EC-Master"
"EC-Master"->"PD-Memory"
activate "PD-Memory"
"EC-Master"<--"PD-Memory"
deactivate "PD-Memory"
Client<--"EC-Master" : PD Input Pointer
deactivate "EC-Master"
|||
Client<-"PD-Memory" : **Read Input**

Client->Client : Process
|||
Client->"EC-Master" : emGetProcessImageOutputPtr()
activate "EC-Master"
"EC-Master"->"PD-Memory"
activate "PD-Memory"
"EC-Master"<--"PD-Memory"
deactivate "PD-Memory"
Client<--"EC-Master" : PD Output Pointer
deactivate "EC-Master"
|||
Client->"PD-Memory" : **Write Output**
|||
Client->"EC-Master" : emExecJob(eUsrJob_SendAllCycFrames)
activate "EC-Master"
"EC-Master"<-"PD-Memory" : Read Output
"EC-Master"->"EC-Master" : Send Frames
return

3.4.2. Application as process data memory provider with fixed buffers

The application may register a memory provider with emIoControl - EC_IOCTL_REGISTER_PDMEMORYPROVIDER in case the master shall use externally allocated memory to store input and output process data values.

skinparam monochrome true
skinparam  SequenceBoxBorderColor transparent
hide footbox

box
database "PD-Memory"
participant Client
end box
participant "EC-Master"

activate Client

Client->"EC-Master" : emExecJob(eUsrJob_ProcessAllRxFrames)
activate "EC-Master"
"EC-Master"->"EC-Master" : Receive Frames
"EC-Master"->"PD-Memory" : **Write Input**
return
|||
Client<-"PD-Memory" : Read Input
Client->Client : Process
Client->"PD-Memory" : Write Output
|||
Client->"EC-Master" : emExecJob(eUsrJob_SendAllCycFrames)
activate "EC-Master"
"EC-Master"<-"PD-Memory" : **Read Output**
"EC-Master"->"EC-Master" : Send Frames
return

The memory provider may optionally supply callback functions to synchronize memory access between the client and the EC-Master.

Receiving new input process data:
Sending new output process data:

skinparam monochrome true
skinparam  SequenceBoxBorderColor transparent
hide footbox

box
database "PD-Memory"
participant Client
end box
participant "EC-Master"

activate Client
Client->"EC-Master" : emExecJob(eUsrJob_ProcessAllRxFrames)
activate "EC-Master"
"EC-Master"->"EC-Master" : Receive Frames
"EC-Master"->Client : pfPDInDataWriteRequest()
activate "EC-Master"
activate Client
Client-->"EC-Master"
deactivate Client
"EC-Master"->"PD-Memory" : **Write Input**
"EC-Master"->Client : pfPDInDataWriteRelease()
activate Client
Client-->"EC-Master"
deactivate Client
|||
deactivate "EC-Master"
return
|||
Client<-"PD-Memory" : Read Input
Client->Client : Process
Client->"PD-Memory" : Write Output
|||
Client->"EC-Master" : emExecJob(eUsrJob_SendAllCycFrames)
|||
activate "EC-Master"
"EC-Master"->Client : pfPDOutDataReadRequest()
activate "EC-Master"
activate Client
Client-->"EC-Master"
deactivate Client
"EC-Master"<-"PD-Memory" : **Read Output**
"EC-Master"->Client : pfPDOutDataReadRelease()
activate Client
Client-->"EC-Master"
deactivate Client
deactivate "EC-Master"

"EC-Master"->"EC-Master" : Send Frames
return

3.4.3. Application as process data memory provider with dynamic buffers

The application registers an external memory provider without fixed buffers via emIoControl - EC_IOCTL_REGISTER_PDMEMORYPROVIDER with the parameters EC_T_MEMPROV_DESC::pbyPDInData and EC_T_MEMPROV_DESC::pbyPDOutData set to EC_NULL. In this case, the EC-Master requests via the callback functions the buffer addresses cyclically when reading or writing process data. This mode can be used to implement dynamic buffering mechanisms between the application and the EC-Master, e.g. double buffering, triple buffering.

skinparam monochrome true
skinparam  SequenceBoxBorderColor transparent
hide footbox

box
database "PD-Output"
database "PD-Input"
participant Client
end box
participant "EC-Master"

activate Client
Client->"PD-Input" : allocPdInBuffer()
activate "PD-Input"
Client<--"PD-Input" :
|||
Client->"EC-Master" : emExecJob(eUsrJob_ProcessAllRxFrames)
activate "EC-Master"
"EC-Master"->"EC-Master" : Receive Frames
"EC-Master"->Client : pfPDInDataWriteRequest()
activate "EC-Master"
activate Client
Client->"PD-Input" : requestPdInBuffer()
"PD-Input"-->Client
Client-->"EC-Master" : return PdInBuffer
deactivate Client
"EC-Master"->"PD-Input" : **Write Input**
"EC-Master"->Client : pfPDInDataWriteRelease()
activate Client
Client->"PD-Input" : releasePdInBuffer()
Client<--"PD-Input"
Client-->"EC-Master"
deactivate Client
|||
deactivate "EC-Master"
return
|||
Client<-"PD-Input" : Read Input
activate Client
Client->Client : Process
Client->"PD-Input" : freePdInBuffer()
Client<--"PD-Input"
deactivate "PD-Input"
Client->"PD-Output" : allocPdOutBuffer()
activate "PD-Output"
Client<--"PD-Output"
Client->"PD-Output" : Write Output
deactivate Client
|||
Client->"EC-Master" : emExecJob(eUsrJob_SendAllCycFrames)
|||
activate "EC-Master"
"EC-Master"->Client : pfPDOutDataReadRequest()
activate "EC-Master"
activate Client
Client->"PD-Output" : requestPdOutBuffer()
"PD-Output"-->Client
Client-->"EC-Master" : return PdOutBuffer
deactivate Client
"EC-Master"<-"PD-Output" : **Read Output**
"EC-Master"->Client : pfPDOutDataReadRelease()
activate Client
Client->"PD-Output" : freePdOutBuffer()
Client<--"PD-Output"
deactivate "PD-Output"
Client-->"EC-Master"
deactivate Client
deactivate "EC-Master"

"EC-Master"->"EC-Master" : Send Frames
"EC-Master"-->Client

3.5. EtherCAT Network Configuration ENI

For reading new input data values and writing new output data values (process data update) the EtherCAT configuration file contains one or multiple “Cyclic” entries. These entries contain one or multiple frames (so-called cyclic frames) to be sent cyclically by the master. Inside the cyclic frames there are one or multiple EtherCAT datagrams containing logical read/write commands for reading and writing process data values.

3.5.1. Single cyclic entry configuration

In the simplest case, there is only a single cyclic entry with one or more cyclic frames.

All process data synchronization modes support this configuration variant.

3.5.2. Multiple cyclic entries configuration

For more complex scenarios it is possible to configure the system using multiple cyclic entries with one or more cyclic frames for each cyclic entry.

The application has to use the EC_T_USER_JOB::eUsrJob_SendCycFramesByTaskId job call to the master to send the appropriate cyclic frame.

See also

emExecJob()

3.5.3. Copy Information for Slave-to-Slave communication

It is possible to configure the system to copy input variables to output variables within EC-Master. The copy info declarations of the corresponding received cyclic frame are processed in emExecJob(eUsrJob_ProcessAllRxFrames).

The exchange of process data takes two communication cycles. The duration is necessary if cable redundancy is used or if the WKC of INPUT needs to be checked before changing OUTPUT.

The copy info declarations are located at /EtherCATConfig/Config/Cyclic/Frame/Cmd/CopyInfos in the ENI file.

See also

Configuration with EC-Engineer

  1. In the “Slave to Slave” tab of the Master select Input and Output Variable and connect them:

Configuration with ET9000

  1. Select “Linked to…” from the Output Variable:
  2. Select Input Variable to be attached to the Output Variable:

Hint

Copy info declaration processing is independent of WKC values, but updating the INPUT source depends on successful Cyclic cmd WKC validation.

3.5.4. Swap variables’ bytes according to ENI

The following screenshot (ET9000) shows how to configure variables to be swapped by the EC-Master:

Hint

The EC-Master does not distinguish between WORD or BYTE swapping. Setting any PDO swap flag instructs the EC-Master to swap the PDO variable.

The swap declarations are located at DataType’s attribute SwapData of RxPdo or TxPdo, e.g. /EtherCATConfig/Config/Slave/ProcessData/RxPdo/Entry/DataType in the ENI file.

3.6. Process Data Access

The process data, exchanged between the EtherCAT master and the slaves in every cycle, are stored in the process data image. There are two separate memory areas, one for the input data and another one for the output data. The base addresses of these areas are provided by calling the functions emGetProcessImageInputPtr() and emGetProcessImageOutputPtr(). The size of the process data input image is defined in the ENI file under EtherCATConfig/Config/ProcessImage/Inputs/ByteSize and EtherCATConfig/Config/ProcessImage/Outputs/ByteSize.

3.6.1. Process Data Access Functions

Process data variables that are packed as array of bits are bit aligned and not byte aligned in process data. See EC_COPYBITS for how to copy data areas with bit offsets that are not byte aligned. Getting and setting bits that are bit aligned and not byte aligned should be done using EC_SETBITS and EC_GETBITS. Accessing complete EC_T_BYTE, EC_T_WORD, EC_T_DWORD, EC_T_QWORD can be accessed more efficiently using the appropriate macros according to the following table.

Note

These functions do not initiate any transmission on the line. Process data is typically transmitted as little endian and must therefore be swapped on big endian systems such as PPC in order to be correctly interpreted.

Variable type

Bit size

Macro

Hint

EC_T_BYTE

8

N/A

Bytes can be directly addressed at pbyBuffer[BitOffset/8]

EC_T_WORD

16

EC_SET_FRM_WORD, EC_GET_FRM_WORD

Contains swap for big endian systems

EC_T_DWORD

32

EC_SET_FRM_DWORD, EC_GET_FRM_DWORD

Contains swap for big endian systems

EC_T_QWORD

64

EC_SET_FRM_QWORD, EC_GET_FRM_QWORD

Contains swap for big endian systems

Bit

1

EC_SETBITS, EC_GETBITS

Contains swap for big endian systems

3.6.2. Process variables’ offset and size

The following screenshot shows variables’ offset and size within the Process Data Image:

Accessing the process data of a specific slave always works by adding an offset to the base address.

There are different ways possible to get this offset. All offsets are given as bit offsets! The offset values will not change until a new configuration is provided (s.a. emNotify - EC_NOTIFY_CLIENTREGISTRATION_DROPPED ) therefore it is sufficient to load them once right after emConfigureMaster(), it is not needed every cycle.

3.6.3. Process variable access via hard coded offsets

The offset value is determined from the EtherCAT configuration tool. It is not recommended to use fixed values as the offsets will change as slaves are added/removed from the configuration.

As shown in the screenshot above, “Slave_1004 [EL2004].Channel 3.Output” is at offset 1.2 with size 0.1 in the example.

The numbering is Byte.Bit so the offset in the example is Byte 1, Bit 2, Bit offset:

8*1+2 = 10

Bit size

0*8+1 = 1

EC_T_BYTE* pbyPdOut    = emGetProcessImageOutputPtr(dwInstanceId);
EC_T_BYTE  byNewValue  = 0x01;
EC_T_DWORD dwBitOffset = 10;
EC_T_DWORD dwBitSize   = 1;

/* set variable in process data */
EC_SETBITS(pbyPdOut, &byNewValue, dwBitOffset, dwBitSize);

3.6.4. Process variable access via generated PD Layout

The EC-Engineer can export the process variables to a PD-Layout C-Header via the menu item Network ‣ Export Process Variables as shown in the following screenshots:

This will generate a header file containing the slaves’ variables as follows:

#include EC_PACKED_INCLUDESTART(1)
#define PDLAYOUT_OUT_OFFSET_SLAVE_2002 22
typedef struct _T_PDLAYOUT_OUT_SLAVE_2002
{
    EC_T_SWORD  swChannel_1_Output; // Slave_2002 [EL4132].Channel 1.Output ...
    EC_T_SWORD  swChannel_2_Output; // Slave_2002 [EL4132].Channel 2.Output ...
} EC_PACKED(1) T_PDLAYOUT_OUT_SLAVE_2002;
#include EC_PACKED_INCLUDESTOP

Example how a value can be set:

EC_T_BYTE* pbyPdOut = emGetProcessImageOutputPtr(dwInstanceId);
T_PDLAYOUT_OUT_SLAVE_2002* pPdOutSlave2002 = (T_PDLAYOUT_OUT_SLAVE_2002*)(pbyPdOut + PDLAYOUT_OUT_OFFSET_SLAVE_2002);

EC_SET_FRM_WORD(&pPdOutSlave2002->swChannel_1_Output, 42);

3.6.5. Process variable access dynamically from ENI

3.6.5.1. emGetCfgSlaveInfo

The slave offsets can be determined dynamically with the function emGetCfgSlaveInfo(): The offsets are stored in EC_T_CFG_SLAVE_INFO::dwPdOffsIn and EC_T_CFG_SLAVE_INFO::dwPdOffsOut.

Example of how “Slave_1004 [EL2004].Channel 3.Output” can be set:

EC_T_CFG_SLAVE_INFO SlaveInfo;
emGetCfgSlaveInfo(dwInstanceId, EC_TRUE, 1004, &SlaveInfo);

EC_T_BYTE* pbyPdOut    = emGetProcessImageOutputPtr(dwInstanceId);
EC_T_BYTE  byNewValue  = 0x01;
EC_T_DWORD dwBitOffset = SlaveInfo.dwPdOffsOut + 2;
EC_T_DWORD dwBitSize   = 1;

/* set variable in process data */
EC_SETBITS(pbyPdOut, &byNewValue, dwBitOffset, dwBitSize);

3.6.5.2. emFindInpVarByName

The variable offsets can be determined dynamically with the functions emFindInpVarByNameEx() or emFindOutpVarByNameEx(): The offset is stored in EC_T_PROCESS_VAR_INFO::nBitOffs. Each input or output has a unique variable name. All variables names are stored in the ENI file under EtherCATConfig/Config/ProcessImage/Inputs/Variable.

Example of how “Slave_1004 [EL2004].Channel 3.Output” can be set:

EC_T_PROCESS_VAR_INFO_EX ProcVarInfo;
emFindOutpVarByNameEx(dwInstanceId, "Slave_1004 [EL2004].Channel 3.Output", &ProcVarInfo);

EC_T_BYTE* pbyPdOut   = emGetProcessImageOutputPtr(dwInstanceId);
EC_T_BYTE  byNewValue = 0x01;

/* set variable in process data */
EC_SETBITS(pbyPdOut, &byNewValue, ProcVarInfo.nBitOffs, ProcVarInfo.nBitSize);

3.7. Trace Data

Trace Data allows applications to trace data in real time on the network. To ensure real-time transmission, it is implemented as part of the cyclic process data. They are placed behind the slave output data in the output area of the process data image of the EtherCAT application. The trace data area can be configured either via the ENI with the help of the EC-Engineer or without changing the ENI using the API emTraceDataConfig().

Trace Data can be captured with a network monitoring tool like Wireshark.

To transfer the data, an additional NOP cmd is appended to the end of the cyclic EtherCAT frame. The NOP cmd has ADP 0 and ADO 0x4154. The EC-Master automatically fills the data area of the NOP Cmd with the current trace data when sending cyclic frames. Since the trace data are transferred to the network as NOP Cmd, they are not evaluated by any ESC. Therefore, the WKC of the trace data remains 0 and the application cannot validate the data.

3.7.1. Trace Data configuration via EC-Engineer

The easiest and most comfortable way to create trace data variables is with the help of the EC-Engineer. The necessary NOP cmd and the process data variables are automatically created and exported to the ENI. The process variables can be accessed as usual using the emFindOutpVarByNameEx() function.

Trace data variables of any size and number can be created in the Variables tab of the EC-Engineer:
The automatically created variable names can also be edited:
The generated process variables can be found in the exported ENI file:
As well as the NOP cmd:

3.7.2. Trace Data configuration via API

The application can configure the trace data size using the emTraceDataConfig() API. The trace data configuration must take place between the initialization of the EC-Master (emInitMaster()) and the configuration of the network (emConfigureMaster()). During emConfigureMaster() the EC-Master tries to expand the process image output area by the trace data buffer and generates the corresponding NOP cmd.

Access to the trace data buffer is via an offset to the process data output image. The offset can be determined via the API emTraceDataGetInfo().

Configuration of the trace data buffer:

//emInitMaster();

emTraceDataConfig(dwInstanceId, sizeof(EC_T_DWORD));

//emConfigureMaster();

Access to the trace data buffer:

EC_T_TRACE_DATA_INFO oTraceDataInfo;
emTraceDataGetInfo(dwInstanceId, &oTraceDataInfo);

EC_SET_FRM_DWORD(oTraceDataInfo.pbyData + oTraceDataInfo.dwOffset, 0x11223344);

Warning

3.8. Error detection and diagnosis

The EC-Master API generally return EC_E_NOERROR or an error code.

One of the parameters that the client must set when registering with the EC-Master is a generic notification callback function (emNotify()). If an error is detected, the master calls this function.

The EC-Master log messages are enabled if EC_T_LOG_PARMS is configured as described in emInitMaster().

3.8.1. Cyclic cmd WKC validation

New input values received from the slaves will be written into the input process data memory only if the WKC of the corresponding datagram is not 0 and not greater than the configured WKC value.

3.8.2. WKC State in Diagnosis Image

Each cyclic Process Data cmd has its own WKC State bit in the diagnosis image. The state is updated on frame receiving, frame loss detection or link disconnection. All process data variables within a datagram have the same WKC State value. The WKC State bit is set to 1 if the WKC value is not as expected or 0. In case of MSU if all the commands related to the MSU return WKC 0, the WKC State will be set to 1.

The WKC State offset within the Diagnosis Image is available at EC_T_CFG_SLAVE_INFO and EC_T_PROCESS_VAR_INFO_EX, EC_T_MSU_INFO see emGetDiagnosisImagePtr(), emGetCfgSlaveInfo(), emGetSlaveInpVarInfoEx(), emGetSlaveOutpVarInfoEx(), emGetMasterSyncUnitInfo().

The application can check the WKC State of a variable e.g. as follows:

EC_T_CFG_SLAVE_INFO oSlaveInfo;
EC_T_BYTE* pbyDiagnosisImage = emGetDiagnosisImagePtr();
EC_T_BYTE byWkcState = 1;

if (EC_NULL != pbyDiagnosisImage)
{
    if (EC_NOERROR == emGetCfgSlaveInfo(EC_TRUE, 2302, &oSlaveInfo))
    {
        EC_GETBITS(pbyDiagnosisImage, &byWkcState, oSlaveInfo.wWkcStateDiagOffsOut[0], 1);
    }
}

if (1 == byWkcState)
{
    /* ... error ... */
}

3.8.2.1. Behavior in case of automatically adjusted expected WKC value

Optionally, the expected WKC value can be automatically adjusted according the state and the presence of the slaves (AUTO_ADJUST_CYCCMD_WKC, disabled by default). The WKC State bits change synchronized to the corresponding notification, e.g. on link disconnection all slaves disappear and the behavior is as follows:

  • All WKC State bits are set to 1 as missing data is not expected.

  • The Master notifies the application about the link disconnection and the slaves’ disappearing

  • All WKC State bits are set to 0 as it is now expected to have no process data if all slaves are absent.

3.8.3. Master Sync Units

Figure out the MSU offsets by calling the function emGetMasterSyncUnitInfo(), as described in emGetMasterSyncUnitInfo().

3.9. EtherCAT Master Stack Source Code

In a source code delivery the master stack sources are divided into 4 parts:

  • SDK Header files

  • Link layer files (multiple Link Layers may be shipped)

  • Link OS layer files (only valid for the Link Layers)

  • Master stack files (configuration, core and interface layer)

  • OS layer files (only valid for the master stack)

The master stack can be ported to several different operating systems and CPU architectures with different compilers and development environments. Typically no supported build environment files like IDE projects are shipped with the source code.

To build the master stack the appropriate build environment for the target operating system has to be used. If an integrated development environment (IDE) exists (Visual Studio, Eclipse, etc.) several projects containing all necessary files are needed to build the artefacts. If no integrated development environment is available makefiles and dependency rules may have to be created which contain the necessary master stack source and header files.

3.9.1. Components

For most platforms three separate independent binaries will have to be generated:

  1. Link Layer Binary (e.g. a downloadable object moduel in VxWorks or a DLL in Windows). The Link Layer binary will be dynamically bound to the application at runtime. (currently not for On Time RTOS-32 and T-Kernel these use static libraries)

  2. Master Stack Library

  3. Remote API Server Library

3.9.1.2. Master Stack Binaries

The following files have to be included into an IDE project or makefile:

  • Master stack files

  • OS layer files

  • For all platforms a static library has to be created. This library will have to be linked together with the application.

3.9.1.3. Remote API Server Binaries

The following files have to be included into an IDE project or makefile:

  • Remote API server files.

  • For all platforms a static library has to be created. This library will have to be linked together with the application.

See also

Operating Systems (OS) for required tool chain settings

3.9.2. Excluding features

It is possible to reduce the footprint of the master library and improve its execution performance by compiling less features.

EXCLUDE_EOE_ENDPOINT

FP-EoE-Endpoint

EXCLUDE_HOTCONNECT

FP-Hot-Connect

EXCLUDE_JUNCTION_REDUNDANCY

FP-Cable-Redundancy

EXCLUDE_MASTER_OBD

FP-Master-Object-Dictionary

EXCLUDE_RED_DEVICE

FP-Cable-Redundancy

EXCLUDE_SPLITTED_FRAME_PROCESSING

FP-Splitted-Frame-Processing

EXCLUDE_DC_SUPPORT

Class-A

The following defines and their impact are described below:

EXCLUDE_ADS_ADAPTER
emAdsAdapterStart()
emAdsAdapterStop()
EXCLUDE_AOE_SUPPORT
EXCLUDE_BAD_CONNECTIONS
EXCLUDE_CONFIG_EXTEND
EXCLUDE_DCX
DCM DCX mode
EXCLUDE_EEPROM_SUPPORT
EXCLUDE_EOE_DEFFERED_SWITCHING

EC_T_USER_JOB::eUsrJob_SwitchEoeFrames

EXCLUDE_EOE_ENDPOINT

emEoeRegisterEndpoint()

EXCLUDE_EXECJOB_REENTRANCY_SUPPORT

EXCLUDE_FOE_SUPPORT
EXCLUDE_FORCE_PROCESSDATA
EXCLUDE_FRAME_LOGGING
EXCLUDE_FRAME_LOSS_SIMULATION
EXCLUDE_GEN_OP_ENI
EXCLUDE_INTERFACE_LOCK
No API protection against InitMaster/DeinitMaster
EXCLUDE_LINE_CROSSED_DETECTION
No line crossed detection
EXCLUDE_LOG_MESSAGES
No Log messages generated
EXCLUDE_MAILBOX_STATISTICS
EXCLUDE_MASTER_OBD
EXCLUDE_MASTERSYNCUNITS
EXCLUDE_MEMORY_PROVIDER
EXCLUDE_MULTIPLE_CYC_ENTRIES
EXCLUDE_PORT_OPERATION
emBlockNode()
emOpenBlockedPorts()
EXCLUDE_RAWMBX_SUPPORT
EXCLUDE_RED_DEVICE
EXCLUDE_RESCUE_SCAN
EXCLUDE_S2SMBX_SUPPORT
EXCLUDE_SLAVE_HANDLING
EXCLUDE_SLAVE_IDENTIFICATION
/EtherCATConfig/Config/Slave/Info/Identification
EXCLUDE_SLAVE_STATISTICS
EXCLUDE_SOE_SUPPORT
EXCLUDE_SPLITTED_FRAME_PROCESSING
EC_IOCTL_SET_SPLITTED_FRAME_PROCESSING_ENABLED
EXCLUDE_TEXT
ecatGetNotifyText()
EXCLUDE_TRACE_DATA

EXCLUDE_TRACE_DATA_VARINFO
EXCLUDE_VARREAD
EXCLUDE_VOE_SUPPORT
EXCLUDE_WKCSTATE