DC cyclic operation and slave configuration. TBC...
authorFlorian Pose <fp@igh-essen.com>
Thu, 09 Apr 2009 09:17:41 +0000
changeset 1392 8fcc1d0987c1
parent 1391 9a547310f8d8
child 1393 979a7b26036d
DC cyclic operation and slave configuration. TBC...
NEWS
TODO
include/ecrt.h
master/fsm_slave_config.c
master/slave_config.c
master/slave_config.h
--- 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. */