# Timing ## JobTask: Interaction between application and EtherCAT® network EtherCAT® is a cycle-based fieldbus technology. The EC-Master has no internal tasks and the timing of the cyclic operation is fully controlled by the application. To implement this, the application contains a thread that cyclically calls emExecJob() / ecatExecJob(). Within the emExecJob() calls, the EC-Master sends and processes the EtherCAT® frames and handles internal state machines. This thread is referred to as the *JobTask* . 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 #### NOTE For real-time EtherCAT® applications, this task must be scheduled in real-time. #### NOTE Blocking APIs such as [`emCoeSdoDownload()`](mbx_coe.html.md#_CPPv416emCoeSdoDownload10EC_T_DWORD10EC_T_DWORD9EC_T_WORD9EC_T_BYTEPK9EC_T_BYTE10EC_T_DWORD10EC_T_DWORD10EC_T_DWORD), which depend on the JobTask and wait for results, must not be called within the JobTask as it would result in a lock-up of the JobTask. #### NOTE It is highly recommended that there is a single task calling all required jobs to run the stack as demonstrated in the EcMasterDemo. \\newpage ## Timing models From the application perspective, the EC-Master behaves like a driver that is controlled by the [`emExecJob()`](api_general_functions.html.md#_CPPv49emExecJob10EC_T_DWORD13EC_T_USER_JOBP19EC_T_USER_JOB_PARMS) function with additional parameters, so-called [`EC_T_USER_JOB`](api_general_functions.html.md#_CPPv413EC_T_USER_JOB). Typical sequence of [`EC_T_USER_JOB`](api_general_functions.html.md#_CPPv413EC_T_USER_JOB) for [`emExecJob()`](api_general_functions.html.md#_CPPv49emExecJob10EC_T_DWORD13EC_T_USER_JOBP19EC_T_USER_JOB_PARMS) to be called cyclically by the application: ![Timing diagram showing the recommended per-cycle sequence of eUsrJob calls: ProcessAllRxFrames, SendAllCycFrames, MasterTimer, and SendAcycFrames in a single-thread application](../Media/Timing_CycAcycFrames-Single.png) ![Symbol_CycJob-P](../Media/Timing_CycJob-P.png) Refresh Inputs : [`EC_T_USER_JOB::eUsrJob_ProcessAllRxFrames`](api_general_functions.html.md#_CPPv4N13EC_T_USER_JOB26eUsrJob_ProcessAllRxFramesE): Process all received frames ![Symbol_CycJob-S](../Media/Timing_CycJob-S.png) Write Outputs : [`EC_T_USER_JOB::eUsrJob_SendAllCycFrames`](api_general_functions.html.md#_CPPv4N13EC_T_USER_JOB24eUsrJob_SendAllCycFramesE): Send cyclic frames to update process output data ![Symbol_CycJob-MT](../Media/Timing_CycJob-MT.png) Administration : [`EC_T_USER_JOB::eUsrJob_MasterTimer`](api_general_functions.html.md#_CPPv4N13EC_T_USER_JOB19eUsrJob_MasterTimerE): Trigger MainDevice and SubDevice state machines ![Symbol_CycJob-AS](../Media/Timing_CycJob-AS.png) Send acyclic datagrams/commands : [`EC_T_USER_JOB::eUsrJob_SendAcycFrames`](api_general_functions.html.md#_CPPv4N13EC_T_USER_JOB22eUsrJob_SendAcycFramesE): Transmit pending acyclic frame(s) When a process data update is initiated by calling 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 the output data are read from the process data image and stored in Ethernet/EtherCAT® frames prior to sending them to the Real-time Ethernet Driver. 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 no further output process data synchronization is necessary. The application is responsible to (cyclically) call the function [`emExecJob()`](api_general_functions.html.md#_CPPv49emExecJob10EC_T_DWORD13EC_T_USER_JOBP19EC_T_USER_JOB_PARMS) 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 MainDevice 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 SubDevice state information) - Raw EtherCAT® datagrams requested by application ## Standard EtherCAT® Timing: Short output dead time **Cyclic frames** ![Timing diagram for cyclic frame transmission in polling mode illustrating the short output dead time between writing outputs and the SubDevice receiving them](../Media/Timing_CycFrames-Polling.png) Application has to perform: ```cpp /* 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** ![Timing diagram for combined cyclic and acyclic frame transmission in polling mode with short output dead time](../Media/Timing_CycAcycFrames-Polling.png) Application has to perform: ```cpp /* 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** ![Timing diagram for cyclic frame transmission with Distributed Clocks (DC) synchronization in polling mode and control set value](../Media/Timing_CycFrames-DC-Polling.png) Application has to perform: ```cpp /* 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); ``` \\newpage ## Alternative EtherCAT® Timing: Short Input dead time ![Timing diagram for cyclic and acyclic frame transmission in interrupt mode illustrating the short input dead time alternative timing scheme](../Media/Timing_CycAcycFrames-Interrupt.png) Application has to perform during startup: ```cpp 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: ```cpp /* 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` \\newpage