Hello, We've been experimenting with the latest EtherLab release (1.2-rc5) in conjunction with MATLAB 2007B. Aiming to trace issues with a test application of our own, we've had a look at the included example and observed the same: the code generated seems to correctly handle data from input terminals but does not effectively output anything. We verified this by looking at the datagrams on the bus using Wireshark.
Looking at the generated code, we've noticed the lack of any sections writing data to the output PDOs' memory addresses (whereas input data _is_ copied to the corresponding BlockIO structs). Manually adding instructions writing data to a PDO's address results in the data being transmitted as expected but rather defeats the purpose. Has anybody got a clue as to what might be going wrong? I'm attaching the "example.c" file generated from the example included with EtherLab. Any pointers would be much appreciated-- Marco Götze -- Dipl.-Inf. Marco Götze, System Design, +49 (3677) 6955-42 Institut für Mikroelektronik- und Mechatronik-Systeme (IMMS) gGmbH Ehrenbergstr. 27 · D-98693 Ilmenau · <http://www.imms.de/>
/*
* example.c
*
* Real-Time Workshop code generation for Simulink model "example.mdl".
*
* Model Version : 1.19
* Real-Time Workshop version : 7.0 (R2007b) 02-Aug-2007
* C source code generated on : Mon Mar 23 15:41:16 2009
*/
#include "example_capi.h"
#include "example.h"
#include "example_private.h"
/* S-Function Block: <Root>/AIN_0
* Mapped Pdos for block EL3102
*/
struct pdo_map pdo_map_1[] = {
{ 0x3101, 2, 1, EC_DIR_INPUT, si_sint16_T, 16,
&example_DWork.AIN_0_PWORK.DataPtr[0], NULL },
{ 0x3102, 2, 1, EC_DIR_INPUT, si_sint16_T, 16,
&example_DWork.AIN_0_PWORK.DataPtr[1], NULL },
};
/* PDO configuration for EL3102
* with configuration layout 0U
*/
ec_pdo_entry_info_t pdo_entry_info_2_0c1e3052_00000000_0[] = {
{ 0x3101, 1, 8 }, /* 0 */
{ 0x3101, 2, 16 }, /* 1 */
{ 0x3102, 1, 8 }, /* 2 */
{ 0x3102, 2, 16 }, /* 3 */
};
ec_pdo_info_t pdo_info_2_0c1e3052_00000000_0[] = {
{ 0x1A00, 2, &pdo_entry_info_2_0c1e3052_00000000_0[0] },
{ 0x1A01, 2, &pdo_entry_info_2_0c1e3052_00000000_0[2U] },
};
ec_sync_info_t sync_manager_2_0c1e3052_00000000_0[] = {
{ 3U, EC_DIR_INPUT, 2U, &pdo_info_2_0c1e3052_00000000_0[0] },
{ (uint8_T)EC_END, },
};
/* S-Function Block: <Root>/AOUT_0
* Mapped Pdos for block EL4132-IgH Mod
*/
struct pdo_map pdo_map_2[] = {
{ 0x3001, 1, 1, EC_DIR_OUTPUT, si_sint16_T, 16,
&example_DWork.AOUT_0_PWORK.DataPtr[0], NULL },
{ 0x3002, 1, 1, EC_DIR_OUTPUT, si_sint16_T, 16,
&example_DWork.AOUT_0_PWORK.DataPtr[1], NULL },
};
/* PDO configuration for EL4132-IgH Mod
* with configuration layout 0U
*/
ec_pdo_entry_info_t pdo_entry_info_2_10243052_f0000000_0[] = {
{ 0x3001, 1, 16 }, /* 0 */
{ 0x3002, 1, 16 }, /* 1 */
};
ec_pdo_info_t pdo_info_2_10243052_f0000000_0[] = {
{ 0x1600, 1, &pdo_entry_info_2_10243052_f0000000_0[0] },
{ 0x1601, 1, &pdo_entry_info_2_10243052_f0000000_0[1U] },
};
ec_sync_info_t sync_manager_2_10243052_f0000000_0[] = {
{ 2U, EC_DIR_OUTPUT, 2U, &pdo_info_2_10243052_f0000000_0[0] },
{ (uint8_T)EC_END, },
};
/* S-Function Block: <Root>/DIN_0
* Mapped Pdos for block EL1014
*/
struct pdo_map pdo_map_3[] = {
{ 0x3101, 1, 1, EC_DIR_INPUT, si_uint8_T, 1,
&example_DWork.DIN_0_PWORK.DataPtr[0], &example_DWork.DIN_0_IWORK.BitOffset
[0] },
{ 0x3101, 2, 1, EC_DIR_INPUT, si_uint8_T, 1,
&example_DWork.DIN_0_PWORK.DataPtr[1], &example_DWork.DIN_0_IWORK.BitOffset
[1] },
{ 0x3101, 3, 1, EC_DIR_INPUT, si_uint8_T, 1,
&example_DWork.DIN_0_PWORK.DataPtr[2], &example_DWork.DIN_0_IWORK.BitOffset
[2] },
{ 0x3101, 4, 1, EC_DIR_INPUT, si_uint8_T, 1,
&example_DWork.DIN_0_PWORK.DataPtr[3], &example_DWork.DIN_0_IWORK.BitOffset
[3] },
};
/* PDO configuration for EL1014
* with configuration layout 0U
*/
ec_pdo_entry_info_t pdo_entry_info_2_03f63052_00000000_0[] = {
{ 0x3101, 1, 1 }, /* 0 */
{ 0x3101, 2, 1 }, /* 1 */
{ 0x3101, 3, 1 }, /* 2 */
{ 0x3101, 4, 1 }, /* 3 */
};
ec_pdo_info_t pdo_info_2_03f63052_00000000_0[] = {
{ 0x1A00, 1, &pdo_entry_info_2_03f63052_00000000_0[0] },
{ 0x1A01, 1, &pdo_entry_info_2_03f63052_00000000_0[1U] },
{ 0x1A02, 1, &pdo_entry_info_2_03f63052_00000000_0[2U] },
{ 0x1A03, 1, &pdo_entry_info_2_03f63052_00000000_0[3U] },
};
ec_sync_info_t sync_manager_2_03f63052_00000000_0[] = {
{ 0U, EC_DIR_INPUT, 4U, &pdo_info_2_03f63052_00000000_0[0] },
{ (uint8_T)EC_END, },
};
/* S-Function Block: <Root>/DOUT_0
* Mapped Pdos for block EL2004
*/
struct pdo_map pdo_map_4[] = {
{ 0x3001, 1, 1, EC_DIR_OUTPUT, si_uint8_T, 1,
&example_DWork.DOUT_0_PWORK.DataPtr[0],
&example_DWork.DOUT_0_IWORK.BitOffset[0] },
{ 0x3001, 2, 1, EC_DIR_OUTPUT, si_uint8_T, 1,
&example_DWork.DOUT_0_PWORK.DataPtr[1],
&example_DWork.DOUT_0_IWORK.BitOffset[1] },
{ 0x3001, 3, 1, EC_DIR_OUTPUT, si_uint8_T, 1,
&example_DWork.DOUT_0_PWORK.DataPtr[2],
&example_DWork.DOUT_0_IWORK.BitOffset[2] },
{ 0x3001, 4, 1, EC_DIR_OUTPUT, si_uint8_T, 1,
&example_DWork.DOUT_0_PWORK.DataPtr[3],
&example_DWork.DOUT_0_IWORK.BitOffset[3] },
};
/* PDO configuration for EL2004
* with configuration layout 0U
*/
ec_pdo_entry_info_t pdo_entry_info_2_07d43052_00000000_0[] = {
{ 0x3001, 1, 1 }, /* 0 */
{ 0x3001, 2, 1 }, /* 1 */
{ 0x3001, 3, 1 }, /* 2 */
{ 0x3001, 4, 1 }, /* 3 */
};
ec_pdo_info_t pdo_info_2_07d43052_00000000_0[] = {
{ 0x1600, 1, &pdo_entry_info_2_07d43052_00000000_0[0] },
{ 0x1601, 1, &pdo_entry_info_2_07d43052_00000000_0[1U] },
{ 0x1602, 1, &pdo_entry_info_2_07d43052_00000000_0[2U] },
{ 0x1603, 1, &pdo_entry_info_2_07d43052_00000000_0[3U] },
};
ec_sync_info_t sync_manager_2_07d43052_00000000_0[] = {
{ 0U, EC_DIR_OUTPUT, 4U, &pdo_info_2_07d43052_00000000_0[0] },
{ (uint8_T)EC_END, },
};
/* Block signals (auto storage) */
BlockIO_example example_B;
/* Block states (auto storage) */
D_Work_example example_DWork;
/* Real-time model */
RT_MODEL_example example_M_;
RT_MODEL_example *example_M = &example_M_;
/* All EtherLAB error messages go in here */
char etl_errbuf[256];
/* Model output function */
static void example_output(int_T tid)
{
/* user code (Output function Body) */
/* EtherCAT Process for Sample Time [0.001] */
if (1) {
ecs_receive(0);
#ifdef ASYNC_ECAT
ecs_send(0);
#endif
}
{
real_T PulseGenerator_Period;
/* S-Function Block: <Root>/AIN_0 */
/* Output Port 1 */
example_B.AIN_0[0] = *(int16_T*)example_DWork.AIN_0_PWORK.DataPtr[0] /
32768.0;
example_B.AIN_0[1] = *(int16_T*)example_DWork.AIN_0_PWORK.DataPtr[1] /
32768.0;
/* Sin: '<Root>/Sine Wave' */
example_B.SineWave[0] = sin(((real_T)example_DWork.counter[0] +
example_P.SineWave_Offset[0]) * 2.0 * 3.1415926535897931E+00 /
example_P.SineWave_NumSamp) * example_P.SineWave_Amp +
example_P.SineWave_Bias;
example_B.SineWave[1] = sin(((real_T)example_DWork.counter[1] +
example_P.SineWave_Offset[1]) * 2.0 * 3.1415926535897931E+00 /
example_P.SineWave_NumSamp) * example_P.SineWave_Amp +
example_P.SineWave_Bias;
/* S-Function Block: <Root>/DIN_0 */
/* Output Port 1 */
example_B.DIN_0[0] = *(uint8_T*)example_DWork.DIN_0_PWORK.DataPtr[0] >>
example_DWork.DIN_0_IWORK.BitOffset[0] & 1U;
example_B.DIN_0[1] = *(uint8_T*)example_DWork.DIN_0_PWORK.DataPtr[1] >>
example_DWork.DIN_0_IWORK.BitOffset[1] & 1U;
example_B.DIN_0[2] = *(uint8_T*)example_DWork.DIN_0_PWORK.DataPtr[2] >>
example_DWork.DIN_0_IWORK.BitOffset[2] & 1U;
example_B.DIN_0[3] = *(uint8_T*)example_DWork.DIN_0_PWORK.DataPtr[3] >>
example_DWork.DIN_0_IWORK.BitOffset[3] & 1U;
/* DiscretePulseGenerator: '<Root>/Pulse Generator' */
example_B.PulseGenerator[0] = ((real_T)example_DWork.clockTickCounter[0] <
example_P.PulseGenerator_Duty) && (example_DWork.clockTickCounter[0] >= 0)
? example_P.PulseGenerator_Amp : 0.0;
example_B.PulseGenerator[1] = ((real_T)example_DWork.clockTickCounter[1] <
example_P.PulseGenerator_Duty) && (example_DWork.clockTickCounter[1] >= 0)
? example_P.PulseGenerator_Amp : 0.0;
example_B.PulseGenerator[2] = ((real_T)example_DWork.clockTickCounter[2] <
example_P.PulseGenerator_Duty) && (example_DWork.clockTickCounter[2] >= 0)
? example_P.PulseGenerator_Amp : 0.0;
example_B.PulseGenerator[3] = ((real_T)example_DWork.clockTickCounter[3] <
example_P.PulseGenerator_Duty) && (example_DWork.clockTickCounter[3] >= 0)
? example_P.PulseGenerator_Amp : 0.0;
PulseGenerator_Period = example_P.PulseGenerator_Period - 1.0;
if ((real_T)example_DWork.clockTickCounter[0] >= PulseGenerator_Period) {
example_DWork.clockTickCounter[0] = 0;
} else {
example_DWork.clockTickCounter[0] = example_DWork.clockTickCounter[0] + 1;
}
if ((real_T)example_DWork.clockTickCounter[1] >= PulseGenerator_Period) {
example_DWork.clockTickCounter[1] = 0;
} else {
example_DWork.clockTickCounter[1] = example_DWork.clockTickCounter[1] + 1;
}
if ((real_T)example_DWork.clockTickCounter[2] >= PulseGenerator_Period) {
example_DWork.clockTickCounter[2] = 0;
} else {
example_DWork.clockTickCounter[2] = example_DWork.clockTickCounter[2] + 1;
}
if ((real_T)example_DWork.clockTickCounter[3] >= PulseGenerator_Period) {
example_DWork.clockTickCounter[3] = 0;
} else {
example_DWork.clockTickCounter[3] = example_DWork.clockTickCounter[3] + 1;
}
/* DataTypeConversion: '<Root>/Data Type Conversion' */
example_B.DataTypeConversion[0] = (example_B.PulseGenerator[0] != 0.0);
example_B.DataTypeConversion[1] = (example_B.PulseGenerator[1] != 0.0);
example_B.DataTypeConversion[2] = (example_B.PulseGenerator[2] != 0.0);
example_B.DataTypeConversion[3] = (example_B.PulseGenerator[3] != 0.0);
}
UNUSED_PARAMETER(tid);
}
/* Model update function */
static void example_update(int_T tid)
{
/* Update for Sin: '<Root>/Sine Wave' */
example_DWork.counter[0] = example_DWork.counter[0] + 1;
example_DWork.counter[1] = example_DWork.counter[1] + 1;
if ((real_T)example_DWork.counter[0] == example_P.SineWave_NumSamp) {
example_DWork.counter[0] = 0;
}
if ((real_T)example_DWork.counter[1] == example_P.SineWave_NumSamp) {
example_DWork.counter[1] = 0;
}
/* user code (Update function Trailer) */
/* EtherCAT Queue for Sample Time [0.001] */
#ifndef ASYNC_ECAT
if (1) {
ecs_send(0);
}
#endif
/* Update absolute time for base rate */
if (!(++example_M->Timing.clockTick0))
++example_M->Timing.clockTickH0;
example_M->Timing.t[0] = example_M->Timing.clockTick0 *
example_M->Timing.stepSize0 + example_M->Timing.clockTickH0 *
example_M->Timing.stepSize0 * 4294967296.0;
UNUSED_PARAMETER(tid);
}
/* Model initialize function */
void example_initialize(boolean_T firstTime)
{
(void)firstTime;
/* Registration code */
/* initialize non-finites */
rt_InitInfAndNaN(sizeof(real_T)); /* initialize real-time model */
(void) memset((char_T *)example_M,0,
sizeof(RT_MODEL_example));
/* Initialize timing info */
{
int_T *mdlTsMap = example_M->Timing.sampleTimeTaskIDArray;
mdlTsMap[0] = 0;
example_M->Timing.sampleTimeTaskIDPtr = (&mdlTsMap[0]);
example_M->Timing.sampleTimes = (&example_M->Timing.sampleTimesArray[0]);
example_M->Timing.offsetTimes = (&example_M->Timing.offsetTimesArray[0]);
/* task periods */
example_M->Timing.sampleTimes[0] = (0.001);
/* task offsets */
example_M->Timing.offsetTimes[0] = (0.0);
}
rtmSetTPtr(example_M, &example_M->Timing.tArray[0]);
{
int_T *mdlSampleHits = example_M->Timing.sampleHitArray;
mdlSampleHits[0] = 1;
example_M->Timing.sampleHits = (&mdlSampleHits[0]);
}
rtmSetTFinal(example_M, -1);
example_M->Timing.stepSize0 = 0.001;
example_M->solverInfoPtr = (&example_M->solverInfo);
example_M->Timing.stepSize = (0.001);
rtsiSetFixedStepSize(&example_M->solverInfo, 0.001);
rtsiSetSolverMode(&example_M->solverInfo, SOLVER_MODE_SINGLETASKING);
/* block I/O */
example_M->ModelData.blockIO = ((void *) &example_B);
(void) memset(((void *) &example_B),0,
sizeof(BlockIO_example));
{
int_T i;
void *pVoidBlockIORegion;
pVoidBlockIORegion = (void *)(&example_B.AIN_0[0]);
for (i = 0; i < 8; i++) {
((real_T*)pVoidBlockIORegion)[i] = 0.0;
}
}
/* parameters */
example_M->ModelData.defaultParam = ((real_T *) &example_P);
/* states (dwork) */
example_M->Work.dwork = ((void *) &example_DWork);
(void) memset((char_T *) &example_DWork,0,
sizeof(D_Work_example));
/* Initialize DataMapInfo substructure containing ModelMap for C API */
example_InitializeDataMapInfo(example_M);
}
/* Model terminate function */
void example_terminate(void)
{
/* user code (Terminate function Body) */
/* Shutting down EtherCAT subsystem */
ecs_end();
}
/*========================================================================*
* Start of GRT compatible call interface *
*========================================================================*/
void MdlOutputs(int_T tid)
{
example_output(tid);
}
void MdlUpdate(int_T tid)
{
example_update(tid);
}
void MdlInitializeSizes(void)
{
example_M->Sizes.numContStates = (0);/* Number of continuous states */
example_M->Sizes.numY = (0); /* Number of model outputs */
example_M->Sizes.numU = (0); /* Number of model inputs */
example_M->Sizes.sysDirFeedThru = (0);/* The model is not direct feedthrough */
example_M->Sizes.numSampTimes = (1); /* Number of sample times */
example_M->Sizes.numBlocks = (8); /* Number of blocks */
example_M->Sizes.numBlockIO = (5); /* Number of block outputs */
example_M->Sizes.numBlockPrms = (8); /* Sum of parameter "widths" */
}
void MdlInitializeSampleTimes(void)
{
}
void MdlInitialize(void)
{
}
void MdlStart(void)
{
{
/* user code (Start function Header) */
const char __attribute__((unused)) *errstr_rc;
/* Sample times for EtherCAT */
unsigned int ec_st[] = {
1000U,
0U };
/* user code (Start function Body) */
/* Initialising EtherCAT Support system */
if ((errstr_rc = ecs_init( ec_st))) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"Could not initialise EtherCAT Support layer: %s",
errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
{
int32_T Ns[4] = { 0, -125, -375, -250 };
int32_T PulseGenerator_Period;
/* S-Function Block: <Root>/AIN_0
* Registering EtherCAT block EL3102 with Driver
*/
if ((errstr_rc = ecs_reg_slave( 0, /* TID */
/* MasterId, DomainId, SlaveAlias, SlavePosition */
0U, 0U, 0U, 3U,
/* VendorId, ProductCode */
2U, 203305042U,
/* SdoConfigCount, SdoVar */
0, NULL,
/* SyncManager Configuration */
sync_manager_2_0c1e3052_00000000_0,
/* Input/Output Configuration */
2, pdo_map_1))) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"EtherCAT slave example/AIN_0 register "
"failed: %s", errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
/* S-Function Block: <Root>/AOUT_0
* Registering EtherCAT block EL4132-IgH Mod with Driver
*/
if ((errstr_rc = ecs_reg_slave( 0, /* TID */
/* MasterId, DomainId, SlaveAlias, SlavePosition */
0U, 0U, 0U, 4U,
/* VendorId, ProductCode */
2U, 270807122U,
/* SdoConfigCount, SdoVar */
0, NULL,
/* SyncManager Configuration */
sync_manager_2_10243052_f0000000_0,
/* Input/Output Configuration */
2, pdo_map_2))) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"EtherCAT slave example/AOUT_0 register "
"failed: %s", errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
/* S-Function Block: <Root>/DIN_0
* Registering EtherCAT block EL1014 with Driver
*/
if ((errstr_rc = ecs_reg_slave( 0, /* TID */
/* MasterId, DomainId, SlaveAlias, SlavePosition */
0U, 0U, 0U, 1U,
/* VendorId, ProductCode */
2U, 66465874U,
/* SdoConfigCount, SdoVar */
0, NULL,
/* SyncManager Configuration */
sync_manager_2_03f63052_00000000_0,
/* Input/Output Configuration */
4, pdo_map_3))) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"EtherCAT slave example/DIN_0 register "
"failed: %s", errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
/* S-Function Block: <Root>/DOUT_0
* Registering EtherCAT block EL2004 with Driver
*/
if ((errstr_rc = ecs_reg_slave( 0, /* TID */
/* MasterId, DomainId, SlaveAlias, SlavePosition */
0U, 0U, 0U, 2U,
/* VendorId, ProductCode */
2U, 131346514U,
/* SdoConfigCount, SdoVar */
0, NULL,
/* SyncManager Configuration */
sync_manager_2_07d43052_00000000_0,
/* Input/Output Configuration */
4, pdo_map_4))) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"EtherCAT slave example/DOUT_0 register "
"failed: %s", errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
/* Start for DiscretePulseGenerator: '<Root>/Pulse Generator' */
PulseGenerator_Period = (int32_T)example_P.PulseGenerator_Period;
if (Ns[0] <= 0) {
example_DWork.clockTickCounter[0] = Ns[0];
} else {
example_DWork.clockTickCounter[0] = Ns[0] - (int32_T)((real_T)(Ns[0] /
PulseGenerator_Period) * example_P.PulseGenerator_Period);
}
if (Ns[1] <= 0) {
example_DWork.clockTickCounter[1] = Ns[1];
} else {
example_DWork.clockTickCounter[1] = Ns[1] - (int32_T)((real_T)(Ns[1] /
PulseGenerator_Period) * example_P.PulseGenerator_Period);
}
if (Ns[2] <= 0) {
example_DWork.clockTickCounter[2] = Ns[2];
} else {
example_DWork.clockTickCounter[2] = Ns[2] - (int32_T)((real_T)(Ns[2] /
PulseGenerator_Period) * example_P.PulseGenerator_Period);
}
if (Ns[3] <= 0) {
example_DWork.clockTickCounter[3] = Ns[3];
} else {
example_DWork.clockTickCounter[3] = Ns[3] - (int32_T)((real_T)(Ns[3] /
PulseGenerator_Period) * example_P.PulseGenerator_Period);
}
/* S-Function Block: <Root>/Coupler
* Registering EtherCAT block EK1100 with Driver
*/
if ((errstr_rc = ecs_reg_slave( 0, /* TID */
/* MasterId, DomainId, SlaveAlias, SlavePosition */
0U, 0U, 0U, 0U,
/* VendorId, ProductCode */
2U, 72100946U,
/* SdoConfigCount, SdoVar */
0, NULL,
/* SyncManager Configuration */
NULL,
/* Input/Output Configuration */
0, NULL))) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"EtherCAT slave example/Coupler register "
"failed: %s", errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
}
/* user code (Start function Trailer) */
/* Starting EtherCAT subsystem */
if ((errstr_rc = ecs_start())) {
snprintf(etl_errbuf, sizeof(etl_errbuf),
"Starting EtherCAT subsystem failed: %s", errstr_rc);
rtmSetErrorStatus(example_M, etl_errbuf);
return;
}
}
MdlInitialize();
}
RT_MODEL_example *example(void)
{
example_initialize(1);
return example_M;
}
void MdlTerminate(void)
{
example_terminate();
}
/*========================================================================*
* End of GRT compatible call interface *
*========================================================================*/
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ etherlab-users mailing list [email protected] http://lists.etherlab.org/mailman/listinfo/etherlab-users
