Files
DCU_APP/GD32E508_DCU_APP/comm/ssc/src/ecatappl.c
T
cbb 6136c2363f feat(ethercat): 添加LAN9252睡眠挂起机制防止HBI访问冲突
添加了s_pmSuspended状态标志来管理LAN9252的电源管理模式,在芯片进入D1-D3
睡眠状态时阻止HBI访问以避免唤醒问题。同步修改了ethercat_sync中断处理程序,
在睡眠挂起期间跳过HBI相关操作确保芯片能够正常维持睡眠状态。

fix(spi): 提升SPI CS EXTI抢占优先级避免帧丢失

将SPI CS EXTI中断优先级从1提升至0,使其能够抢占PDI/SYNC1等关键中断,确
保SPI帧释放处理能够在微秒级完成,避免因延时导致的ESP32 CS间隔超时和帧
丢失问题。

feat(ssc): 实现OP输入新鲜度不变量监控机制

添加了输入映射序列号监控机制,当PDI路径中断时能够检测到输入数据冻结并
自动触发强制刷新,解决结构洞问题导致的输入数据停止更新现象。

chore(pdo): 更新PDO输入字节注释说明布局变更历史
2026-09-13 18:59:57 +08:00

712 lines
28 KiB
C

/**
\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)];
/*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);
/* 1.6.22:稀疏写 ESC 计划(密排 count 只写有效段; 实现见 ethercat_pdo.cpp) */
extern UINT8 EcatPdo_SparseEscPlan(UINT16 *off0, UINT16 *len0, UINT16 *off1, UINT16 *len1);
/* 1.6.25:差分写 ESC 多段计划(段头/段尾 + 3-buffer 冲刷; 实现见 ethercat_pdo.cpp) */
extern UINT8 EcatPdo_EscWritePlan(UINT16 *offs, UINT16 *lens, UINT8 maxSegs);
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+过程数据写) */
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*/
/*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)
{
/*ECAT_DBG(1.6.0 剖分:输入映射全程 + 过程数据写细分)*/
/* 1.6.22 稀疏写:APPL 仍整填 aPdInputData(对齐 SDO 0x6000),但 HW_EscWriteIsr
* 只写密排有效段+段3/5,跳过空槽区 —— 省的是 PRAM 字节时间,不是 RAM 拷贝。
* 1.6.25 差分写:在稀疏之上再跳过「与影子一致且 3-buffer 冲刷完成」的段。 */
const UINT32 dbgT0 = ecatdbg_dwt();
APPL_InputMapping((UINT16*)aPdInputData);
const UINT32 dbgT1 = ecatdbg_dwt();
{
UINT16 offs[4], lens[4];
const UINT8 nseg = EcatPdo_EscWritePlan(offs, lens, 4U);
if (nseg == 0U) {
HW_EscWriteIsr(((MEM_ADDR *) aPdInputData), nEscAddrInputData, nPdInputSize );
} else {
for (UINT8 i = 0U; i < nseg; ++i) {
HW_EscWriteIsr(((MEM_ADDR *)((UINT8 *)aPdInputData + offs[i])),
(UINT16)(nEscAddrInputData + offs[i]), lens[i]);
}
}
}
g_dbg_inWriteCyc += ecatdbg_dwt() - dbgT1;
g_dbg_inCyc += ecatdbg_dwt() - dbgT0;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function will copies the outputs from the ESC memory to the local memory
to the hardware. This function is only called in case of an SM2
(output process data) event.
1.6.0 输出按需全量读(负载优化):每周期先读输出 PDO 头 12B 探针(覆盖 SEQ@0
与 WIN@8),经 EcatPdo_OutputProbe 判定——seq 无变化沿且无清统计请求时,
跳过 384B 全量读(只补读 SM2 末字完成事件应答),省掉每周期 ~190µs 的
PRAM 搬运(含 ESC 核仲裁等待)。主站滚动窗口扫槽依赖的 WIN 字节在探针内
每周期刷新,窗口扫描不受影响。SM2 应答语义不变:首字(探针内)+末字
(两分支各自覆盖)。
*////////////////////////////////////////////////////////////////////////////////////////
void PDO_OutputMapping(void)
{
/*ECAT_DBG(1.6.0 剖分:输出映射全程)*/
const UINT32 dbgT0 = ecatdbg_dwt();
/* 1.6.0:输出按需全量读——探针 12B 判定是否真的有新输出 */
UINT8 head[12];
HW_EscReadIsr(((MEM_ADDR *) head), nEscAddrOutputData, 12U );
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;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\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)
{
/*ECAT_DBG(1.6.0 剖分:ISR 全程)*/
const UINT32 dbgT0 = ecatdbg_dwt();
if(bEscIntEnabled)
{
/* get the AL event register */
const UINT32 dbgTa = ecatdbg_dwt();
UINT16 ALEvent = HW_GetALEventRegister_Isr();
g_dbg_alCyc += ecatdbg_dwt() - dbgTa;
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*/
const UINT32 dbgTb = ecatdbg_dwt();
ECAT_Application();
g_dbg_appCyc += ecatdbg_dwt() - dbgTb;
}
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 */
const UINT32 dbgTc = ecatdbg_dwt();
PDO_InputMapping();
g_dbg_inCyc += ecatdbg_dwt() - dbgTc;
}
/*
Check if cycle exceed
*/
/*if next SM event was triggered during runtime increment cycle exceed counter*/
const UINT32 dbgTd = ecatdbg_dwt();
ALEvent = HW_GetALEventRegister_Isr();
g_dbg_alCyc += ecatdbg_dwt() - dbgTd;
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)
/*ECAT_DBG(1.6.0 剖分:ISR 全程 收尾)*/
g_dbg_pdiCyc += ecatdbg_dwt() - dbgT0;
g_dbg_pdiCnt++;
}
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();
/*ECAT_DBG(1.6.0 剖分:free-run 应用+输入映射块)*/
{
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;
}
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 */
}
/** @} */