How to write an EtherCAT Slave SII image

Background

As mandatory element, each EtherCAT slave has a slave information interface (SII) which is accessible by the master.

Physically, this is a special storage area for slave-specific data in an EEPROM memory chip. Its size is varaiable in the range of 1 kBits – 512 kBits (128 – 65536 Bytes).

For loadable firmware, the size of the SII is limited to 64 K. Because there is no separate EEPROM in the netX chips, the SII is virtually created in the netX.

After configuration, the firmware writes the content of the SII to the virtual EEPROM.


Please find more informations about the SII in the EtherCAT Slave Protocol API:

https://hilscher.atlassian.net/wiki/display/DL/EtherCAT+Slave

Create an SII image

With the help of the Conformance Test Tool (CTT) or TwinCAT, an SII image can be created from an ESI file.

Please first of all delete the RX/TX-PDO blocks from the ESI file, since the CTT and Twincat can only read a maximum of 0xFF "String category blocks". They are also not needed to create an SII image.


Please follow these steps, in case you are using the Conformance Test Tool for creation of an SII image:

  1. Open the Conformance Test Tool.
  2. Scan for any device and open the SII tab.
  3. Select the ESI file from the tab on the right side "ESI Files Repository" and add it to the SII tab via drag and drop.
  4. This can be saved in a *.BIN file now.
  5. Open the *.BIN file in an Hexeditior.
  6. Delete every entry before address 0x080 (first 128 bytes). This area will we written by the stack and is therefore not needed.
  7. change the *.BIN file to a *.c formatted file.

Write the SII image

The follow process needs to be performed, between the Channel Init state and "Bus on".

Therefore the Bus Startup should be changed from "Automatic" to "Controlled by Application", if the stack is configured via database.

This is how it needs to be configured in Sycon.net (other configuration Tools may vary):

After getting the configuration "RCX_CHANNEL_INIT_CNF", call the function "Sii_SetupCategoryData()".

Code snippet LOM

const TLR_UINT8 g_abSiiCategoryData []=
{
0x0A, 0x00, 0x94, 0x00, …
/*Please copy the data from the SII which has been created out of the ESI file here.
Remember not to use the first 128 Byte!*/
};
const unsigned long g_ulSiiCategoryDataSize = sizeof(g_abSiiCategoryData);
/*******************************************************************************
* @brief This function creates a valid SII image for the slave.
* It uses packets to copy the binary image of the category data into
* the SII.
*
* @param ptRsc pointer to resources.
* @param pbCategoryData pointer to image of category data according
* to EtherCAT specification.
* @param ulCategoryDataBytelen byte length of category data array
*
* @return TLR_RESULT returns TLR_S_OK if no error,
* otherwise it will return an error code.
*/
TLR_RESULT Sii_SetupCategoryData(
ECSPX_RSC_T* ptRsc,
const TLR_UINT8* pbCategoryData,
TLR_UINT32 ulCategoryDataBytelen)
{
TLR_RESULT eRslt = TLR_S_OK;
ECAT_ESM_SII_WRITE_REQ_T* ptSiiWriteReq = NULL;
void* pvPck = NULL;
TLR_UINT32 ulImagePos = 0;
TLR_UINT32 ulFragmentLen = 0;
/* we start at position 0 of the image */
ulImagePos = 0x00;
while (ulImagePos < ulCategoryDataBytelen)
{
/* by default we write 0x10 byte fragments */
ulFragmentLen = 0x10;
/* check if our end position is larger than the image of the category data */
if (ulImagePos + ulFragmentLen > ulCategoryDataBytelen)
{
ulFragmentLen = ulCategoryDataBytelen - ulImagePos;
}
/* retrieve a pointer to a resource (packet) of pool */
eRslt = TLR_POOL_PACKET_GET(ptRsc->tLoc.hPool, &pvPck);
if (eRslt != TLR_S_OK)
{
/* leave loop */
break; /* TODO: improve */
}
/* write the fragment */
ptSiiWriteReq = (ECAT_ESM_SII_WRITE_REQ_T*)pvPck;
memset(ptSiiWriteReq, 0, sizeof(ECAT_ESM_SII_WRITE_REQ_T));
/* fill packet header */
ptSiiWriteReq->tHead.ulDest = (UINT32)ptRsc->tRem.tEcsEsmTaskQueLink.hQue;
ptSiiWriteReq->tHead.ulSrc = (UINT32)ptRsc->tLoc.hQue;
ptSiiWriteReq->tHead.ulDestId = 0x00;
ptSiiWriteReq->tHead.ulSrcId = 0x00;
ptSiiWriteReq->tHead.ulLen = 4 + ulFragmentLen;
ptSiiWriteReq->tHead.ulId = 0x00;
ptSiiWriteReq->tHead.ulSta = TLR_S_OK;
ptSiiWriteReq->tHead.ulCmd = ECAT_ESM_SII_WRITE_REQ;
ptSiiWriteReq->tHead.ulExt = 0x00;
ptSiiWriteReq->tHead.ulRout = 0x00;
/* fill data part of packet */
ptSiiWriteReq->tData.ulOffset = ulImagePos + 0x80; /* category data starts at 0x80 of SII */
memcpy((char*)(&ptSiiWriteReq->tData.abData), pbCategoryData + ulImagePos, ulFragmentLen);
/* fire the request */
eRslt = TLR_QUE_SENDPACKET_FIFO_INTERN(ptRsc->tRem.tEcsEsmTaskQueLink.hQue, ptSiiWriteReq, TLR_INFINITE);
/* TODO: TLR_QUE_SENDPACKET_FIFO */
/* TODO: why not TLR_FINITE ? */
if ( eRslt != TLR_S_OK )
{
eRslt = TLR_POOL_PACKET_RELEASE( ptRsc->tLoc.hPool, ptSiiWriteReq );
/* leave loop */
break;
}
/* we wait directly for expected cnf packet */
eRslt = WaitForResponse( ptRsc, (ptSiiWriteReq->tHead.ulCmd | 1) ); /* TODO: improve !! */
if ( eRslt != TLR_S_OK )
{
/* leave loop */
break; /* TODO: improve ? */
}
/* set next start position */
ulImagePos += ulFragmentLen;
}
/* check if error occured */
if ( eRslt != TLR_S_OK )
{
TODO: add error handling */
}
return eRslt;
}

Change the LOM Codesnippet to fit the CIFX API

The paket send function needs to be changed as shown below for use in CIFX API, sind the above code-snippet has been created for LOM Firmware only.

/* packet for sending */
/*__ALIGN4_PRE CIFX_PACKET __ALIGN4_POST tSendPkt = {{0}};*/
CIFX_PACKET tSendPkt = {{0}};
/* packet for writing station alias to SII
* (CRC checksum will be calculated and set by stack)
*/
ECAT_ESM_SII_WRITE_REQ_T* ptWriteSiiReq = (ECAT_ESM_SII_WRITE_REQ_T*)&tSendPkt;
ptSiiWriteReq->tHead.ulDest = 0x20;
ptSiiWriteReq->tHead.ulSrc = 0;
/* fire the request */
tResult = xChannelPutPacket(ptCoEApp->tCommon.hChannel, (CIFX_PACKET*)ptWriteSiiReq, ptCoEApp->tCommon.ulTimeout);