This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Execute in place "XIP" AM437x beckhoff Ethercat SSC on SYS/BIOS

Other Parts Discussed in Thread: SYSBIOS

Hi all

I just find out we could use XIP on AM437x.

link: e2e.ti.com/.../1871461

So I just wondered if any one could help me on this matter ?

so just I have to mention :

I am using ethercat stack sode "Beckhoff ssc" on AM437x.

and I m using sys/bios.

so please help me in with any application note , or wiki page which helps me to modify GEL file and boot loader firmware.

thanks in advance

  • I will notify the ISDK team to comment on this.
  • Hi Mina, we are working on an application note for AM437x DDRless systems. We have a preliminary presentation (attached) with some steps and changes in order to build EtherCAT slave application and bootloader for using QSPI XIP (NOR + OCMC RAM) or using L3 (L2 as SRAM + OCMC RAM). This is a preliminary work but I hope it helps.

    Thank you,
    Paula

    AM437X_QSPI_XIP_EcatSlave_preliminary.pptx

  • Hi Paula Carrillo

    Thanks for power point slides.very useful .so far we succeeded to run the program from l2 cache and ocmcram.
    I have to mention we did not follow the procedure exactly.

    there was a part which requested to :

    L3 build
    Enabling L2 as SRAM
    File: sbl_am43xx_platform.c
    HW_WR_REG32((0x44E10654), 4);
    HW_WR_REG32((0x44E101E0), 0x10000);

    however if I modify sbl_am43xx_platform.c I will get the following error in debug mode .

    Trouble Writing Memory Block at 0x40500000 on Page 0 of Length 0x7ff0: (Error - 1065 @ 0x3d5A)


    I can solve the error by moving initialization for L2 cache to the gel file :
    C:\ti\ccsv6\ccs_base\emulation\boards\idk_am437x\gel\AM437x_EVMs.gel


    hotmenu AM43xx_IDK_EVM_Initialization()
    {
    GEL_TextOut("**** AM437x IDK EVM Initialization is in progress .......... \n","Output",1,1,1);
    ARM_OPP100_Config(2); //2= IDK with DDR3
    AM43xx_DDR3_config(2); //2 = IDK v1.2
    //***********************************************************************************************************
    //**************************************** Modify ********************************************
    //***********************************************************************************************************
    //Config MPU clock in CTRL_MPUSS Register
    *(unsigned int*)(0x44E10654) = (unsigned int)(4);
    //Enable MPUSS L2 cache as SRAM through CTRL_MPU_L2 Register
    *(unsigned int*)(0x44E101E0) = (unsigned int)(0x10000);
    //***********************************************************************************************************
    //***********************************************************************************************************
    //***********************************************************************************************************
    GEL_TextOut("**** AM437x IDK EVM Initialization is Done ****************** \n\n\n","Output",1,1,1);
    }

    so now I can run the program from internal memory.

    I didn't get time to play with XIP fully ,for XIP I will get back to you later.
  • Hi Thanks for the update!.. and yes, enabling L2 as SRAM through GEL file is also correct
    Paula
  • Hi Paula Carrillo

    thanks for prompt reply .I have few more questions:

    1.how we suppose to boot SRAM and OCMCRAM from QSPI flash?
    as I know all the bootloader in the sdk uses DDR rather than internal on chip memories.
    do You have a sample project for bootloader which we could refer to?

    2.after compiler optimization we are using 220KByte out of 256kByte. so I m thinking for a way to increase code memory ,so I wonder is it possible to share OCMCRAM and SRAM for code memory?

    thanks in advance
    I hope to hear from you soon
  • Hi please import/check "booloader" CCS project from C:\TI\sysbios_ind_sdk_2.1.1.2\sdk\starterware\bootloader. In order to build this project you have to import few other projects to your CCS workspace (ex: dal, device, board, utils, soc, ..) Please check in project's properties -> Libraries in order to get the complete list.

    Also please note that in CCS project configuration (manage configurations) you can select different type of bootloaders. For example you can pick "am43xx_boot_qspi_debug". No sure if you want to, but if you want to ensure DDR is not initialize you can comment it inside sbl_am43xx_platform.c

    Please see below snippet code example, I added few building define symbols in my project in case you want to do the same:

    #ifdef DDR_INIT

    SBLPlatformDdrInit(boardInitPrms.boardId);

    #endif

    #ifdef L2_AS_SRAM

    //PC-- test DDRless (SRAM) EtherCAT slave. Need to init L2 as SRAM

    // AM437X MPUSS_CTRL register offset */

    // CONTROL_SEC_SPARE0 (0x1E0)

    // CONTROL_MPUSS_CTRL (0x654)

    // SOC_CONTROL_MODULE_REG (0x44e10000U)

    HW_WR_REG32((0x44E10654), 4);

    HW_WR_REG32((0x44E101E0), 0x10000);

    I am attaching you sbl_am43xx_platform.c file for your reference

    /**
     *  \file  sbl_am43xx_platform.c
     *
     * \brief  This file contain functions to configure the platform.
     *
     *  \copyright Copyright (C) 2013 Texas Instruments Incorporated -
     *             http://www.ti.com/
     */
    
    /*
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    
    #include "types.h"
    #include "hw_types.h"
    #include "soc_control.h"
    #include "board.h"
    #include "soc.h"
    #include "wdt.h"
    #include "am437x.h"
    #include "hw_cm_wkup.h"
    #include "hw_control_am43xx.h"
    #include "console_utils.h"
    #include "sbl_am43xx_platform_ddr.h"
    #include "sbl_am43xx_platform_pll.h"
    #include "sbl_platform.h"
    
    /* ========================================================================== */
    /*                           Macros & Typedefs                                */
    /* ========================================================================== */
    //PC-- added
    //#define L2_AS_SRAM
    
    /* ========================================================================== */
    /*                         Structures and Enums                               */
    /* ========================================================================== */
    
    
    /* ========================================================================== */
    /*                 Internal Function Declarations                             */
    /* ========================================================================== */
    
    
    /* ========================================================================== */
    /*                            Global Variables Declarations                   */
    /* ========================================================================== */
    
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    
    void SBLPlatformConfig(void)
    {
        uint32_t status = E_FAIL;
        boardInitParams_t boardInitPrms;
    
        status = BOARDInit(NULL);
        CONSOLEUtilsPrintf("BOARDInit status [0x%x]\n", status);
    
        boardInitPrms.boardId = BOARDGetId();
    
        if(BOARD_UNKNOWN == boardInitPrms.boardId)
        {
            /*
             * If UNKNOWN board is detected force it to GP EVM.
             */
            boardInitPrms.boardId = BOARD_GPEVM;
            boardInitPrms.baseBoardRev = BOARD_REV_UNKNOWN;
            boardInitPrms.dcBoardRev = BOARD_REV_UNKNOWN;
            CONSOLEUtilsPrintf("UNKNOWN Board detected. Forcing to GP EVM...\n");
            status = BOARDInit(&boardInitPrms);
            CONSOLEUtilsPrintf("Forced BOARDInit status [0x%x]\n", status);
        }
    
        /* Print SoC & Board Information. */
        SOCPrintInfo();
        BOARDPrintInfo();
    
        /* TODO: Enable WDT module clock in prcm */
        HW_WR_REG32((SOC_WDT1_REG + WDT_WSPR) , 0xAAAAU);
        while(HW_RD_REG32(SOC_WDT1_REG + WDT_WWPS) != 0x00U);
    
        HW_WR_REG32((SOC_WDT1_REG + WDT_WSPR) , 0x5555U);
        while(HW_RD_REG32(SOC_WDT1_REG + WDT_WWPS) != 0x00U);
    
        /* Set the PLL0 to generate 300MHz for ARM */
        SBLPlatformPllInit(boardInitPrms.boardId);
    
        /* Enable the control module */
        HW_WR_REG32((SOC_CM_WKUP_REG + PRCM_CM_WKUP_CTRL_CLKCTRL) ,
                PRCM_CM_WKUP_CTRL_CLKCTRL_MODULEMODE_ENABLE);
        /* TODO: Need to wait till the module is enabled */
    
        /* DDR Initialization */
        //PC-- DDRless test. Avoid init DDR for ensuring DDR less operation
    #ifdef DDR_INIT
        SBLPlatformDdrInit(boardInitPrms.boardId);
    #endif
    #ifdef L2_AS_SRAM
        //PC-- test DDRless (SRAM) EtherCAT slave. Need to init L2 as SRAM
        //   AM437X MPUSS_CTRL register offset */
        //   CONTROL_SEC_SPARE0       (0x1E0)
        //   CONTROL_MPUSS_CTRL       (0x654)
        //   SOC_CONTROL_MODULE_REG   (0x44e10000U)
    
        HW_WR_REG32((0x44E10654), 4);
        HW_WR_REG32((0x44E101E0), 0x10000);
    #endif
    }
    
    void SBLPlatformConfigPostBoot(void)
    {
    }
    
    /* -------------------------------------------------------------------------- */
    /*                 Internal Function Definitions                              */
    /* -------------------------------------------------------------------------- */
    
    
    /* -------------------------------------------------------------------------- */
    /*                 Deprecated Function Declarations                           */
    /* -------------------------------------------------------------------------- */
    

    Also, please keep in mind you can copy Image from flash to OCMCRAM or DDR. You define to where to copy the image adding a "TI header" to the binary. Below a couple of using tiimage.exe

    tiimage.exe 0x40500000 NONE ecat_appl.bin ecat_appl_ti.bin

    tiimage.exe 0x80000000 NONE ecat_appl.bin ecat_appl_ti.bin

     

    However, before adding TI's header you would need to convert your application .out to a .bin you can use arm-none-eabi-objcopy.exe for this. Below an example of the commands I used:

    arm-none-eabi-objcopy.exe -O binary -R .ARM.exidx -R .debug_aranges -R .debug_info -R .debug_abbrev -R .debug_line -R .debug_frame -R .debug_str -R .debug_loc -R .debug_ranges ecat_appl.out ecat_appl.bin

     

    For getting a better idea on how the image is copy and how the program entrance point is determined inside the bootloader please check below functions:

    SBLQspiCopy(), SBLCopyImage(), SblQspiImageCopy()

     

    In case of QSPI XIP we won't need to copy the image, it is already flashed there, so we can just fix the point of entrance (snippet code below, attached file for your reference)

    #ifdef XIP_QSPI

    *pEntryPoint = 0x30080000; //Fixed quick test

    CONSOLEUtilsPrintf("\nPC--Changing entry point to %x\n",pEntryPoint);

    #else

    status = SblQspiImageCopy(pEntryPoint);

    #endif

    /**
     *  \file  sbl_qspi.c
     *
     * \brief  This file copy the application binary from QSPI nor flash to DDR.
     */
    
    /**
     * \copyright  Copyright (C) 2013 Texas Instruments Incorporated -
     *             http://www.ti.com/
     */
    
    /**
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    
    #include "types.h"
    #include "console_utils.h"
    #include "sbl_copy.h"
    #include "sbl_qspi.h"
    #include "error.h"
    #include "qspi_flash.h"
    #include "qspi_lib.h"
    #include "qspi_app.h"
    #include "device.h"
    #include "soc.h"
    #include "board.h"
    #include "pinmux.h"
    #include "prcm.h"
    
    /* ========================================================================== */
    /*                           Macros & Typedefs                                */
    /* ========================================================================== */
    
    /**
     * \brief Instance number for QSPI nor flash
     */
    #define QSPI_FLASH_DEV_INST_NUM 0U
    
    /**
     * \brief Offset from where the application is read from the QSPI flash
     */
    #define OFFSET_ADDR  0x80000U
    
    /** \brief Config base address for QSPI module */
    #define QSPI_CONFIG_BASE_ADDR 0x47900000U
    
    //PC-- added
    //#define XIP_QSPI
    
    /* ========================================================================== */
    /*                         Structures and Enums                               */
    /* ========================================================================== */
    
    /* None */
    
    /* ========================================================================== */
    /*                 Internal Function Declarations                             */
    /* ========================================================================== */
    
    /**
     * \brief This function initializes the QSPI controller.
     *
     * \param instNum  QSPI Instance number.
     */
    static void SblQspiInit(uint32_t instNum);
    
    /**
     * \brief This function copies the application image to the DDR by reading the
     *       header info.
     *
     * \param  pEntryPoint  Entry address read from TI image header.
     *
     * \retval TRUE         Image copy successful.
     * \retval FALSE        Image copy failed.
     */
    static uint32_t SblQspiImageCopy(uint32_t *pEntryPoint);
    
    /**
     * \brief This API gets the board info like instance and chip select.
     *
     * \param pQspiObj Pointer to the flash device object
     *
     * \retval S_PASS    BOARD info successfully retrieved. QSPI is connected to
     *                   serial flash on this board.
     *
     * \retval E_FAIL    This board does not support this boot mode
     *                   - Serial Flash device may not be present on this board.
     *                   - Serial flash may not be connected to QSPI controller.
     *
     */
    static int32_t SblQspiBoardInfoGet(qspiAppObj_t *pQspiObj);
    
    /**
     * \brief  This API gots the soc info - base address of the QSPI instance
     *
     * \param  pQspiObj     Pointer to the flash device object.
     *
     * \retval S_PASS SOC info successfully returned.
     * \retval E_FAIL This SOC does not support this boot mode.
     */
    static int32_t SblQspiSocInfoGet(qspiAppObj_t *pQspiObj);
    
    /* ========================================================================== */
    /*                            Global Variables Declarations                   */
    /* ========================================================================== */
    
    /** \brief  Global structure for QSPI instance related data */
    static qspiAppObj_t gSblQspiObj;
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    
    uint32_t SBLQspiCopy(uint32_t *pEntryPoint, uint32_t instNum)
    {
        uint32_t status;
    
        /* Get Board Info for QSPI*/
        status = SblQspiBoardInfoGet(&gSblQspiObj);
        if(S_PASS == status)
        {
            /* Get SOC info for QSPI*/
            status = SblQspiSocInfoGet(&gSblQspiObj);
            if (S_PASS == status)
            {
                /* Clock configuration for QSPI controller*/
                status = PRCMModuleEnable(CHIPDB_MOD_ID_QSPI,
                                          gSblQspiObj.instNum,
                                          FALSE);
                if(S_PASS == status)
                {
                    /** PinMux for QSPI controller */
                    status = PINMUXModuleConfig(CHIPDB_MOD_ID_QSPI,
                                                gSblQspiObj.instNum,
                                                NULL);
                    if(S_PASS == status)
                    {
                        SblQspiInit(instNum);
                        //PC-- added
    					#ifdef XIP_QSPI
                        	*pEntryPoint = 0x30080000;  //Fixed quick test
                        	CONSOLEUtilsPrintf("\nPC--Changing entry point to %x\n",pEntryPoint);
    					#else
                            status = SblQspiImageCopy(pEntryPoint);
    					#endif
                    }
                    else
                    {
                        CONSOLEUtilsPrintf("\nFAILURE!!\nQSPI Pinmux failed\n");
                    }
                }
                else
                {
                    CONSOLEUtilsPrintf("\nFAILURE!! QSPI clock enable failed\n");
                }
            }
            else
            {
                CONSOLEUtilsPrintf("\nFAILURE!!\n QSPI boot not supported on this SOC ");
            }
        }
        else
        {
            CONSOLEUtilsPrintf("FAILURE!!!\n QSPI boot not supported on this board\n");
        }
        return status;
    }
    
    
    /* -------------------------------------------------------------------------- */
    /*                 Internal Function Definitions                              */
    /* -------------------------------------------------------------------------- */
    
    static uint32_t SblQspiImageCopy(uint32_t *pEntryPoint)
    {
        ti_header imageHdr;
        uint32_t *dstAddr;
        uint32_t retVal = TRUE;
        uint32_t srcOffsetAddr = OFFSET_ADDR;
        /* Read the ti header*/
        QSPILibRead(&gSblQspiObj.qspiLibInfo,
                    srcOffsetAddr,
                    (uint32_t) &imageHdr,
                    8U);
        srcOffsetAddr += 8U;
        CONSOLEUtilsPrintf("\nCopying Header of the application image ");
        dstAddr = (uint32_t *)imageHdr.load_addr;
        *pEntryPoint = imageHdr.load_addr;
    
        CONSOLEUtilsPrintf("\nCopying image from flash to DDR\n\n");
        /* Read image file from QSPI nor flash memory to DDR */
        QSPILibRead(&gSblQspiObj.qspiLibInfo,
                    srcOffsetAddr,
                    (uint32_t) dstAddr,
                    imageHdr.image_size);
        return retVal;
    }
    
    static void SblQspiInit(uint32_t instNum)
    {
        qspiLibCtrlInfo_t qspiLibCtrlInfo;
        /* Set the QSPI config base address */
        qspiLibCtrlInfo.cfgBaseAddr = QSPI_CONFIG_BASE_ADDR;
        /* Set the QSPI memory mapped base Address from chibdb*/
        qspiLibCtrlInfo.memMapBaseAddr = gSblQspiObj.instAddr;
        qspiLibCtrlInfo.chipSelect = gSblQspiObj.chipSelect;
        qspiLibCtrlInfo.qspiLibReadType = QSPI_LIB_READ_TYPE_QUAD;
        qspiLibCtrlInfo.qspiLibTxMode = QSPI_LIB_TX_MODE_MEMORY_MAPPED;
        gSblQspiObj.qspiLibInfo.qspiLibCtrlInfo = qspiLibCtrlInfo;
        /* Initialise the QSPI library */
        QSPILibInit(&gSblQspiObj.qspiLibInfo);
    }
    
    static int32_t SblQspiBoardInfoGet(qspiAppObj_t *pQspiObj)
    {
        int32_t status = E_FAIL;
        chipdbModuleID_t modId;
        uint32_t qspiInstNum;
        uint32_t chipSelect;
        uint32_t devIndex = 0U;
        uint32_t * qspiFlashDeviceIdList;
    
        /* Check which QSPI device is present on this board */
        qspiFlashDeviceIdList = QSPIFlashGetDeviceIdList();
    
        do {
            if (TRUE == BOARDIsDevicePresent(qspiFlashDeviceIdList[devIndex]))
            {
                /* QSPI Device Found */
                pQspiObj->devId = qspiFlashDeviceIdList[devIndex];
                break;
            }
            devIndex++;
        } while (DEVICE_ID_INVALID != qspiFlashDeviceIdList[devIndex]);
    
        if (DEVICE_ID_INVALID == qspiFlashDeviceIdList[devIndex])
        {
            CONSOLEUtilsPrintf("No QSPI device found!\n");
        }
        else
        {
            /* Set the QSPI data for Serial NOR flash from board data */
            modId = BOARDGetDeviceCtrlModId(pQspiObj->devId,
                                            QSPI_FLASH_DEV_INST_NUM);
            if (CHIPDB_MOD_ID_INVALID == modId)
            {
                CONSOLEUtilsPrintf("Invalid device information from board data\n");
            }
            else if (CHIPDB_MOD_ID_QSPI == modId)
            {
                qspiInstNum = BOARDGetDeviceCtrlInfo(pQspiObj->devId,
                    QSPI_FLASH_DEV_INST_NUM);
                chipSelect = BOARDGetDeviceCtrlInfo(pQspiObj->devId,
                    QSPI_FLASH_DEV_INST_NUM);
                if((INVALID_INST_NUM == qspiInstNum) || (INVALID_INFO == chipSelect))
                {
                    CONSOLEUtilsPrintf("Invalid QSPI board data!\n");
                }
                else
                {
                    pQspiObj->instNum = qspiInstNum;
                    pQspiObj->chipSelect  = chipSelect;
                    status = S_PASS;
                }
            }
            else
            {
                CONSOLEUtilsPrintf("This flash is not connected to QSPI\n");
            }
        }
        return (status);
    }
    
    static int32_t SblQspiSocInfoGet(qspiAppObj_t *pQspiObj)
    {
        int32_t status = S_PASS;
        if(TRUE == CHIPDBIsResourcePresent(CHIPDB_MOD_ID_QSPI, pQspiObj->instNum))
        {
            pQspiObj->instAddr = CHIPDBBaseAddress(CHIPDB_MOD_ID_QSPI,
                pQspiObj->instNum);
        }
        else
        {
            /*QSPI instance number is not present . */
            status = E_FAIL;
        }
        return status;
    }
    

    About your second question, you could move some *.text to SRAM.. I did a similar approach when moving *.text from NOR_MEM (QSPI) to OCMCRAM. Please refer to previous attached presentation, and search for "moving critical .text".  Proposed modifications need to be done on the project *.xdt file (in our EtherCAT slave project the file is ecat_appl.xdt)

    Thank you,

    Paula