添加了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输入字节注释说明布局变更历史
712 lines
28 KiB
C
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 */
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @} */
|
|
|