EtherCAT IO & homing

Reading an ICPDAS ECAT-2055 for a single axis — why the ORG / OT inputs must be registered and bound, or the motor won’t move. Worked example on a SuperCAT master (Yaskawa servo + ECAT-2055 as slaves), with the actual APS168 call sequence.

Setting up the bus first? See Bus setup: scan, ESI & device recognition — it explains how the slaves get recognized and where the 0001.csv used below comes from.

1 · What is EtherCAT

EtherCAT is a master/slave industrial fieldbus. One master runs on a real-time OS and, every bus cycle, passes a single frame through all slaves — writing outputs and reading inputs on the fly. Cycle times run from about 1 ms down to the microsecond range, which is what makes it deterministic enough for motion control.

In this guide the master is SuperCAT and the slaves are a Yaskawa servo (the axis) plus an ICPDAS ECAT-2055 (8 DI / 8 DO) that carries the limit and home switches.

2 · One dictionary, two ways to access it

Every slave exposes an Object Dictionary (OD) — a table where each value has an index (e.g. 0x6000 = the 8 DI, 0x6200 = the 8 DO). There are two ways to reach those objects, and the difference matters:

Object Dictionary 0x6000 8x DI ro 0x6200 8x DO rw PDO · cyclic (fast) every bus cycle, real-time IO deterministic period ~ 1 cycle SDO · acyclic (slow) on demand, via Mailbox ~ 324 cycles / transfer no mailbox -> -4101

The ECAT-2055 has no Mailbox, so an SDO read of its DI simply fails with -4101. Its IO only lives in the cyclic PDO process image — remember that, it drives everything below.

3 · The SuperCAT master — hardware or pure software

SuperCAT is ADLINK’s EtherCAT master software. You can run it two ways, and the application code (APS168) is identical either way:

software · EtherCAT master SuperCAT hardware PCIe-8338 or pure software dongle PDO / SDO slave ECAT-2055 8x DI / 8x DO read DI (verified) APS_get_field_bus_d_port_input(board,0,MOD1,…) write DO APS_set_field_bus_d_port_output(…) – same pattern, not used in this project

4 · Registering & binding the IO (the part that bites)

Symptom you’ll hit first: the motor refuses to move and the UI shows both +OT and −OT tripped at once. The limits are fine — the axis simply isn’t reading the DI yet. Because the OT switches are B-contact (NC), an unread input reads as 0, and inverted logic turns 0 into “tripped” on both ends.

Reading a DI value is not the same as letting the motion engine use it for homing and limits. For that, the engine must see the ECAT-2055 as a registered DIO module. You register it by declaring it in a config file — no bus scan, no special authority needed.

Step ★ — register the module

APS_load_config_from_file(board, "E:\...\MCPRO2\0001.csv", 0)

The whole config is two lines — “slave 1 has an 8-bit DI and an 8-bit DO”:

SlaveID, Type, Port/Ch, SubMod, ODIndex, AccessLength, ...
1,       1,    0,       0,      0,       8,   ...   # slave1 8-bit DI
1,       2,    0,       0,      0,       8,   ...   # slave1 8-bit DO

(Type 1 = DI, Type 2 = DO — mapping observed from the working MiniJog project; one row is read as input, the other written as output. LowerBound/UpperBound/DataType = -1 are unused for digital IO.)

Step ★★ — bind the signals to the axis

Now tell the axis which DI bit is ORG / PEL / MEL, set the contact polarity, and enable the mapping:

APS_set_axis_param(ax, PRA_MOTION_SGN_ORG_MAP, (1<<8)|0)   # ORG <- DI0
APS_set_axis_param(ax, PRA_MOTION_SGN_MEL_MAP, (1<<8)|1)   # MEL <- DI1
APS_set_axis_param(ax, PRA_MOTION_SGN_PEL_MAP, (1<<8)|2)   # PEL <- DI2
APS_set_axis_param(ax, PRA_EL_LOGIC,           1)          # B-contact (NC), inverted
APS_set_axis_param(ax, PRA_MOTION_SGN_MAP_EN,  0xE)        # enable ORG/MEL/PEL

With the module registered and the signals bound, APS_home_move() finds ORG, the OT watchdog protects both ends, and the by-module read APS_get_field_bus_d_port_input() works.

The actual call sequence, in program order

1 · startup open the card APS_initial() get axis id APS_get_first_axisId() start the EtherCAT bus APS_start_field_bus() ★ register ECAT-2055 as DIO module (MOD1) APS_load_config_from_file(…\MCPRO2\0001.csv) 2 · bind select IO access source APS_set_board_param(PRB_IO_ACCESS_SEL, 3) map limits / home to DI bits · PEL←DI2, MEL←DI1, ORG←DI0 APS_set_axis_param(PRA_MOTION_SGN_PEL/MEL/ORG_MAP, (1<<8)|bit) set contact polarity · B-contact inversion APS_set_axis_param(PRA_EL_LOGIC, 1) APS_set_axis_param(PRA_ORG_LOGIC, 0) enable the mapping (bit1~3 = MEL/PEL/ORG) APS_set_axis_param(PRA_MOTION_SGN_MAP_EN, 0xE) 3 · home servo on APS_set_servo_on(ax, 1) set home params (mode 0 = ORG, dir, EZ align, shift…) APS_set_axis_param(PRA_HOME_MODE / DIR / EZA / ACC / VM / VO / SHIFT) run homing → engine catches ORG (needs ★ + enable) APS_home_move(ax) 4 · runtime read DI for display, 100 ms (by-module, works after ★) APS_get_field_bus_d_port_input(board,0,MOD1,…) Skip the register step (no 0001.csv) → engine reads DI as 0 → B-contact inversion makes both +OT/−OT look tripped → motor won’t move, and home can never catch ORG. The root cause is the missing registration, not the limits.

Side path. APS_get_address_mapping_in_byte() reads the raw process-image byte directly, without any registration. It’s handy for a quick manual read of the DI, but the engine still won’t home on it until you register and bind. This was the early workaround before the config-file route.

Contact types

  • OT (over-travel) = B-contact (NC) — fail-safe: idle conducts and reads 1; a trip or a broken wire reads 0. Set PRA_EL_LOGIC = 1 so 0 means “tripped”.
  • ORG (home dog) = A-contact (NO) — idle reads 0; hitting the dog reads 1.

5 · References