Skip to end of banner
Go to start of banner

ECS dynamic PDO and MDP Example exercise

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 12 Next »

1. ECS Setup.

Necessary hardware and sotware for this training

The same like in ECS SimpleConfig Example exercise. Follow the steps 1 till 3 and use here now netX 90 - EtherCAT Slave - dynamicPDO V3.0.0.0

2. Create a new PDO

(like in the training ECS CustomOD Example exercise)

go to the file: AppECS_DemoObjectDictionary.h

add new Objects

OBJECT_DESCRIPTION_T g_tObjects[] =
{
  ...
  {
    .usIndex = 0x1602,
    .bMaxNumOfSubObjs = ARRCNT(s_ab1601_Elements),
    .bObjectCode = ODV3_OBJCODE_RECORD,
    .usAccessFlags = 0,
    .bIndicationFlags = 0,
    .usDatatype = ECAT_OD_DTYPE_PDO_MAPPING,
    .usAccessRights = ECAT_OD_READ_ALL,
    /* no SimpleVar, therefore no ulMaxFieldUnits value */
    .pszName = "3. RxPDO",
    /* no SimpleVar, therefore no initial value */
    .ptSi00 = &g_tSiObj_1602[0],
    .ptSiBreak = &g_tSiObj_1602[ ARRCNT(g_tSiObj_1602) ],
  },
  ...
  {
    .usIndex = 0x1C12,
    .bMaxNumOfSubObjs = 3,
	...
  },
  ...
  {
    .usIndex = 0x2002,
    .bMaxNumOfSubObjs = ARRCNT(g_tSiObj_2001) - 1,
    .bObjectCode = ODV3_OBJCODE_RECORD,
    .usAccessFlags = ODV3_ACCESS_FLAGS_RXPDO_MAPPABLE,
    .bIndicationFlags = 0,
    .usDatatype = ECAT_OD_DTYPE_UNSIGNED8,/**< \todo what exactly shall be used here */
    .usAccessRights = ECAT_OD_READ_ALL,
    /* no SimpleVar, therefore no ulMaxFieldUnits value */
    .pszName = "Outputs",
    /* no SimpleVar, therefore no initial value */
    .ptSi00 = &g_tSiObj_2002[0],
    .ptSiBreak = &g_tSiObj_2002[ ARRCNT(g_tSiObj_2002) ],
  },
  ...  
}

add new PDO

static const uint32_t s_ab1602_Elements[] =
{
  PDOMAPPING(0x2002, 1, 8),
};

static const uint8_t s_b1602_NumElements = ARRCNT(s_ab1602_Elements);

SUBOBJECT_DESCRIPTION_T g_tSiObj_1602[] =
{
  {
    .bSubIndex = 0,
    .bIndicationFlags = 0,
    .usAccessRights = ECAT_OD_READ_ALL,
    .usDatatype = ECAT_OD_DTYPE_UNSIGNED8,
    .ulMaxFieldUnits = 1,
    .pszName = "Number of elements",
    .pvInitialValue = &s_b1602_NumElements,
    .ulInitialValueLength = sizeof(s_b1602_NumElements),
  },
  {
    .bSubIndex = 1,
    .bIndicationFlags = 0,
    .usAccessRights = ECAT_OD_READ_ALL,
    .usDatatype = ECAT_OD_DTYPE_UNSIGNED32,
    .ulMaxFieldUnits = 1,
    .pszName = 0,
    .pvInitialValue = &s_ab1602_Elements[0],
    .ulInitialValueLength = sizeof(s_ab1602_Elements[0]),
  },
};

add the new PDO to the SyncManager object

static const uint16_t s_aus1C12_Entries[] = { 0x1600, 0x1601 , 0x1602 };
...
SUBOBJECT_DESCRIPTION_T tSiObj_1C12[] =
{
   ...
  {
    .bSubIndex = 3,
    .bIndicationFlags = 0,
    .usAccessRights = ECAT_OD_READ_ALL|ECAT_OD_WRITE_PREOP, /* for PDO Assignment*/
    .usDatatype = ECAT_OD_DTYPE_UNSIGNED16,
    .ulMaxFieldUnits = 1,
    .pszName = 0,
    .pvInitialValue = &s_aus1C12_Entries[2],
    .ulInitialValueLength = sizeof(s_aus1C12_Entries[2]),
  },
};

add new custom subobject

static const uint8_t s_b2002_NumElements;

SUBOBJECT_DESCRIPTION_T g_tSiObj_2002[] =
{
  {
    .bSubIndex = 0,
    .bIndicationFlags = 0,
    .usAccessRights = ECAT_OD_READ_ALL,
    .usDatatype = ECAT_OD_DTYPE_UNSIGNED8,
    .ulMaxFieldUnits = 1,
    .pszName = "Number of elements",
    .pvInitialValue = &s_b2002_NumElements,
    .ulInitialValueLength = sizeof(s_b2002_NumElements),
  },
  {
    .bSubIndex = 1,
    .bIndicationFlags = 0,
    .usAccessRights = ECAT_OD_ACCESS_ALL,
    .usDatatype = ECAT_OD_DTYPE_UNSIGNED8,
    .ulMaxFieldUnits = 1,
    .pszName = "Outputdata10",
    .pvInitialValue = 0,
    .ulInitialValueLength = 0,
  },
};
static const uint8_t s_b2002_NumElements = ARRCNT(g_tSiObj_2002) - 1; /* SI 00 does not counts */


3. Ecat_SetIoSizeReq

Ecat_SetIoSizeReq is a special request with that the application can tell the stack a changed IO size. This is necessary for dynamic PDO changes.

Go to the file AppECS_DemoApplicationFunctions.c.

Here go to the function AppECS_Write_ObjectInd(...)

Here can be found new source code to recive the syncmanager objects 0x1C12 and 0x1c13.

uint32_t AppECS_Write_ObjectInd(APP_DATA_T *ptAppData, CIFX_PACKET* ptPkt)
{
  ...
  switch ( ptInd->tData.usIndex )
    {
      ...
      case 0x1C12:
         lRet = OD_WriteInd_PDOAssignmentParameter(&tAppECSData, ptAppData, ptReq);
         break;
      case 0x1C13:
         lRet = OD_WriteInd_PDOAssignmentParameter(&tAppECSData, ptAppData, ptReq);
         break;
      default:
         lRet = CIFX_INVALID_PARAMETER;
         break;
    }
  ...
}

Inside of the function OD_WriteInd_PDOAssignmentParameter is the fuction OD_CalculatePdoOffsets() and Ecat_SetIoSizeReq().

That means, if the EtherCAT master writes a sync mangerobject to the ECS slave, the slave application will get this object and it needs to check wtich PDO the EhterCAT master wants and caclulate the new size PDO size.

Because of the new 1 Byte 0x1602, add now some code for 0x1602:

static uint32_t  OD_CalculatePdoOffsets(APP_ECS_DATA_T *ptAppEcsData, APP_DATA_T *ptAppData, ODV3_WRITE_OBJECT_REQ_T* ptPck)
{
  ...
  switch (ptPck->tData.usIndex)
  {
    case 0x1C12:
    {
      for (j = 0;  j < ECS_NUMBER_OF_RX_SUBINDX_INCL_SUB0; j++)
      {
        /* add offset of PDO to list and calculate next offset,
         * usTotalInpuSize was set to 0 before 1st function call*/
        ptAppEcsData->tAssignment.tAssign1C12Temp.OffsetInProcessData[j] = ptAppEcsData->usTotalOutputSize;
        if (ptAppEcsData->tAssignment.tAssign1C12Temp.SubindexEntry[j] == 0x1600)
        {
          /* calculate next offset */
          ptAppEcsData->usTotalOutputSize += 6;
        }
        else if (ptAppEcsData->tAssignment.tAssign1C12Temp.SubindexEntry[j] == 0x1601)
        {
          /* calculate next offset */
          ptAppEcsData->usTotalOutputSize += 4;
        }
        else if (ptAppEcsData->tAssignment.tAssign1C12Temp.SubindexEntry[j] == 0x1602)
        {
          /* calculate next offset */
          ptAppEcsData->usTotalOutputSize += 1;
        }
      }
	  ...
    }
    break;
	...
  }
return lRet;
}

After OD_CalculatePdoOffsets() the application calls Ecat_SetIoSizeReq()


go to file AppECS_DemoApplication.h

#define ECS_NUMBER_OF_RX_SUBINDX_INCL_SUB0  4


The slave application allways needs to decide if  the requested PDO data from EtherCAT master is possbil.

For example, if the slave has plugable input and output hardware. If the slave has only connected input hardware and in the EtherCAT master project is choosen output hardware, than the EtherCAT slave can handle only input data and no output data.

4. ESI Change

add the new PDO in the ESI file

        <Index>#x1602</Index>
          <Name>3. RxPDO</Name>
          <Entry>
            <Index>#x2002</Index>
            <SubIndex>1</SubIndex>
            <BitLen>8</BitLen>
            <Name>1 Byte Out (0)</Name>
            <DataType>BYTE</DataType>
          </Entry>

Hilscher NETX90 RE ECS V5.2.0.xml

5. TwinCAT

Copy the new ESI file to the TwinCAT ESI file folder. In the new project now activate PDO assignment.

under Stuatup the new PDO 1602 can be seen.

set a braekpoint in netX Studio and click on relaod of TwinCAT

6. ESI Change for MDP






  • No labels