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 fuction OD_WriteInd_PDOAssignmentParameter is the fuction OD_CalculatePdoOffsets() where the application uses the Ecat_SetIoSizeReq.
That means, if the EtherCAT master writes a sync manger, the application 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()