/**
\addtogroup EcatAppl EtherCAT application
@{
*/
/**
\file ecatappl.c
\author EthercatSSC@beckhoff.com
\brief Implementation
This file contains the Process Data interface
\version 5.11
Changes to version V5.10.1:
V5.11 COE3: change 0x10F3.2 (Sync Error limit) from UINT32 to UINT16 (according to the ETG.1020)
V5.11 ECAT1: update EEPROM access reset operation
V5.11 ECAT10: change PROTO handling to prevent compiler errors
V5.11 ECAT11: create application interface function pointer, add eeprom emulation interface functions
V5.11 ECAT2: update EEPROM access retry cycle (add 10ms delay between two retry cycles)
V5.11 ECAT3: handle bus cycle calculation for input/output only devices and create warning diag message only if calculation failed
V5.11 ECAT4: enhance SM/Sync monitoring for input/output only slaves
V5.11 ECAT6: add function to calculate bus cycle time
V5.11 ECAT8: call PDO_InputMapping only once if DC is enabled and COE is not supported
V5.11 EEPROM1: fix compiler error during pEEPROM pointer initialization
V5.11 EEPROM2: write Station alias value to EEPROM data register on EEPROM reload command
V5.11 EEPROM3: clear EEPROM error bits
V5.11 EEPROM4: prevent the variable in the EEPROM busy loop to be removed by the compiler
V5.11 ESM7: "add Sync define for 0x22 (""SYNCTYPE_SM2_SYNCHRON""), support value 0x22 for 0x1C33.1 (SM2 sync)"
Changes to version V5.01:
V5.10 COE1: Define one entry description for all 0x1C3x objects and change data type of SI11,12,13 to UINT16 (according ETG.1020)
V5.10 ECAT1: Correct calculation of blinking and flashing sequence
V5.10 ECAT13: Update Synchronisation handling (FreeRun,SM Sync, Sync0, Sync1)
Compare DC UINT configuration (by ESC Config data) vs. DC activation register settings
Update 0x1C3x entries
V5.10 ECAT2: Prevent EEPROM data null pointer access (if the pointer is null an command error is set)
EEPROM emulation return command error if unknown command was received
V5.10 ECAT4: Update alignment marco for 8 to 15 bit alignments (16 and 32 Bit controllers)
Bugfix calculate LED blink frequency
V5.10 ECAT7: Add "bInitFinished" to indicate if the initialization is complete
V5.10 HW2: Change HW_GetTimer return value to UINT32
Changes to version V5.0:
V5.01 APPL3: Include library demo application
V5.01 ESC1: Change ESC access function (if EEPROM Emulation is active)
V5.01 ESC2: Add missed value swapping
Changes to version V4.40:
V5.0 TEST1: Add test application. See Application Note ET9300 for more details.
V5.0 ECAT2: Application specific functions are moved to application files.
V5.0 ECAT3: Global dummy variables used for dummy ESC operations.
V5.0 ESC1: ESC 32Bit Access added.
V5.0 ESC3: Add EEPROM emulation support.
V5.0 ESM3: Handling pending ESM transitions.
V5.0 ESC5: Enhance EEPROM access handling.
V5.0 PDO1: AL Event flags are not rechecked in PDO_OutputMappping(). (Already checked before call function)
V5.0 SYNC1: Add missed SM event indication (0x1C32/0x1C33 SI11).
Changes to version V4.30:
V4.40 DIAG1: add diagnosis message support
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.
V4.40 PDO2: Generic process data length calculation
V4.40 ECAT2: call cyclic CheckIfLocalError() to check the local flags
V4.40 HW0: Generic hardware access functions. Add Function (PDI_Isr()), content merged from spihw.c and mcihw.c.
V4.40 WD1: define (ESC_SM_WD_SUPPORTED) to choose ESC SyncManager watchdog or local watchdog
V4.40 ESM2: Change state transition behaviour from SafeOP to OP
V4.40 TIMER1: Change bus cycle time calculation and trigger of ECAT_CheckTimer() if ECAT_TIMER_INT is reset
V4.40 HW1: Add support for fc1100 hardware
Changes to version V4.20:
V4.30 EL9800: EL9800_x cyclic application is moved to el9800.c
V4.30 OBJ 3: add object dictionary initialization
V4.30 SYNC: add CalcSMCycleTime() (calculation of bus cycle time); change synchronisation control functions
V4.30 PDO: include PDO specific functions (moved from coeappl.c).
xxx_InputMapping(); xxx_OutputMapping(); xxx_ReadInputs(); xxx_ResetOutputs(); xxx_Application()
V4.30 CiA402: Add CiA402_StateMachine() and CiA402_Application() call
V4.20 DC 1: Add DC pending Statemachine handling
V4.20 PIC24: Add EL9800_4 (PIC24) required source code
V4.20 LED 1: Modified LED Handling
V4.11 APPL 1: The checkWatchdog() function should not called in checkTimer() if this function is triggered by an Interrupt
Changes to version V4.08:
V4.10 LED 1: The handling of the EtherCAT-Error-LED was added
V4.10 AOE 3: The AoE fragment size has to be initialized during the state transition
from INIT to PREOP
Changes to version V4.07:
V4.08 LED 1: The handling of the EtherCAT-LED can be (de-)selected by the switch LEDS_SUPPORTED
because the ET1100 and ET1200 have an output port which could be connected directly.
Changes to version V4.01:
V4.02 ECAT 1: The watchdog timer variables shall be initialized.
Changes to version V4.00:
V4.01 APPL 1: If the application is running in synchron mode and no SM event
is received, the application should be called from the main loop
V4.01 APPL 2: In FreeRun mode the output should only be copied if the slave is in OP
Changes to version V3.20:
V4.00 APPL 1: The watchdog checking should be done by a microcontroller
timer because the watchdog trigger of the ESC will be reset too
if only a part of the sync manager data is written
V4.00 APPL 2: The setting of EtherCAT state LEDs were included
V4.00 APPL 3: The outputs should be reset to a safe state,
when the state OP is left
V4.00 APPL 4: An example for the EEPROM access through the ESC is shown in
the function APPL_StartMailboxHandler
V4.00 APPL 5: The inputs should be read once when the state transition
from PREOP to SAFEOP is made
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 */
}
/** @} */