diff --git a/db/Beckhoff_7XXX/ecmcELM7222-0010.substitutions b/db/Beckhoff_7XXX/ecmcELM7222-0010.substitutions new file mode 100644 index 000000000..61e7f46e9 --- /dev/null +++ b/db/Beckhoff_7XXX/ecmcELM7222-0010.substitutions @@ -0,0 +1,13 @@ +file "ecmcEL72XX_DRV.template" +{ + pattern {CH_ID} + {01 } + {02 } +} + +file "ecmcEL72XX_ENC.template" +{ + pattern {CH_ID} + {01 } + {02 } +} diff --git a/examples/test/elm7222/cfg/AM8112_ch1.yaml b/examples/test/elm7222/cfg/AM8112_ch1.yaml new file mode 100644 index 000000000..1112d8b7b --- /dev/null +++ b/examples/test/elm7222/cfg/AM8112_ch1.yaml @@ -0,0 +1,71 @@ +axis: + id: 1 + type: joint # this is for future selection of axis type + mode: CSV # supported mode, CSV and CSP + +epics: + name: axis + precision: 3 + unit: deg + motorRecord: + enable: true + description: AM8112 CSV CH1 + +drive: + numerator: 2880000 # Fastest speed in engineering units + denominator: 2147483648 # I/O range for ECMC_EC_ALIAS_DRV_VELO_SET + type: 1 # Stepper: 0. DS402: 1 (DS402 = servos and advanced stepper drives) + control: ec0.s$(DRV_SLAVE).driveControl01 + status: ec0.s$(DRV_SLAVE).driveStatus01 + setpoint: ec0.s$(DRV_SLAVE).velocitySetpoint01 + # control bit for reset in 'control' + reset: 7 + # status bit for warning in 'status' + warning: 7 + # list of error bits in 'status', or if type==string, complete EC-link + error: + - 3 # Error + - 7 # Warning as Error + +encoder: + numerator: 360 + denominator: 1048576 + type: 1 # Type: 0=Incremental, 1=Absolute + bits: 32 # Total bit count of encoder raw data + absBits: 25 # Absolute bit count (for absolute encoders) always least significant part of 'bits' + absOffset: 0 # Encoder offset in eng units (for absolute encoders) + position: ec0.s$(DRV_SLAVE).positionActual01 # Ethercat entry for actual position input (encoder) + +controller: + Kp: 15 + Ki: 0.05 + +trajectory: + type: 1 + axis: + velocity: 18000 # 5000 rpm (web page), 7883 rpm (name plate) => 47298 deg/s + acceleration: 90000 + jerk: 360000 + +input: + limit: + forward: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for low limit switch input + backward: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for high limit switch input + home: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for home switch input + interlock: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for interlock switch input + +monitoring: + lag: + enable: true + tolerance: 360 + time: 100 + target: + enable: yes + tolerance: 0.1 + time: 100 + velocity: + enable: true + max: 28000 + time: + trajectory: 100 + drive: 200 diff --git a/examples/test/elm7222/cfg/AM8112_ch2.yaml b/examples/test/elm7222/cfg/AM8112_ch2.yaml new file mode 100644 index 000000000..bbbadfc07 --- /dev/null +++ b/examples/test/elm7222/cfg/AM8112_ch2.yaml @@ -0,0 +1,71 @@ +axis: + id: 1 + type: joint # this is for future selection of axis type + mode: CSV # supported mode, CSV and CSP + +epics: + name: axis + precision: 3 + unit: deg + motorRecord: + enable: true + description: AM8112 CSV CH2 + +drive: + numerator: 2880000 # Fastest speed in engineering units + denominator: 2147483648 # I/O range for ECMC_EC_ALIAS_DRV_VELO_SET + type: 1 # Stepper: 0. DS402: 1 (DS402 = servos and advanced stepper drives) + control: ec0.s$(DRV_SLAVE).driveControl02 + status: ec0.s$(DRV_SLAVE).driveStatus02 + setpoint: ec0.s$(DRV_SLAVE).velocitySetpoint02 + # control bit for reset in 'control' + reset: 7 + # status bit for warning in 'status' + warning: 7 + # list of error bits in 'status', or if type==string, complete EC-link + error: + - 3 # Error + - 7 # Warning as Error + +encoder: + numerator: 360 + denominator: 1048576 + type: 1 # Type: 0=Incremental, 1=Absolute + bits: 32 # Total bit count of encoder raw data + absBits: 25 # Absolute bit count (for absolute encoders) always least significant part of 'bits' + absOffset: 0 # Encoder offset in eng units (for absolute encoders) + position: ec0.s$(DRV_SLAVE).positionActual02 # Ethercat entry for actual position input (encoder) + +controller: + Kp: 15 + Ki: 0.05 + +trajectory: + type: 1 + axis: + velocity: 18000 # 5000 rpm (web page), 7883 rpm (name plate) => 47298 deg/s + acceleration: 90000 + jerk: 360000 + +input: + limit: + forward: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for low limit switch input + backward: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for high limit switch input + home: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for home switch input + interlock: ec0.s$(DRV_SLAVE).ONE.0 # Ethercat entry for interlock switch input + +monitoring: + lag: + enable: true + tolerance: 360 + time: 100 + target: + enable: yes + tolerance: 0.1 + time: 100 + velocity: + enable: true + max: 28000 + time: + trajectory: 100 + drive: 200 diff --git a/examples/test/elm7222/startup_ch1.iocsh b/examples/test/elm7222/startup_ch1.iocsh new file mode 100644 index 000000000..bbaf2f303 --- /dev/null +++ b/examples/test/elm7222/startup_ch1.iocsh @@ -0,0 +1,22 @@ +require ecmccfg,ELM7222 "ENG_MODE=1,ECMC_VER=9.2.0" + +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}addSlave.cmd, "HW_DESC=ELM7222-0010, SLAVE_ID=21" +${SCRIPTEXEC} ${ecmccfg_DIR}applySlaveConfig.cmd, "CONFIG=-Motor-ch1-Beckhoff-AM8112-xFx1" + +epicsEnvSet("DRV_SLAVE", ${ECMC_EC_SLAVE_NUM}) +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}loadYamlAxis.cmd, "FILE=cfg/AM8112_ch1.yaml, DEV=${DEV=${IOC}}, DRV_SLAVE=${DRV_SLAVE}" + +#- ############################################################################# +#- apply configuration +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}applyConfig.cmd +#- ############################################################################# +#- go active +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}setAppMode.cmd + +#- be quiet +asynSetTraceMask(MC_CPU1, -1, 0x01) +asynSetTraceIOMask(MC_CPU1, -1, 6) +asynSetTraceInfoMask(MC_CPU1, -1, 1) + +#- reset all errors +ecmcConfigOrDie "ControllerErrorReset()" diff --git a/examples/test/elm7222/startup_ch2.iocsh b/examples/test/elm7222/startup_ch2.iocsh new file mode 100644 index 000000000..539186877 --- /dev/null +++ b/examples/test/elm7222/startup_ch2.iocsh @@ -0,0 +1,22 @@ +require ecmccfg,ELM7222 "ENG_MODE=1,ECMC_VER=9.2.0" + +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}addSlave.cmd, "HW_DESC=ELM7222-0010, SLAVE_ID=21" +${SCRIPTEXEC} ${ecmccfg_DIR}applySlaveConfig.cmd, "CONFIG=-Motor-ch2-Beckhoff-AM8112-xFx1" + +epicsEnvSet("DRV_SLAVE", ${ECMC_EC_SLAVE_NUM}) +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}loadYamlAxis.cmd, "FILE=cfg/AM8112_ch2.yaml, DEV=${DEV=${IOC}}, DRV_SLAVE=${DRV_SLAVE}" + +#- ############################################################################# +#- apply configuration +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}applyConfig.cmd +#- ############################################################################# +#- go active +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}setAppMode.cmd + +#- be quiet +asynSetTraceMask(MC_CPU1, -1, 0x01) +asynSetTraceIOMask(MC_CPU1, -1, 6) +asynSetTraceInfoMask(MC_CPU1, -1, 1) + +#- reset all errors +ecmcConfigOrDie "ControllerErrorReset()" diff --git a/examples/test/elm7321/startup.iocsh b/examples/test/elm7321/startup.iocsh index 5f18c483f..264dd7bb7 100644 --- a/examples/test/elm7321/startup.iocsh +++ b/examples/test/elm7321/startup.iocsh @@ -3,7 +3,7 @@ require ecmccfg,ELM7231 "ENG_MODE=1,ECMC_VER=9.2.0" ${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}configureSlave.cmd, "HW_DESC=ELM7231-0010, SLAVE_ID=20, CONFIG=-Motor-Beckhoff-AM8123-1NH1-0000" epicsEnvSet("DRV_SLAVE", ${ECMC_EC_SLAVE_NUM}) -${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}loadYamlAxis.cmd, "FILE=cfg/AM813.yaml, DEV=${DEV=${IOC}}, DRV_SLAVE=${DRV_SLAVE}" +${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}loadYamlAxis.cmd, "FILE=cfg/AM8123.yaml, DEV=${DEV=${IOC}}, DRV_SLAVE=${DRV_SLAVE}" #- ############################################################################# #- apply configuration diff --git a/hardware/Beckhoff_7XXX/ELM/ecmcELM7222-0010.cmd b/hardware/Beckhoff_7XXX/ELM/ecmcELM7222-0010.cmd new file mode 100644 index 000000000..247e8e916 --- /dev/null +++ b/hardware/Beckhoff_7XXX/ELM/ecmcELM7222-0010.cmd @@ -0,0 +1,78 @@ +#-d /** +#-d \brief hardware script for ELM7222-0010 +#-d \details ELM7222-0010 Servo terminal with OCT feedback +#-d \author Niko Kivel +#-d \file +#-d \note SDOS +#-d \param [out] SDO 0x1011:01 --> 1684107116 \b reset +#-d */ + +#- ########################################################### +#- ############ Information: +#- Description: ELM7222-0010 Servo terminal with OCT feedback +#- +#- Note: The sync mode can not be written to in newer firmwares: +#- (0x1C32,0x1,0x1C33,0x1). So then these lines below needs +#- to be removed or commented out. +#- The log will then show error like: +#- EtherCAT ERROR 0-46: SDO download 0x1C32:01 (2 bytes) aborted. +#- EtherCAT ERROR 0-46: SDO abort message 0x06090030: "Value range of parameter exceeded". +#- EtherCAT ERROR 0-46: SDO configuration failed. +#- +#- ########################################################### + +epicsEnvSet("ECMC_EC_HWTYPE" "ELM7222-0010") +epicsEnvSet("ECMC_EC_VENDOR_ID" "0x2") +epicsEnvSet("ECMC_EC_PRODUCT_ID" "0x50227569") +epicsEnvSet("ECMC_EC_COMP_TYPE" "EL7222_OCT") + +#- verify slave, including reset +${SCRIPTEXEC} ${ecmccfg_DIR}slaveVerify.cmd "RESET=true" + +#- ========================== Channel 1 ========================== +#- Activly choose CSV +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x7010,0x3,9,1)" + +#- ############ read electronic nameplate +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x8008,0x1,1,1)" +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x8008,0x2,1,1)" +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x8008,0x3,1,1)" + +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},1,2,0x1610,0x7010,0x01,U16,driveControl01)" +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},1,2,0x1612,0x7010,0x06,S32,velocitySetpoint01)" + +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},2,3,0x1a00,0x6000,0x11,U32,positionActual01)" +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},2,3,0x1a10,0x6010,0x01,U16,driveStatus01)" + +#- ========================== Channel 2 ========================== +#- Activly choose CSV +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x7110,0x3,9,1)" + +#- ############ read electronic nameplate +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x8108,0x1,1,1)" +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x8108,0x2,1,1)" +ecmcConfigOrDie "Cfg.EcWriteSdo(${ECMC_EC_SLAVE_NUM},0x8108,0x3,1,1)" + +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},1,2,0x1650,0x7110,0x01,U16,driveControl02)" +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},1,2,0x1652,0x7110,0x06,S32,velocitySetpoint02)" + +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},2,3,0x1a40,0x6100,0x11,U32,positionActual02)" +ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},${ECMC_EC_VENDOR_ID},${ECMC_EC_PRODUCT_ID},2,3,0x1a50,0x6110,0x01,U16,driveStatus02)" + +#- ############ Distributed clocks config: +#- Configure DC clock +#- From TwinCAT: SYNC 0: User defined 62.5 us, SYNC 1: 4000 us <-- I set this to the cycle time below +ecmcEpicsEnvSetCalc("ECMC_TEMP_PERIOD_NANO_SECS",1000/${ECMC_EC_SAMPLE_RATE=1000}*1E6) +ecmcConfigOrDie "Cfg.EcSlaveConfigDC(${ECMC_EC_SLAVE_NUM},0x700,62500,${ECMC_SYNC_0_OFFSET_NS=0},${ECMC_TEMP_PERIOD_NANO_SECS},${ECMC_SYNC_1_OFFSET_NS=0})" +epicsEnvUnset("ECMC_TEMP_PERIOD_NANO_SECS") + +#- watchdog +${SCRIPTEXEC} ${ecmccfg_DIR}ecmcWatchDog.cmd + +#- Set 4000 ms delay of ethercat bus at startup: +#- Somtimes the Ex72xx-xxxx will not report a correct encoder signal when transition from PREOP to OP. This is not reflected in any status word or bit +#- This will result in problems sicne ecmc cannot know if teh value is correct or not after startup. +#- For the drives with problems measurements have been made which concludes that after 2600ms after entering OP the EL72xx will give correct encoder position. +#- For twincat probably this is not an isue since the terminals are not goung from PROP to OP so often. +#- Conclusion: Need to contact Beckhoff. Probably firmware bug. +ecmcConfigOrDie "Cfg.EcSetDelayECOkAtStartup(${ECMC_EC_STARTUP_DELAY=4000})" diff --git a/hardware/Motors/ecmcELM7222-0010-Motor-ch1-Beckhoff-AM8112-xFx1.cmd b/hardware/Motors/ecmcELM7222-0010-Motor-ch1-Beckhoff-AM8112-xFx1.cmd new file mode 100644 index 000000000..cd1394d76 --- /dev/null +++ b/hardware/Motors/ecmcELM7222-0010-Motor-ch1-Beckhoff-AM8112-xFx1.cmd @@ -0,0 +1,52 @@ +############################################################ +############# Parmetrization of ELM7222-XXXX for motor AM8112-xFx1 on channel 1 +#- Motor WITH brake +#- +#- Note: For important parameters see TwinCAT CoE startup list for the +#- motor terminal configuration. +#- +#- Macros (optional): +#-d \param I_MAX_MA : Maximum current in mA (defaults to 16500 mA) +#-d \param I_RUN_MA : Running current in mA (defaults to 4500 mA) +#-d */ + +#- Current loop integral time +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8010,0x12,6,2)" +#- Current loop proportianal gain +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8010,0x13,133,2)" + +#- Velocity loop integral time +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8010,0x14,150,4)" +#- Velocity loop proportianal gain +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8010,0x15,82,4)" + +#- standstill window +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8010,0x33,10,2)" + + +#- Motor max current +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x11,${I_MAX_MA=16500},4)" +#- Motor rated current +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x12,${I_RUN_MA=4500},4)" +#- Motor pole pairs +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x13,3,1)" +#- Commutation offset +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x15,270,2)" +#- Torque contstant +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x16,81,4)" +#- Rotor moment of inertia +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x18,75,4)" +#- Winding inductance +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x19,8,2)" +#- Motor speed limitation +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x1b,10000,4)" + +#- Motor Temperature warn level +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x2b,1200,2)" +#- Motor thermal time constant +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8011,0x2d,419,2)" + +#- Release delay +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8012,0x11,20,2)" +#- Application delay +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8012,0x12,8,2)" diff --git a/hardware/Motors/ecmcELM7222-0010-Motor-ch2-Beckhoff-AM8112-xFx1.cmd b/hardware/Motors/ecmcELM7222-0010-Motor-ch2-Beckhoff-AM8112-xFx1.cmd new file mode 100644 index 000000000..367fbe3cf --- /dev/null +++ b/hardware/Motors/ecmcELM7222-0010-Motor-ch2-Beckhoff-AM8112-xFx1.cmd @@ -0,0 +1,52 @@ +############################################################ +############# Parmetrization of ELM7222-XXXX for motor AM8112-xFx1 on channel 2 +#- Motor WITH brake +#- +#- Note: For important parameters see TwinCAT CoE startup list for the +#- motor terminal configuration. +#- +#- Macros (optional): +#-d \param I_MAX_MA : Maximum current in mA (defaults to 16500 mA) +#-d \param I_RUN_MA : Running current in mA (defaults to 4500 mA) +#-d */ + +#- Current loop integral time +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8110,0x12,6,2)" +#- Current loop proportianal gain +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8110,0x13,133,2)" + +#- Velocity loop integral time +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8110,0x14,150,4)" +#- Velocity loop proportianal gain +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8110,0x15,82,4)" + +#- standstill window +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8110,0x33,10,2)" + + +#- Motor max current +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x11,${I_MAX_MA=16500},4)" +#- Motor rated current +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x12,${I_RUN_MA=4500},4)" +#- Motor pole pairs +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x13,3,1)" +#- Commutation offset +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x15,270,2)" +#- Torque contstant +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x16,81,4)" +#- Rotor moment of inertia +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x18,75,4)" +#- Winding inductance +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x19,8,2)" +#- Motor speed limitation +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x1b,10000,4)" + +#- Motor Temperature warn level +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x2b,1200,2)" +#- Motor thermal time constant +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8111,0x2d,419,2)" + +#- Release delay +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8112,0x11,20,2)" +#- Application delay +ecmcConfigOrDie "Cfg.EcAddSdo(${ECMC_EC_SLAVE_NUM},0x8112,0x12,8,2)"