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.
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.
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:
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.
SuperCAT is ADLINK’s EtherCAT master software. You can run it two ways, and the application code (APS168) is identical either way:
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.
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.)
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.
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.
PRA_EL_LOGIC = 1 so 0 means “tripped”.0001.csv comes from.