Discussion:
[etherlab-users] EL7041-1000 - AL status message 0x001E: "Invalid input configuration".
Jakob Flierl
2015-05-08 19:15:24 UTC
Permalink
Hi,

I'm trying to write a driver for EL7041-1000 for LinuxCNC, I'm getting in dmesg:

[19022.235581] EtherCAT ERROR 0-3: Failed to set SAFEOP state, slave
refused state change (PREOP + ERROR).
[19022.239594] EtherCAT ERROR 0-3: AL status message 0x001E: "Invalid
input configuration".

The PDO mapping source code of the driver is here:

https://github.com/koppi/linuxcnc-ethercat/blob/add-el7041-1000/src/lcec_el7041_1000.c#L146-L228

Can't find the root cause and the drive refuses to go into OP:

$ ethercat slaves
0 0:0 OP + EK1100 EtherCAT-Koppler (2A E-Bus)
1 0:1 OP + EL2004 4K. Dig. Ausgang 24V, 0.5A
2 0:2 OP + EL1004 4K. Dig. Eingang 24V, 3ms
3 0:3 PREOP E EL7041-1000 1K. Schrittmotor-Endstufe (50V, 5A, standard)

For reference:

$ ethercat -p3 cstruct
/* Master 0, Slave 3, "EL7041-1000"
* Vendor ID: 0x00000002
* Product code: 0x1b813052
* Revision number: 0x001403e8
*/

ec_pdo_entry_info_t slave_3_pdo_entries[] = {
{0x0000, 0x00, 1},
{0x7000, 0x02, 1},
{0x7000, 0x03, 1},
{0x7000, 0x04, 1},
{0x0000, 0x00, 4},
{0x0000, 0x00, 8},
{0x7000, 0x11, 16},
{0x7020, 0x01, 1},
{0x7020, 0x02, 1},
{0x7020, 0x03, 1},
{0x0000, 0x00, 5},
{0x0000, 0x00, 8},
{0x7020, 0x21, 16},
{0x0000, 0x00, 1},
{0x6000, 0x02, 1},
{0x6000, 0x03, 1},
{0x6000, 0x04, 1},
{0x6000, 0x05, 1},
{0x0000, 0x00, 2},
{0x6000, 0x08, 1},
{0x6000, 0x09, 1},
{0x6000, 0x0a, 1},
{0x0000, 0x00, 1},
{0x0000, 0x00, 1},
{0x6000, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1},
{0x1800, 0x09, 1},
{0x6000, 0x11, 16},
{0x6000, 0x12, 16},
{0x6020, 0x01, 1},
{0x6020, 0x02, 1},
{0x6020, 0x03, 1},
{0x6020, 0x04, 1},
{0x6020, 0x05, 1},
{0x6020, 0x06, 1},
{0x6020, 0x07, 1},
{0x0000, 0x00, 1},
{0x0000, 0x00, 3},
{0x6020, 0x0c, 1},
{0x6020, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1},
{0x1806, 0x09, 1},
{0x6020, 0x11, 16},
{0x6020, 0x12, 16},
};

ec_pdo_info_t slave_3_pdos[] = {
{0x1600, 7, slave_3_pdo_entries + 0}, /* ENC RxPDO-Map Control compact */
{0x1604, 5, slave_3_pdo_entries + 7}, /* STM RxPDO-Map Velocity */
{0x1606, 1, slave_3_pdo_entries + 12},
{0x1a00, 17, slave_3_pdo_entries + 13}, /* ENC TxPDO-Map Status compact */
{0x1a06, 14, slave_3_pdo_entries + 30},
{0x1a07, 2, slave_3_pdo_entries + 44},
};

ec_sync_info_t slave_3_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 3, slave_3_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 3, slave_3_pdos + 3, EC_WD_DISABLE},
{0xff}
};
Thomas Bitsky Jr
2015-05-08 20:26:46 UTC
Permalink
I find I have to fire up TwinCAT System Manager on a Windows VM and go through how it would configure the card for the more complicated slaves. If you check the right boxes, it will list the entire raw process you need for initializing the card properly.

Based on that, here’s what I do for the EL7041 and EP7041 (they configure the same). I’ve used it with dozens of them; it’s my go-to stepper card. Word of caution: put an EL9100 in front of the card, or position will be reset every time someone presses E-Stop, then control power is restored. There is no software solution to this. What I have my company do is put the EL9100 then EL7041 at the end of the rack. We leave the EL9100 powered at all times, then E-Stop breaks the motor power.


// vendor id, product id
#define BECKHOFF_EL7041 0x00000002, 0x1b813052
#define BECKHOFF_EP7041 0x00000002, 0x1b814052

#define EL70X1_STEPPERTYPE BECKHOFF_EP7041

#define EL70X1_STEPSPERREV 200


/////////////////////////////////////////////////////////////////////
// Private Variables
/////////////////////////////////////////////////////////////////////

static ec_pdo_entry_info_t el7041_pdo_entries_[] = {

///////////////////////
// Output PDOS
// PDO 0x1601
{0x7000, 0x01, 1}, /* Enable latch C */
{0x7000, 0x02, 1}, /* Enable latch extern on positive edge */
{0x7000, 0x03, 1}, /* Set counter */
{0x7000, 0x04, 1}, /* Enable latch extern on negative edge */
{0x0000, 0x00, 4}, /* Gap */
{0x0000, 0x00, 8}, /* Gap */
{0x7000, 0x11, 32}, /* Set counter value */
// PDO 0x1602
{0x7010, 0x01, 1}, /* Enable */
{0x7010, 0x02, 1}, /* Reset */
{0x7010, 0x03, 1}, /* Reduce torque */
{0x0000, 0x00, 5}, /* Gap */
{0x0000, 0x00, 8}, /* Gap */
// PDO 0x1606
{0x7020, 0x01, 1}, // Control_Execute
{0x7020, 0x02, 1}, // Emergency Stop
{0x0000, 0x00, 6}, // Gap
{0x0000, 0x00, 8}, // Gap
{0x7020, 0x11, 32}, // Target Position
{0x7020, 0x21, 16}, // Velocity
{0x7020, 0x22, 16}, // Start type
{0x7020, 0x23, 16}, // Acceleration
{0x7020, 0x24, 16}, // Deceleration
//////////////////////////
// Input PDOs
// PDO 0x1A01
{0x6000, 0x01, 1}, /* Latch C valid */
{0x6000, 0x02, 1}, /* Latch extern valid */
{0x6000, 0x03, 1}, /* Set counter done */
{0x6000, 0x04, 1}, /* Counter underflow */
{0x6000, 0x05, 1}, /* Counter overflow */
{0x0000, 0x00, 2}, /* Gap */
{0x6000, 0x08, 1}, /* Extrapolation stall */
{0x6000, 0x09, 1}, /* Status of input A */
{0x6000, 0x0a, 1}, /* Status of input B */
{0x6000, 0x0b, 1}, /* Status of input C */
{0x0000, 0x00, 1}, /* Gap */
{0x6000, 0x0d, 1}, /* Status of extern latch */
{0x1c32, 0x20, 1}, /* Sync error */
{0x0000, 0x00, 1}, /* Gap */
{0x1801, 0x09, 1}, // Status TxPDO Toggle
{0x6000, 0x11, 32}, /* Internal Counter value */
{0x6000, 0x12, 32}, /* Latch value */
// PDO 0x1A03
{0x6010, 0x01, 1}, /* Ready to enable */
{0x6010, 0x02, 1}, /* Ready */
{0x6010, 0x03, 1}, /* Warning */
{0x6010, 0x04, 1}, /* Error */
{0x6010, 0x05, 1}, /* Moving positive */
{0x6010, 0x06, 1}, /* Moving negative */
{0x6010, 0x07, 1}, /* Torque reduced */
{0x0000, 0x00, 1}, /* Gap */
{0x0000, 0x00, 3}, /* Gap */
{0x6010, 0x0c, 1}, /* Digital input 1 */
{0x6010, 0x0d, 1}, /* Digital input 2 */
{0x1c32, 0x20, 1}, /* Sync error */
{0x0000, 0x00, 1}, /* Gap */
{0x1803, 0x09, 1}, // Status TxPDO Toggle
// PDO 0x1A06
{0x6020, 0x01, 1}, // Status Busy
{0x6020, 0x02, 1}, // Status In Target
{0x6020, 0x03, 1}, // Status Warning
{0x6020, 0x04, 1}, // Status Error
{0x6020, 0x05, 1}, // Status Calibrated
{0x6020, 0x06, 1}, // Status Accelerate
{0x6020, 0x07, 1}, // Status Decelerate
{0x0000, 0x00, 1}, // GAP
{0x0000, 0x00, 8}, // GAP
{0x6020, 0x11, 32}, // Actual Position
{0x6020, 0x21, 16}, // Actual Velocity
{0x6020, 0x22, 32}, // Actual drive time
};

static ec_pdo_info_t el7041_pdos_[] = {
{0x1601, 7, el7041_pdo_entries_ + 0}, /* ENC RxPDO-Map Control compact */
{0x1602, 5, el7041_pdo_entries_ + 7}, /* STM RxPDO-Map Control */
{0x1606, 9, el7041_pdo_entries_ + 12}, /* STM RxPDO-Map Velocity */
{0x1a01, 17, el7041_pdo_entries_ + 21}, /* ENC TxPDO-Map Status compact */
{0x1a03, 14, el7041_pdo_entries_ + 38}, /* STM TxPDO-Map Status */
{0x1a06, 12, el7041_pdo_entries_ + 52}, /* STM TxPDO-Map Status */
};

static ec_sync_info_t el7041_syncs_[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 3, el7041_pdos_ + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 3, el7041_pdos_ + 3, EC_WD_DISABLE},
{0xff}
};


//
// Configure the slave into the EtherCAT network
//
BOOL
el70X1_ecConfigure(
EL70X1StepperInterface* el,
ec_master_t* master,
unsigned int slavePosDomain,
unsigned int slavePosIndex)
{
ec_slave_config_t* sc;

PRINTF( CTSMSG_INFO "Begin el70X1_ecConfigure...\n") ;
//
// Create the slave configuration
//
if ( !(sc = ecrt_master_slave_config(
master,
slavePosDomain, slavePosIndex, // Bus position
EL70X1_STEPPERTYPE // Slave type
)) )
{
PRINTF(CTSMSG_INFO
"el70X1_ecConfigure -- Failed to get slave configuration.\n");
return FALSE;
}
//
// Map the PDOs
//
//
// Pre-configured PDO mappings
// Use the complete position mapping
//
ecrt_slave_config_sdo8( sc, 0x1C12, 0, 0 ); /* clear sm pdo 0x1c12 */
ecrt_slave_config_sdo16( sc, 0x1C12, 1, 0x1601 ); /* download pdo 1C12 index */
ecrt_slave_config_sdo16( sc, 0x1C12, 2, 0x1602 ); /* download pdo 1C12 index */
ecrt_slave_config_sdo16( sc, 0x1C12, 3, 0x1606 ); /* download pdo 1C12 index */
ecrt_slave_config_sdo8( sc, 0x1C12, 0, 3 ); /* set number of RxPDO */

ecrt_slave_config_sdo8( sc, 0x1C13, 0, 0 ); /* clear sm pdo 0x1c12 */
ecrt_slave_config_sdo16( sc, 0x1C13, 1, 0x1A01 ); /* download pdo 1C13 index */
ecrt_slave_config_sdo16( sc, 0x1C13, 2, 0x1A03 ); /* download pdo 1C13 index */
ecrt_slave_config_sdo16( sc, 0x1C13, 3, 0x1A06 ); /* download pdo 1C13 index */
ecrt_slave_config_sdo8( sc, 0x1C13, 0, 3 ); /* set number of TxPDO */

//
// Register startup configuration for the hardware
//
// Set the maximum current for the drive
// Unit: 1 mA
ecrt_slave_config_sdo16( sc, 0x8010, 0x01, 4630 );

// Set the holding current
// Unit: 1 mA
ecrt_slave_config_sdo16( sc, 0x8010, 0x02, 500 );

// Set the nominal voltage
// Unit: 1 mv / 1000
ecrt_slave_config_sdo16( sc, 0x8010, 0x03, 48000 );
// Set motor coil resistance
// Unit: 0.01 ohm
ecrt_slave_config_sdo16( sc, 0x8010, 0x04, 104 );
// Set Motor full steps per revolution
// unit: steps
ecrt_slave_config_sdo16( sc, 0x8010, 0x06, EL70X1_STEPSPERREV );


// Set Kp Factor
// Unit: 0.001
ecrt_slave_config_sdo16( sc, 0x8011, 0x01, 200);

// Set filter limit frequencey of the current controller (low-pass)
// Unit: 1hz
ecrt_slave_config_sdo16( sc, 0x8011, 0x06, 0);
//
// Configure the hardware's PDOs
//
if (ecrt_slave_config_pdos(sc, EC_END, el7041_syncs_))
{
PRINTF(CTSMSG_INFO
"el70X1_ecConfigure -- Failed to configure PDOs.\n");
return FALSE;
}
//
// Set the initial state
//
el->fsm = &stateReset;
PRINTF(CTSMSG_INFO "el70X1_ecConfigure was SUCCESSFUL...\n");
return TRUE;
}

Also, somewhere in your PDO registry list, you’ll need:

//
// Stepper Drive Y EP7041-0002
//
{0,7, EL70X1_STEPPERTYPE, 0x7000, 0x03, &pgbl_stepperY.off_controlSetCounter, &pgbl_stepperY.off_controlSetCounter_bit},
{0,7, EL70X1_STEPPERTYPE, 0x7000, 0x11, &pgbl_stepperY.off_setCounterValue, 0},
{0,7, EL70X1_STEPPERTYPE, 0x7010, 0x01, &pgbl_stepperY.off_controlEnable, &pgbl_stepperY.off_controlEnable_bit},
{0,7, EL70X1_STEPPERTYPE, 0x7010, 0x02, &pgbl_stepperY.off_controlReset, &pgbl_stepperY.off_controlReset_bit},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x01, &pgbl_stepperY.off_controlExecute, &pgbl_stepperY.off_controlExecute_bit},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x02, &pgbl_stepperY.off_controlEmergencyStop, &pgbl_stepperY.off_controlEmergencyStop_bit},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x11, &pgbl_stepperY.off_targetPosition, 0},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x21, &pgbl_stepperY.off_velocity, 0},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x22, &pgbl_stepperY.off_startType, 0},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x22, &pgbl_stepperY.off_acceleration, 0},
{0,7, EL70X1_STEPPERTYPE, 0x7020, 0x22, &pgbl_stepperY.off_deceleration, 0},
{0,7, EL70X1_STEPPERTYPE, 0x6000, 0x03, &pgbl_stepperY.off_statusSetCounterDone, &pgbl_stepperY.off_statusSetCounterDone_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6000, 0x11, &pgbl_stepperY.off_internalCounterValue, 0},
{0,7, EL70X1_STEPPERTYPE, 0x6010, 0x01, &pgbl_stepperY.off_readyToEnable, &pgbl_stepperY.off_readyToEnable_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6010, 0x02, &pgbl_stepperY.off_ready, &pgbl_stepperY.off_ready_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6010, 0x0c, &pgbl_stepperY.off_input1, &pgbl_stepperY.off_input1_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6010, 0x0d, &pgbl_stepperY.off_input2, &pgbl_stepperY.off_input2_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6010, 0x05, &pgbl_stepperY.off_movingPositive, &pgbl_stepperY.off_movingPositive_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6010, 0x06, &pgbl_stepperY.off_movingNegative, &pgbl_stepperY.off_movingNegative_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6020, 0x01, &pgbl_stepperY.off_busy, &pgbl_stepperY.off_busy_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6020, 0x02, &pgbl_stepperY.off_inTarget, &pgbl_stepperY.off_inTarget_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6020, 0x03, &pgbl_stepperY.off_warning, &pgbl_stepperY.off_warning_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6020, 0x04, &pgbl_stepperY.off_error, &pgbl_stepperY.off_error_bit},
{0,7, EL70X1_STEPPERTYPE, 0x6020, 0x11, &pgbl_stepperY.off_actualPosition, 0},
{0,7, EL70X1_STEPPERTYPE, 0x6020, 0x21, &pgbl_stepperY.off_actualVelocity, 0},


Obviously, you’ll have different position numbers and you’ll be storing your byte and bit offsets in different variables, but the above setup should get you going.

Thanks!
Thomas C. Bitsky Jr. | Lead Developer
ADC | automateddesign.com<http://automateddesign.com/>
P: 630-783-1150 F: 630-783-1159 M: 630-632-6679

On May 8, 2015, at 2:15 PM, Jakob Flierl <***@gmail.com<mailto:***@gmail.com>> wrote:

Hi,

I'm trying to write a driver for EL7041-1000 for LinuxCNC, I'm getting in dmesg:

[19022.235581] EtherCAT ERROR 0-3: Failed to set SAFEOP state, slave
refused state change (PREOP + ERROR).
[19022.239594] EtherCAT ERROR 0-3: AL status message 0x001E: "Invalid
input configuration".

The PDO mapping source code of the driver is here:

https://github.com/koppi/linuxcnc-ethercat/blob/add-el7041-1000/src/lcec_el7041_1000.c#L146-L228

Can't find the root cause and the drive refuses to go into OP:

$ ethercat slaves
0 0:0 OP + EK1100 EtherCAT-Koppler (2A E-Bus)
1 0:1 OP + EL2004 4K. Dig. Ausgang 24V, 0.5A
2 0:2 OP + EL1004 4K. Dig. Eingang 24V, 3ms
3 0:3 PREOP E EL7041-1000 1K. Schrittmotor-Endstufe (50V, 5A, standard)

For reference:

$ ethercat -p3 cstruct
/* Master 0, Slave 3, "EL7041-1000"
* Vendor ID: 0x00000002
* Product code: 0x1b813052
* Revision number: 0x001403e8
*/

ec_pdo_entry_info_t slave_3_pdo_entries[] = {
{0x0000, 0x00, 1},
{0x7000, 0x02, 1},
{0x7000, 0x03, 1},
{0x7000, 0x04, 1},
{0x0000, 0x00, 4},
{0x0000, 0x00, 8},
{0x7000, 0x11, 16},
{0x7020, 0x01, 1},
{0x7020, 0x02, 1},
{0x7020, 0x03, 1},
{0x0000, 0x00, 5},
{0x0000, 0x00, 8},
{0x7020, 0x21, 16},
{0x0000, 0x00, 1},
{0x6000, 0x02, 1},
{0x6000, 0x03, 1},
{0x6000, 0x04, 1},
{0x6000, 0x05, 1},
{0x0000, 0x00, 2},
{0x6000, 0x08, 1},
{0x6000, 0x09, 1},
{0x6000, 0x0a, 1},
{0x0000, 0x00, 1},
{0x0000, 0x00, 1},
{0x6000, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1},
{0x1800, 0x09, 1},
{0x6000, 0x11, 16},
{0x6000, 0x12, 16},
{0x6020, 0x01, 1},
{0x6020, 0x02, 1},
{0x6020, 0x03, 1},
{0x6020, 0x04, 1},
{0x6020, 0x05, 1},
{0x6020, 0x06, 1},
{0x6020, 0x07, 1},
{0x0000, 0x00, 1},
{0x0000, 0x00, 3},
{0x6020, 0x0c, 1},
{0x6020, 0x0d, 1},
{0x1c32, 0x20, 1},
{0x0000, 0x00, 1},
{0x1806, 0x09, 1},
{0x6020, 0x11, 16},
{0x6020, 0x12, 16},
};

ec_pdo_info_t slave_3_pdos[] = {
{0x1600, 7, slave_3_pdo_entries + 0}, /* ENC RxPDO-Map Control compact */
{0x1604, 5, slave_3_pdo_entries + 7}, /* STM RxPDO-Map Velocity */
{0x1606, 1, slave_3_pdo_entries + 12},
{0x1a00, 17, slave_3_pdo_entries + 13}, /* ENC TxPDO-Map Status compact */
{0x1a06, 14, slave_3_pdo_entries + 30},
{0x1a07, 2, slave_3_pdo_entries + 44},
};

ec_sync_info_t slave_3_syncs[] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 3, slave_3_pdos + 0, EC_WD_DISABLE},
{3, EC_DIR_INPUT, 3, slave_3_pdos + 3, EC_WD_DISABLE},
{0xff}
};
_______________________________________________
etherlab-users mailing list
etherlab-***@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users
Jakob Flierl
2015-05-09 23:29:45 UTC
Permalink
Thank's Thomas,

I simplified the pdo mappings in the source code. It now works, I
updated the sources on github and will create a pull request to the
original repo at https://github.com/sittner/linuxcnc-ethercat after
more testing.

Loading...