2026-08-09 03:27:21 +08:00
/**
\addtogroup EcatAppl EtherCAT application
@{
*/
/**
\file ecatappl.c
\author EthercatSSC@beckhoff.com
\brief Implementation
This file contains the Process Data interface
\version 5.11
<br>Changes to version V5.10.1:<br>
V5.11 COE3: change 0x10F3.2 (Sync Error limit) from UINT32 to UINT16 (according to the ETG.1020)<br>
V5.11 ECAT1: update EEPROM access reset operation<br>
V5.11 ECAT10: change PROTO handling to prevent compiler errors<br>
V5.11 ECAT11: create application interface function pointer, add eeprom emulation interface functions<br>
V5.11 ECAT2: update EEPROM access retry cycle (add 10ms delay between two retry cycles)<br>
V5.11 ECAT3: handle bus cycle calculation for input/output only devices and create warning diag message only if calculation failed<br>
V5.11 ECAT4: enhance SM/Sync monitoring for input/output only slaves<br>
V5.11 ECAT6: add function to calculate bus cycle time<br>
V5.11 ECAT8: call PDO_InputMapping only once if DC is enabled and COE is not supported<br>
V5.11 EEPROM1: fix compiler error during pEEPROM pointer initialization<br>
V5.11 EEPROM2: write Station alias value to EEPROM data register on EEPROM reload command<br>
V5.11 EEPROM3: clear EEPROM error bits<br>
V5.11 EEPROM4: prevent the variable in the EEPROM busy loop to be removed by the compiler<br>
V5.11 ESM7: "add Sync define for 0x22 (""SYNCTYPE_SM2_SYNCHRON""), support value 0x22 for 0x1C33.1 (SM2 sync)"<br>
<br>Changes to version V5.01:<br>
V5.10 COE1: Define one entry description for all 0x1C3x objects and change data type of SI11,12,13 to UINT16 (according ETG.1020)<br>
V5.10 ECAT1: Correct calculation of blinking and flashing sequence<br>
V5.10 ECAT13: Update Synchronisation handling (FreeRun,SM Sync, Sync0, Sync1)<br>
Compare DC UINT configuration (by ESC Config data) vs. DC activation register settings<br>
Update 0x1C3x entries<br>
V5.10 ECAT2: Prevent EEPROM data null pointer access (if the pointer is null an command error is set)<br>
EEPROM emulation return command error if unknown command was received<br>
V5.10 ECAT4: Update alignment marco for 8 to 15 bit alignments (16 and 32 Bit controllers)<br>
Bugfix calculate LED blink frequency<br>
V5.10 ECAT7: Add "bInitFinished" to indicate if the initialization is complete<br>
V5.10 HW2: Change HW_GetTimer return value to UINT32<br>
<br>Changes to version V5.0:<br>
V5.01 APPL3: Include library demo application<br>
V5.01 ESC1: Change ESC access function (if EEPROM Emulation is active)<br>
V5.01 ESC2: Add missed value swapping<br>
<br>Changes to version V4.40:<br>
V5.0 TEST1: Add test application. See Application Note ET9300 for more details.<br>
V5.0 ECAT2: Application specific functions are moved to application files.<br>
V5.0 ECAT3: Global dummy variables used for dummy ESC operations.<br>
V5.0 ESC1: ESC 32Bit Access added.<br>
V5.0 ESC3: Add EEPROM emulation support.<br>
V5.0 ESM3: Handling pending ESM transitions.<br>
V5.0 ESC5: Enhance EEPROM access handling.<br>
V5.0 PDO1: AL Event flags are not rechecked in PDO_OutputMappping(). (Already checked before call function)<br>
V5.0 SYNC1: Add missed SM event indication (0x1C32/0x1C33 SI11).<br>
<br>Changes to version V4.30:<br>
V4.40 DIAG1: add diagnosis message support<br>
V4.40 PDO1: merge content of HW_InputMapping (spihw.c/mcihw.c) to PDO_InputMapping. merge content of HW_OutputMapping (spihw.c/mcihw.c) to PDO_OutputMapping.<br>
V4.40 PDO2: Generic process data length calculation<br>
V4.40 ECAT2: call cyclic CheckIfLocalError() to check the local flags<br>
V4.40 HW0: Generic hardware access functions. Add Function (PDI_Isr()), content merged from spihw.c and mcihw.c.<br>
V4.40 WD1: define (ESC_SM_WD_SUPPORTED) to choose ESC SyncManager watchdog or local watchdog<br>
V4.40 ESM2: Change state transition behaviour from SafeOP to OP<br>
V4.40 TIMER1: Change bus cycle time calculation and trigger of ECAT_CheckTimer() if ECAT_TIMER_INT is reset<br>
V4.40 HW1: Add support for fc1100 hardware<br>
<br>Changes to version V4.20:<br>
V4.30 EL9800: EL9800_x cyclic application is moved to el9800.c<br>
V4.30 OBJ 3: add object dictionary initialization<br>
V4.30 SYNC: add CalcSMCycleTime() (calculation of bus cycle time); change synchronisation control functions<br>
V4.30 PDO: include PDO specific functions (moved from coeappl.c).<br>
xxx_InputMapping(); xxx_OutputMapping(); xxx_ReadInputs(); xxx_ResetOutputs(); xxx_Application()<br>
V4.30 CiA402: Add CiA402_StateMachine() and CiA402_Application() call<br>
V4.20 DC 1: Add DC pending Statemachine handling<br>
V4.20 PIC24: Add EL9800_4 (PIC24) required source code<br>
V4.20 LED 1: Modified LED Handling<br>
V4.11 APPL 1: The checkWatchdog() function should not called in checkTimer() if this function is triggered by an Interrupt<br>
<br>Changes to version V4.08:<br>
V4.10 LED 1: The handling of the EtherCAT-Error-LED was added<br>
V4.10 AOE 3: The AoE fragment size has to be initialized during the state transition<br>
from INIT to PREOP<br>
<br>Changes to version V4.07:<br>
V4.08 LED 1: The handling of the EtherCAT-LED can be (de-)selected by the switch LEDS_SUPPORTED<br>
because the ET1100 and ET1200 have an output port which could be connected directly.<br>
<br>Changes to version V4.01:<br>
V4.02 ECAT 1: The watchdog timer variables shall be initialized.<br>
<br>Changes to version V4.00:<br>
V4.01 APPL 1: If the application is running in synchron mode and no SM event<br>
is received, the application should be called from the main loop<br>
V4.01 APPL 2: In FreeRun mode the output should only be copied if the slave is in OP<br>
<br>Changes to version V3.20:<br>
V4.00 APPL 1: The watchdog checking should be done by a microcontroller<br>
timer because the watchdog trigger of the ESC will be reset too<br>
if only a part of the sync manager data is written<br>
V4.00 APPL 2: The setting of EtherCAT state LEDs were included<br>
V4.00 APPL 3: The outputs should be reset to a safe state,<br>
when the state OP is left<br>
V4.00 APPL 4: An example for the EEPROM access through the ESC is shown in<br>
the function APPL_StartMailboxHandler<br>
V4.00 APPL 5: The inputs should be read once when the state transition<br>
from PREOP to SAFEOP is made<br>
V4.00 APPL 6: The main function was split in MainInit and MainLoop
*/
/*-----------------------------------------------------------------------------------------
------
------ Includes
------
-----------------------------------------------------------------------------------------*/
#include "ecatslv.h"
#define _ECATAPPL_ 1
#include "ecatappl.h"
#undef _ECATAPPL_
/* ECATCHANGE_START(V5.11) ECAT10*/
/*remove definition of _ECATAPPL_ (#ifdef is used in ecatappl.h)*/
/* ECATCHANGE_END(V5.11) ECAT10*/
#include "coeappl.h"
/* ECATCHANGE_START(V5.11) ECAT11*/
#define _APPL_INTERFACE_ 1
#include "applInterface.h"
#undef _APPL_INTERFACE_
/* ECATCHANGE_END(V5.11) ECAT11*/
#include "el9800appl.h"
/*--------------------------------------------------------------------------------------
------
------ local Types and Defines
------
--------------------------------------------------------------------------------------*/
#ifndef ECAT_TIMER_INC_P_MS
/**
* \todo Define the timer ticks per ms
*/
#warning "Define the timer ticks per ms"
#endif /* #ifndef ECAT_TIMER_INC_P_MS */
/*-----------------------------------------------------------------------------------------
------
------ local variables and constants
------
-----------------------------------------------------------------------------------------*/
/*variables only required to calculate values for SM Synchronisation objects (0x1C3x)*/
UINT16 u16BusCycleCntMs ; //used to calculate the bus cycle time in Ms
UINT32 StartTimerCnt ; //variable to store the timer register value when get cycle time was triggered
BOOL bCycleTimeMeasurementStarted ; // indicates if the bus cycle measurement is started
UINT16 aPdOutputData [( MAX_PD_OUTPUT_SIZE >> 1 )];
UINT16 aPdInputData [( MAX_PD_INPUT_SIZE >> 1 )];
2026-09-06 00:19:18 +08:00
/*ECAT_DBG_START(1.6.0 临时剖分埋点)*/
/* 1.6.0 负载归因埋点:DWT 周期累加器,经 0x2000 sub5..8 上报,主站 1s 差分出速率。
* 只为定位 free-run 模式下每周期 508µs 计入时间的真实去向;定位完成后整块移除。
* EcatDbg_Dwt() 定义在 comm/ethercat_sync.cpp (extern "C")。 */
extern UINT32 EcatDbg_Dwt ( void );
#define ecatdbg_dwt() EcatDbg_Dwt()
/* 1.6.0:输出探针(实现见 comm/ethercat_pdo.cpp,C 链接) */
extern UINT8 EcatPdo_OutputProbe ( UINT8 const * head );
2026-09-12 01:59:42 +08:00
/* 1.6.22:稀疏写 ESC 计划(密排 count 只写有效段; 实现见 ethercat_pdo.cpp) */
extern UINT8 EcatPdo_SparseEscPlan ( UINT16 * off0 , UINT16 * len0 , UINT16 * off1 , UINT16 * len1 );
2026-09-12 20:10:52 +08:00
/* 1.6.25:差分写 ESC 多段计划(段头/段尾 + 3-buffer 冲刷; 实现见 ethercat_pdo.cpp) */
extern UINT8 EcatPdo_EscWritePlan ( UINT16 * offs , UINT16 * lens , UINT8 maxSegs );
2026-09-06 00:19:18 +08:00
volatile UINT32 g_dbg_pdiCyc = 0 ; /* sub5: PDI_Isr 全函数累计周期 */
volatile UINT32 g_dbg_outCyc = 0 ; /* sub6: PDO_OutputMapping(输出探针/全量读) */
volatile UINT32 g_dbg_freerunCyc = 0 ; /* sub7: MainLoop free-run 分支(SM 同步下恒 0) */
volatile UINT32 g_dbg_pdiCnt = 0 ; /* sub8: PDI_Isr 触发次数(=每周期 1 次) */
volatile UINT32 g_dbg_inCyc = 0 ; /* sub9: PDO_InputMapping 全程(APPL+640B 写) */
volatile UINT32 g_dbg_inWriteCyc = 0 ; /* sub10: 其中 HW_EscWriteIsr 640B 过程数据写 */
volatile UINT32 g_dbg_alCyc = 0 ; /* sub11: PDI_Isr 内 AL 事件读×2+超限应答 */
volatile UINT32 g_dbg_appCyc = 0 ; /* sub12: ECAT_Application(桥 processOutput) */
/*ECAT_DBG_END*/
2026-08-09 03:27:21 +08:00
/*variables are declared in ecatslv.c*/
extern VARVOLATILE UINT16 u16dummy ;
BOOL bInitFinished = FALSE ; /** < \brief indicates if the initialization is finished*/
/*-----------------------------------------------------------------------------------------
------
------ local functions
------
-----------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------
------
------ Functions
------
-----------------------------------------------------------------------------------------*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function will copies the inputs from the local memory to the ESC memory
to the hardware
*/ ///////////////////////////////////////////////////////////////////////////////////////
void PDO_InputMapping ( void )
{
2026-09-06 00:19:18 +08:00
/*ECAT_DBG(1.6.0 剖分:输入映射全程 + 640B 写细分)*/
2026-09-12 01:59:42 +08:00
/* 1.6.22 稀疏写:APPL 仍整填 aPdInputData(对齐 SDO 0x6000),但 HW_EscWriteIsr
2026-09-12 20:10:52 +08:00
* 只写密排有效段+段3/5,跳过空槽区 —— 省的是 PRAM 字节时间,不是 RAM 拷贝。
* 1.6.25 差分写:在稀疏之上再跳过「与影子一致且 3-buffer 冲刷完成」的段。 */
2026-09-06 00:19:18 +08:00
const UINT32 dbgT0 = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
APPL_InputMapping (( UINT16 * ) aPdInputData );
2026-09-06 00:19:18 +08:00
const UINT32 dbgT1 = ecatdbg_dwt ();
2026-09-12 01:59:42 +08:00
{
2026-09-12 20:10:52 +08:00
UINT16 offs [ 4 ], lens [ 4 ];
const UINT8 nseg = EcatPdo_EscWritePlan ( offs , lens , 4U );
if ( nseg == 0U ) {
2026-09-12 01:59:42 +08:00
HW_EscWriteIsr ((( MEM_ADDR * ) aPdInputData ), nEscAddrInputData , nPdInputSize );
2026-09-12 20:10:52 +08:00
} else {
for ( UINT8 i = 0U ; i < nseg ; ++ i ) {
HW_EscWriteIsr ((( MEM_ADDR * )(( UINT8 * ) aPdInputData + offs [ i ])),
( UINT16 )( nEscAddrInputData + offs [ i ]), lens [ i ]);
}
2026-09-12 01:59:42 +08:00
}
}
2026-09-06 00:19:18 +08:00
g_dbg_inWriteCyc += ecatdbg_dwt () - dbgT1 ;
g_dbg_inCyc += ecatdbg_dwt () - dbgT0 ;
2026-08-09 03:27:21 +08:00
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function will copies the outputs from the ESC memory to the local memory
2026-09-06 00:19:18 +08:00
to the hardware. This function is only called in case of an SM2
2026-08-09 03:27:21 +08:00
(output process data) event.
2026-09-06 00:19:18 +08:00
1.6.0 输出按需全量读(负载优化):每周期先读输出 PDO 头 12B 探针(覆盖 SEQ@0
与 WIN@8),经 EcatPdo_OutputProbe 判定——seq 无变化沿且无清统计请求时,
跳过 384B 全量读(只补读 SM2 末字完成事件应答),省掉每周期 ~190µs 的
PRAM 搬运(含 ESC 核仲裁等待)。主站滚动窗口扫槽依赖的 WIN 字节在探针内
每周期刷新,窗口扫描不受影响。SM2 应答语义不变:首字(探针内)+末字
(两分支各自覆盖)。
2026-08-09 03:27:21 +08:00
*/ ///////////////////////////////////////////////////////////////////////////////////////
void PDO_OutputMapping ( void )
{
2026-09-06 00:19:18 +08:00
/*ECAT_DBG(1.6.0 剖分:输出映射全程)*/
const UINT32 dbgT0 = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
2026-09-06 00:19:18 +08:00
/* 1.6.0:输出按需全量读——探针 12B 判定是否真的有新输出 */
UINT8 head [ 12 ];
HW_EscReadIsr ((( MEM_ADDR * ) head ), nEscAddrOutputData , 12U );
2026-08-09 03:27:21 +08:00
2026-09-06 00:19:18 +08:00
if ( EcatPdo_OutputProbe ( head ) )
{
HW_EscReadIsr ((( MEM_ADDR * ) aPdOutputData ), nEscAddrOutputData , nPdOutputSize );
APPL_OutputMapping (( UINT16 * ) aPdOutputData );
}
else
{
/* 无新输出:补读 SM2 末字完成事件应答(首字已随探针读过) */
HW_EscReadWordIsr ( u16dummy ,( nEscAddrOutputData + nPdOutputSize - 2 ));
}
g_dbg_outCyc += ecatdbg_dwt () - dbgT0 ;
2026-08-09 03:27:21 +08:00
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function shall be called every 1ms.
\brief If the switch ECAT_TIMER_INT is 0, the watchdog control is implemented without using
\brief interrupts. In this case a local timer register is checked every ECAT_Main cycle
\brief and the function is triggered if 1 ms is elapsed
*/ ///////////////////////////////////////////////////////////////////////////////////////
void ECAT_CheckTimer ( void )
{
if ( sSyncManOutPar . u32CycleTime == 0 )
{
u16BusCycleCntMs ++ ;
}
/*decrement the state transition timeout counter*/
if ( bEcatWaitForAlControlRes && ( EsmTimeoutCounter > 0 ))
{
EsmTimeoutCounter -- ;
}
DC_CheckWatchdog ();
}
/*ECATCHANGE_START(V5.11) ECAT6*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function is called from the PDI_Isr and is used to calculate the bus cycle time
*/ ///////////////////////////////////////////////////////////////////////////////////////
void HandleBusCycleCalculation ( void )
{
/*calculate the cycle time if device is in SM Sync mode and Cycle time was not calculated yet*/
if ( ! bDcSyncActive && bEscIntEnabled )
{
BOOL bTiggerCalcCycleTime = FALSE ;
if ( sSyncManOutPar . u16GetCycleTime == 1 )
bTiggerCalcCycleTime = TRUE ;
if ( bTiggerCalcCycleTime )
{
/*get bus cycle time triggered */
sSyncManOutPar . u32CycleTime = 0 ;
sSyncManOutPar . u16GetCycleTime = 0 ;
sSyncManInPar . u32CycleTime = 0 ;
sSyncManInPar . u16GetCycleTime = 0 ;
u16BusCycleCntMs = 0 ;
bCycleTimeMeasurementStarted = TRUE ;
StartTimerCnt = ( UINT32 ) HW_GetTimer ();
}
else
{
if ( bCycleTimeMeasurementStarted == TRUE )
{
UINT32 CurTimerCnt = ( UINT32 ) HW_GetTimer ();
/*ECATCHANGE_START(V5.11) ECAT3*/
UINT32 CalcCycleTime = 0 ;
#if ECAT_TIMER_INC_P_MS
CalcCycleTime = ( UINT32 ) u16BusCycleCntMs * 1000000 + ((( INT32 )( CurTimerCnt - StartTimerCnt )) * 1000000 / ECAT_TIMER_INC_P_MS ); //get elapsed cycle time in ns
#endif
/*ECATCHANGE_START(V5.11) ECAT4*/
sSyncManOutPar . u32CycleTime = CalcCycleTime ;
/*ECATCHANGE_END(V5.11) ECAT4*/
sSyncManInPar . u32CycleTime = CalcCycleTime ;
u16BusCycleCntMs = 0 ;
StartTimerCnt = 0 ;
bCycleTimeMeasurementStarted = FALSE ;
/*ECATCHANGE_END(V5.11) ECAT3*/
/* CiA402 Motion controller cycle time is only set if DC Synchronisation is active*/
}
}
}
}
/*ECATCHANGE_END(V5.11) ECAT6*/
void PDI_Isr ( void )
{
2026-09-06 00:19:18 +08:00
/*ECAT_DBG(1.6.0 剖分:ISR 全程)*/
const UINT32 dbgT0 = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
if ( bEscIntEnabled )
{
/* get the AL event register */
2026-09-06 00:19:18 +08:00
const UINT32 dbgTa = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
UINT16 ALEvent = HW_GetALEventRegister_Isr ();
2026-09-06 00:19:18 +08:00
g_dbg_alCyc += ecatdbg_dwt () - dbgTa ;
2026-08-09 03:27:21 +08:00
ALEvent = SWAPWORD ( ALEvent );
if ( ALEvent & PROCESS_OUTPUT_EVENT )
{
if ( bDcRunning && bDcSyncActive )
{
/* Reset SM/Sync0 counter. Will be incremented on every Sync0 event*/
u16SmSync0Counter = 0 ;
}
if ( sSyncManOutPar . u16SmEventMissedCounter > 0 )
sSyncManOutPar . u16SmEventMissedCounter -- ;
/*ECATCHANGE_START(V5.11) ECAT6*/
//calculate the bus cycle time if required
HandleBusCycleCalculation ();
/*ECATCHANGE_END(V5.11) ECAT6*/
/* Outputs were updated, set flag for watchdog monitoring */
bEcatFirstOutputsReceived = TRUE ;
/*
handle output process data event
*/
if ( bEcatOutputUpdateRunning )
{
/* slave is in OP, update the outputs */
PDO_OutputMapping ();
}
else
{
/* Just acknowledge the process data event in the INIT,PreOP and SafeOP state */
HW_EscReadWordIsr ( u16dummy , nEscAddrOutputData );
HW_EscReadWordIsr ( u16dummy ,( nEscAddrOutputData + nPdOutputSize - 2 ));
}
}
/*ECATCHANGE_START(V5.11) ECAT4*/
if (( ALEvent & PROCESS_INPUT_EVENT ) && ( nPdOutputSize == 0 ))
{
//calculate the bus cycle time if required
HandleBusCycleCalculation ();
}
/*ECATCHANGE_END(V5.11) ECAT4*/
/*
Call ECAT_Application() in SM Sync mode
*/
if ( sSyncManOutPar . u16SyncType == SYNCTYPE_SM_SYNCHRON )
{
/* The Application is synchronized to process data Sync Manager event*/
2026-09-06 00:19:18 +08:00
const UINT32 dbgTb = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
ECAT_Application ();
2026-09-06 00:19:18 +08:00
g_dbg_appCyc += ecatdbg_dwt () - dbgTb ;
2026-08-09 03:27:21 +08:00
}
if ( bEcatInputUpdateRunning
/*ECATCHANGE_START(V5.11) ESM7*/
&& (( sSyncManInPar . u16SyncType == SYNCTYPE_SM_SYNCHRON ) || ( sSyncManInPar . u16SyncType == SYNCTYPE_SM2_SYNCHRON ))
/*ECATCHANGE_END(V5.11) ESM7*/
)
{
/* EtherCAT slave is at least in SAFE-OPERATIONAL, update inputs */
2026-09-06 00:19:18 +08:00
const UINT32 dbgTc = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
PDO_InputMapping ();
2026-09-06 00:19:18 +08:00
g_dbg_inCyc += ecatdbg_dwt () - dbgTc ;
2026-08-09 03:27:21 +08:00
}
/*
Check if cycle exceed
*/
/*if next SM event was triggered during runtime increment cycle exceed counter*/
2026-09-06 00:19:18 +08:00
const UINT32 dbgTd = ecatdbg_dwt ();
2026-08-09 03:27:21 +08:00
ALEvent = HW_GetALEventRegister_Isr ();
2026-09-06 00:19:18 +08:00
g_dbg_alCyc += ecatdbg_dwt () - dbgTd ;
2026-08-09 03:27:21 +08:00
ALEvent = SWAPWORD ( ALEvent );
if ( ALEvent & PROCESS_OUTPUT_EVENT )
{
sSyncManOutPar . u16CycleExceededCounter ++ ;
sSyncManInPar . u16CycleExceededCounter = sSyncManOutPar . u16CycleExceededCounter ;
/* Acknowledge the process data event*/
HW_EscReadWordIsr ( u16dummy , nEscAddrOutputData );
HW_EscReadWordIsr ( u16dummy ,( nEscAddrOutputData + nPdOutputSize - 2 ));
}
} //if(bEscIntEnabled)
2026-09-06 00:19:18 +08:00
/*ECAT_DBG(1.6.0 剖分:ISR 全程 收尾)*/
g_dbg_pdiCyc += ecatdbg_dwt () - dbgT0 ;
g_dbg_pdiCnt ++ ;
2026-08-09 03:27:21 +08:00
}
void Sync0_Isr ( void )
{
Sync0WdCounter = 0 ;
if ( bDcSyncActive )
{
if ( bEcatInputUpdateRunning )
{
LatchInputSync0Counter ++ ;
}
/*ECATCHANGE_START(V5.11) ECAT4*/
if ( u16SmSync0Value > 0 )
{
/* Check if Sm-Sync sequence is invalid */
if ( u16SmSync0Counter > u16SmSync0Value )
{
/*ECATCHANGE_START(V5.11) COE3*/
if (( nPdOutputSize > 0 ) && ( sSyncManOutPar . u16SmEventMissedCounter <= sErrorSettings . u16SyncErrorCounterLimit ))
{
/*ECATCHANGE_END(V5.11) COE3*/
sSyncManOutPar . u16SmEventMissedCounter = sSyncManOutPar . u16SmEventMissedCounter + 3 ;
}
/*ECATCHANGE_START(V5.11) COE3*/
if (( nPdInputSize > 0 ) && ( nPdOutputSize == 0 ) && ( sSyncManInPar . u16SmEventMissedCounter <= sErrorSettings . u16SyncErrorCounterLimit ))
{
/*ECATCHANGE_END(V5.11) COE3*/
sSyncManInPar . u16SmEventMissedCounter = sSyncManInPar . u16SmEventMissedCounter + 3 ;
}
} // if (u16SmSync0Counter > u16SmSync0Value)
if (( nPdOutputSize == 0 ) && ( nPdInputSize > 0 ))
{
/* Input only with DC, check if the last input data was read*/
UINT16 ALEvent = HW_GetALEventRegister_Isr ();
ALEvent = SWAPWORD ( ALEvent );
if (( ALEvent & PROCESS_INPUT_EVENT ) == 0 )
{
/* no input data was read by the master, increment the sm missed counter*/
u16SmSync0Counter ++ ;
}
else
{
/* Reset SM/Sync0 counter*/
u16SmSync0Counter = 0 ;
sSyncManInPar . u16SmEventMissedCounter = 0 ;
}
}
else
{
u16SmSync0Counter ++ ;
}
} //SM -Sync monitoring enabled
/*ECATCHANGE_END(V5.11) ECAT4*/
if ( ! bEscIntEnabled && bEcatOutputUpdateRunning )
{
/* Output mapping was not done by the PDI ISR */
PDO_OutputMapping ();
}
/* Application is synchronized to SYNC0 event*/
ECAT_Application ();
if ( bEcatInputUpdateRunning
&& ( LatchInputSync0Value > 0 ) && ( LatchInputSync0Value == LatchInputSync0Counter ) ) /* Inputs shall be latched on a specific Sync0 event */
{
/* EtherCAT slave is at least in SAFE-OPERATIONAL, update inputs */
PDO_InputMapping ();
if ( LatchInputSync0Value == 1 )
{
/* if inputs are latched on every Sync0 event (otherwise the counter is reset on the next Sync1 event) */
LatchInputSync0Counter = 0 ;
}
}
}
}
void Sync1_Isr ( void )
{
Sync1WdCounter = 0 ;
if ( bEcatInputUpdateRunning
&& ( sSyncManInPar . u16SyncType == SYNCTYPE_DCSYNC1 )
&& ( LatchInputSync0Value == 0 )) /* Inputs are latched on Sync1 (LatchInputSync0Value == 0), if LatchInputSync0Value > 0 inputs are latched with Sync0 */
{
/* EtherCAT slave is at least in SAFE-OPERATIONAL, update inputs */
PDO_InputMapping ();
}
/* Reset Sync0 latch counter (to start next Sync0 latch cycle) */
LatchInputSync0Counter = 0 ;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function shall called within a 1ms cycle.
Set Run and Error Led depending on the Led state
*/ ///////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pObjectDictionary Pointer to application specific object dictionary.
NULL if no specific object are available.
\return 0 if initialization was successful
\brief This function initialize the EtherCAT Sample Code
*/ ///////////////////////////////////////////////////////////////////////////////////////
UINT16 MainInit ( void )
{
UINT16 Error = 0 ;
/*Hardware init function need to be called from the application layer*/
/*ECATCHANGE_START(V5.11) EEPROM1*/
#ifdef SET_EEPROM_PTR
SET_EEPROM_PTR
#endif
/*ECATCHANGE_END(V5.11) EEPROM1*/
/* initialize the EtherCAT Slave Interface */
ECAT_Init ();
/* initialize the objects */
COE_ObjInit ();
/*Timer initialization*/
u16BusCycleCntMs = 0 ;
StartTimerCnt = 0 ;
bCycleTimeMeasurementStarted = FALSE ;
/*indicate that the slave stack initialization finished*/
bInitFinished = TRUE ;
/*Application Init need to be called from the application layer*/
return Error ;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function shall be called cyclically from main
*/ ///////////////////////////////////////////////////////////////////////////////////////
void MainLoop ( void )
{
/*return if initialization not finished */
if ( bInitFinished == FALSE )
return ;
/* FreeRun-Mode: bEscIntEnabled = FALSE, bDcSyncActive = FALSE
Synchron-Mode: bEscIntEnabled = TRUE, bDcSyncActive = FALSE
DC-Mode: bEscIntEnabled = TRUE, bDcSyncActive = TRUE */
if (
( ! bEscIntEnabled || ! bEcatFirstOutputsReceived ) /* SM-Synchronous, but not SM-event received */
&& ! bDcSyncActive /* DC-Synchronous */
)
{
/* if the application is running in ECAT Synchron Mode the function ECAT_Application is called
from the ESC interrupt routine (in mcihw.c or spihw.c),
in ECAT Synchron Mode it should be additionally checked, if the SM-event is received
at least once (bEcatFirstOutputsReceived = 1), otherwise no interrupt is generated
and the function ECAT_Application has to be called here (with interrupts disabled,
because the SM-event could be generated while executing ECAT_Application) */
if ( ! bEscIntEnabled )
{
/* application is running in ECAT FreeRun Mode,
first we have to check, if outputs were received */
UINT16 ALEvent = HW_GetALEventRegister ();
ALEvent = SWAPWORD ( ALEvent );
if ( ALEvent & PROCESS_OUTPUT_EVENT )
{
/* set the flag for the state machine behaviour */
bEcatFirstOutputsReceived = TRUE ;
if ( bEcatOutputUpdateRunning )
{
/* update the outputs */
PDO_OutputMapping ();
}
}
else if ( nPdOutputSize == 0 )
{
/* if no outputs are transmitted, the watchdog must be reset, when the inputs were read */
if ( ALEvent & PROCESS_INPUT_EVENT )
{
/* Outputs were updated, set flag for watchdog monitoring */
bEcatFirstOutputsReceived = TRUE ;
}
}
}
DISABLE_ESC_INT ();
2026-09-06 00:19:18 +08:00
/*ECAT_DBG(1.6.0 剖分:free-run 应用+输入映射块)*/
2026-08-09 03:27:21 +08:00
{
2026-09-06 00:19:18 +08:00
const UINT32 dbgT1 = ecatdbg_dwt ();
ECAT_Application ();
if ( bEcatInputUpdateRunning )
{
/* EtherCAT slave is at least in SAFE-OPERATIONAL, update inputs */
PDO_InputMapping ();
}
g_dbg_freerunCyc += ecatdbg_dwt () - dbgT1 ;
2026-08-09 03:27:21 +08:00
}
ENABLE_ESC_INT ();
}
#if !ECAT_TIMER_INT
/* there is no interrupt routine for the hardware timer so check the timer register if the desired cycle elapsed*/
{
UINT32 CurTimer = ( UINT32 ) HW_GetTimer ();
if ( CurTimer >= ECAT_TIMER_INC_P_MS )
{
ECAT_CheckTimer ();
HW_ClearTimer ();
}
}
#endif
/* call EtherCAT functions */
ECAT_Main ();
/* call lower prior application part */
COE_Main ();
CheckIfEcatError ();
}
/*The main function was moved to the application files.*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief ECAT_Application (prev. SSC versions "COE_Application")
this function calculates and the physical process signals and triggers the input mapping
*/ ///////////////////////////////////////////////////////////////////////////////////////
void ECAT_Application ( void )
{
APPL_Application ();
/* PDO Input mapping is called from the specific trigger ISR */
}
/** @} */