DC cyclic operation and slave configuration. TBC...
--- a/NEWS Wed Apr 08 16:20:13 2009 +0000
+++ b/NEWS Thu Apr 09 09:17:41 2009 +0000
@@ -10,6 +10,7 @@
* Added a userspace library for accessing the application interface. This
library is licensed under LGPLv2.
+* Added distributed clocks support.
* Added VoE mailbox protocol support.
* Separated datagram initialization from filling the payload with zeros.
Introduced new method ec_datagram_zero() for that.
--- a/TODO Wed Apr 08 16:20:13 2009 +0000
+++ b/TODO Thu Apr 09 09:17:41 2009 +0000
@@ -10,6 +10,10 @@
Version 1.5.0:
+* Distributed clocks:
+ - Delay calculation.
+ - Synchronize the reference clock to the master clock.
+* Read alias from register 0x0012 instead of SII.
* Output link state in 'ethercat master'.
* Finish library implementation.
* Re-work EoE code.
@@ -22,12 +26,10 @@
* Check force_config flag before error.
* Remove allow_scanning flag.
* Test File access over EtherCAT (FoE) reading.
-* Distributed clocks.
* Implement ecrt_master_slave() in kernel space.
* Check for ioctl() interface version.
* Improve application-triggered SDO transfers by moving the statemachine into
the SDO handlers.
-* FoE in application interface?
* Apply watchdog patches from J. Mohre.
Future issues:
--- a/include/ecrt.h Wed Apr 08 16:20:13 2009 +0000
+++ b/include/ecrt.h Thu Apr 09 09:17:41 2009 +0000
@@ -41,6 +41,10 @@
*
* Changes in version 1.5:
*
+ * - Added the distributed clocks feature and the respective methods
+ * ecrt_slave_config_dc_assign_activate() and
+ * ecrt_slave_config_dc_sync_cycle_times() to configure a slave for cyclic
+ * operation.
* - Changed the meaning of the negative return values of
* ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
* - Imlemented the Vendor-specific over EtherCAT mailbox protocol. See
@@ -671,6 +675,25 @@
is desired */
);
+/** Sets the AssignActivate word necessary for DC operation.
+ *
+ * The AssignActivate word is vendor-specific and can be taken from the XML
+ * device description file (Device -> Dc -> AssignActivate). Set this to zero,
+ * if the slave shall be not operated without distributed clocks (default).
+ */
+void ecrt_slave_config_dc_assign_activate(
+ ec_slave_config_t *sc, /**< Slave configuration. */
+ uint16_t assign_activate /**< AssignActivate word. */
+ );
+
+/** Sets the cylce times for the SYNC0 and SYNC1 signals.
+ */
+void ecrt_slave_config_dc_sync_cycle_times(
+ ec_slave_config_t *sc, /**< Slave configuration. */
+ uint32_t sync0_cycle_time, /**< SYNC0 cycle time [ns]. */
+ uint32_t sync1_cycle_time /**< SYNC1 cycle time [ns]. */
+ );
+
/** Add an SDO configuration.
*
* An SDO configuration is stored in the slave configuration object and is
--- a/master/fsm_slave_config.c Wed Apr 08 16:20:13 2009 +0000
+++ b/master/fsm_slave_config.c Thu Apr 09 09:17:41 2009 +0000
@@ -52,6 +52,9 @@
void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *);
@@ -63,6 +66,8 @@
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_enter_dc_assign(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *);
@@ -602,6 +607,7 @@
ec_slave_t *slave = fsm->slave;
// No CoE configuration to be applied?
+ // FIXME check for config
if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
ec_fsm_slave_config_enter_pdo_conf(fsm);
return;
@@ -805,7 +811,7 @@
}
if (!slave->base_fmmu_count) { // skip FMMU configuration
- ec_fsm_slave_config_enter_safeop(fsm);
+ ec_fsm_slave_config_enter_dc_cycle(fsm);
return;
}
@@ -861,6 +867,161 @@
return;
}
+ ec_fsm_slave_config_enter_dc_cycle(fsm);
+}
+
+/*****************************************************************************/
+
+/** Check for DCs to be configured.
+ */
+void ec_fsm_slave_config_enter_dc_cycle(
+ ec_fsm_slave_config_t *fsm /**< slave state machine */
+ )
+{
+ ec_datagram_t *datagram = fsm->datagram;
+ ec_slave_t *slave = fsm->slave;
+ ec_slave_config_t *config = slave->config;
+
+ if (config->dc_assign_activate) {
+ if (!slave->base_dc_supported) {
+ EC_WARN("Attempt to enable synchronized mode for slave %u,"
+ " that seems not to support distributed clocks!\n",
+ slave->ring_position);
+ }
+
+ // set DC cycle times
+ ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
+ EC_WRITE_U32(datagram->data, config->dc_sync_cycle_times[0]);
+ EC_WRITE_U32(datagram->data + 4, config->dc_sync_cycle_times[1]);
+ fsm->retries = EC_FSM_RETRIES;
+ fsm->state = ec_fsm_slave_config_state_dc_cycle;
+ } else {
+ ec_fsm_slave_config_enter_dc_assign(fsm);
+ }
+}
+
+/*****************************************************************************/
+
+/** Slave configuration state: DC CYCLE.
+ */
+void ec_fsm_slave_config_state_dc_cycle(
+ ec_fsm_slave_config_t *fsm /**< slave state machine */
+ )
+{
+ ec_datagram_t *datagram = fsm->datagram;
+ ec_slave_t *slave = fsm->slave;
+
+ if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
+ return;
+
+ if (datagram->state != EC_DATAGRAM_RECEIVED) {
+ fsm->state = ec_fsm_slave_config_state_error;
+ EC_ERR("Failed to receive DC cycle times datagram for slave %u"
+ " (datagram state %u).\n",
+ slave->ring_position, datagram->state);
+ return;
+ }
+
+ if (datagram->working_counter != 1) {
+ slave->error_flag = 1;
+ fsm->state = ec_fsm_slave_config_state_error;
+ EC_ERR("Failed to set DC cycle times of slave %u: ",
+ slave->ring_position);
+ ec_datagram_print_wc_error(datagram);
+ return;
+ }
+
+ // set DC start time
+ ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
+ EC_WRITE_U64(datagram->data, 0x37E11D600ULL); // 15 s, FIXME
+ fsm->retries = EC_FSM_RETRIES;
+ fsm->state = ec_fsm_slave_config_state_dc_start;
+}
+
+/*****************************************************************************/
+
+/** Slave configuration state: DC START.
+ */
+void ec_fsm_slave_config_state_dc_start(
+ ec_fsm_slave_config_t *fsm /**< slave state machine */
+ )
+{
+ ec_datagram_t *datagram = fsm->datagram;
+ ec_slave_t *slave = fsm->slave;
+
+ if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
+ return;
+
+ if (datagram->state != EC_DATAGRAM_RECEIVED) {
+ fsm->state = ec_fsm_slave_config_state_error;
+ EC_ERR("Failed to receive DC start time datagram for slave %u"
+ " (datagram state %u).\n",
+ slave->ring_position, datagram->state);
+ return;
+ }
+
+ if (datagram->working_counter != 1) {
+ slave->error_flag = 1;
+ fsm->state = ec_fsm_slave_config_state_error;
+ EC_ERR("Failed to set DC start time of slave %u: ",
+ slave->ring_position);
+ ec_datagram_print_wc_error(datagram);
+ return;
+ }
+
+ ec_fsm_slave_config_enter_dc_assign(fsm);
+}
+
+/*****************************************************************************/
+
+/** Set the DC AssignActivate word.
+ */
+void ec_fsm_slave_config_enter_dc_assign(
+ ec_fsm_slave_config_t *fsm /**< slave state machine */
+ )
+{
+ ec_datagram_t *datagram = fsm->datagram;
+ ec_slave_t *slave = fsm->slave;
+ ec_slave_config_t *config = slave->config;
+
+ // assign sync unit to EtherCAT or PDI
+ ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
+ EC_WRITE_U16(datagram->data, config->dc_assign_activate);
+ fsm->retries = EC_FSM_RETRIES;
+ fsm->state = ec_fsm_slave_config_state_dc_assign;
+}
+
+/*****************************************************************************/
+
+/** Slave configuration state: DC ASSIGN.
+ */
+void ec_fsm_slave_config_state_dc_assign(
+ ec_fsm_slave_config_t *fsm /**< slave state machine */
+ )
+{
+ ec_datagram_t *datagram = fsm->datagram;
+ ec_slave_t *slave = fsm->slave;
+
+ if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
+ return;
+
+ if (datagram->state != EC_DATAGRAM_RECEIVED) {
+ fsm->state = ec_fsm_slave_config_state_error;
+ EC_ERR("Failed to receive DC activation datagram for slave %u"
+ " (datagram state %u).\n",
+ slave->ring_position, datagram->state);
+ return;
+ }
+
+ if (datagram->working_counter != 1) {
+ slave->error_flag = 1;
+ fsm->state = ec_fsm_slave_config_state_error;
+ EC_ERR("Failed to set DC cyclia operation state of slave %u: ",
+ slave->ring_position);
+ ec_datagram_print_wc_error(datagram);
+ return;
+ }
+
ec_fsm_slave_config_enter_safeop(fsm);
}
--- a/master/slave_config.c Wed Apr 08 16:20:13 2009 +0000
+++ b/master/slave_config.c Thu Apr 09 09:17:41 2009 +0000
@@ -61,20 +61,26 @@
unsigned int i;
sc->master = master;
+
sc->alias = alias;
sc->position = position;
sc->vendor_id = vendor_id;
sc->product_code = product_code;
+
sc->slave = NULL;
for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++)
ec_sync_config_init(&sc->sync_configs[i]);
+ sc->used_fmmus = 0;
+
+ sc->dc_assign_activate = 0x0000;
+ sc->dc_sync_cycle_times[0] = 0x00000000;
+ sc->dc_sync_cycle_times[1] = 0x00000000;
+
INIT_LIST_HEAD(&sc->sdo_configs);
INIT_LIST_HEAD(&sc->sdo_requests);
INIT_LIST_HEAD(&sc->voe_handlers);
-
- sc->used_fmmus = 0;
}
/*****************************************************************************/
@@ -399,7 +405,7 @@
}
/******************************************************************************
- * Realtime interface
+ * Application interface
*****************************************************************************/
int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index,
@@ -665,6 +671,22 @@
return -ENOENT;
}
+/*****************************************************************************/
+
+void ecrt_slave_config_dc_assign_activate(ec_slave_config_t *sc,
+ uint16_t assign_activate)
+{
+ sc->dc_assign_activate = assign_activate;
+}
+
+/*****************************************************************************/
+
+void ecrt_slave_config_dc_sync_cycle_times(ec_slave_config_t *sc,
+ uint32_t sync0_cycle_time, uint32_t sync1_cycle_time)
+{
+ sc->dc_sync_cycle_times[0] = sync0_cycle_time;
+ sc->dc_sync_cycle_times[1] = sync1_cycle_time;
+}
/*****************************************************************************/
@@ -880,6 +902,8 @@
EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_clear);
EXPORT_SYMBOL(ecrt_slave_config_pdos);
EXPORT_SYMBOL(ecrt_slave_config_reg_pdo_entry);
+EXPORT_SYMBOL(ecrt_slave_config_dc_assign_activate);
+EXPORT_SYMBOL(ecrt_slave_config_dc_sync_cycle_times);
EXPORT_SYMBOL(ecrt_slave_config_sdo);
EXPORT_SYMBOL(ecrt_slave_config_sdo8);
EXPORT_SYMBOL(ecrt_slave_config_sdo16);
--- a/master/slave_config.h Wed Apr 08 16:20:13 2009 +0000
+++ b/master/slave_config.h Thu Apr 09 09:17:41 2009 +0000
@@ -66,6 +66,9 @@
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
uint8_t used_fmmus; /**< Number of FMMUs used. */
+ uint16_t dc_assign_activate; /**< Vendor-specific AssignActivate word. */
+ uint32_t dc_sync_cycle_times[2]; /**< SYNC[0,1] cycle times. */
+
struct list_head sdo_configs; /**< List of SDO configurations. */
struct list_head sdo_requests; /**< List of SDO requests. */
struct list_head voe_handlers; /**< List of VoE handlers. */