From: Graeme Foot <graeme.foot@touchcut.com>
Date: Tue, 18 Oct 2019 11:40:16 +1200

Hot plugged slaves can fail to read DC registers if they are read
before the EEPROM is loaded.

In the EtherCAT Hardware Data Sheet Section I document, section 17.2
Power-on Sequence, it says in Step 4:
"Process memory is not accessible until the SII EEPROM is loaded, 
as well as any function depending on ESC Configuration data"

For various ESC's (e.g. ET1201 ASIC) activation of the DC unit is based
on bits .2 and .3 of register 0x0141, which is loaded from the EEPROM.
While the DC unit is not activated the DC registers can not be read or
written from the master.

Section 17.2, Step 6, says that once the EEPROM is loaded, Register 0x0110
bit 0 turns to 1.  Due to this I have reordered the fsm_slave_scan
states so that the datalink states (which read register 0x0110) are run
before checking the dc registers.  This state now blocks until bit 0 is
set and error's out if there is a timout.

Apparently ET1100 and ET1201 ESC's get their DC units activated based on
information read from the EEPROM.  Only the ET1200 has the DC unit
activated by default, allowing the DC registers to be read immediately.

diff --git a/master/fsm_slave_scan.c b/master/fsm_slave_scan.c
--- a/master/fsm_slave_scan.c
+++ b/master/fsm_slave_scan.c
@@ -51,6 +51,15 @@
  */
 #define SCAN_RETRY_TIME 100
 
+/** EEPROM load timeout [ms].
+ *
+ * Used to calculate timeouts bsed on the jiffies counter.
+ *
+ * \attention Must be more than 10 to avoid problems on kernels that run with
+ * a timer interupt frequency of 100 Hz.
+ */
+#define EEPROM_LOAD_TIMEOUT 500
+
 /*****************************************************************************/
 
 void ec_fsm_slave_scan_state_start(ec_fsm_slave_scan_t *, ec_datagram_t *);
@@ -369,16 +378,13 @@
     slave->base_dc_supported = (octet >> 2) & 0x01;
     slave->base_dc_range = ((octet >> 3) & 0x01) ? EC_DC_64 : EC_DC_32;
 
-    if (slave->base_dc_supported) {
-        // read DC capabilities
-        ec_datagram_fprd(datagram, slave->station_address, 0x0910,
-                slave->base_dc_range == EC_DC_64 ? 8 : 4);
-        ec_datagram_zero(datagram);
-        fsm->retries = EC_FSM_RETRIES;
-        fsm->state = ec_fsm_slave_scan_state_dc_cap;
-    } else {
-        ec_fsm_slave_scan_enter_datalink(fsm, datagram);
-    }
+    // dc registers are not available for reading until the 
+    // EEPROM has finished reading, so read the datalink information
+    // first, checking the PDI operation/EEPROM loaded status
+    // before continuing
+    fsm->scan_jiffies_start = jiffies;
+    fsm->eeprom_loaded_retry = 0;
+    ec_fsm_slave_scan_enter_datalink(fsm, datagram);
 }
 
 /*****************************************************************************/
@@ -474,7 +480,13 @@
         slave->ports[i].receive_time = new_time;
     }
 
-    ec_fsm_slave_scan_enter_datalink(fsm, datagram);
+#ifdef EC_SII_ASSIGN
+    ec_fsm_slave_scan_enter_assign_sii(fsm, datagram);
+#elif defined(EC_SII_CACHE)
+    ec_fsm_slave_scan_enter_sii_identity(fsm, datagram);
+#else
+    ec_fsm_slave_scan_enter_attach_sii(fsm, datagram);
+#endif
 }
 
 /*****************************************************************************/
@@ -703,16 +715,48 @@
         ec_datagram_print_wc_error(fsm->datagram);
         return;
     }
+    
+    // check that the PDI operation/EEPROM loaded bit is set
+    if ((EC_READ_U8(fsm->datagram->data) & 0x01) == 0) {
+        unsigned long diff_ms = (fsm->datagram->jiffies_received -
+                fsm->scan_jiffies_start) * 1000 / HZ;
+      
+        if (fsm->eeprom_loaded_retry == 0) {
+            fsm->eeprom_loaded_retry = 1;
+            EC_SLAVE_WARN(slave, "EEPROM not yet loaded.  Retrying...\n");
+        }
+        
+        if (diff_ms < EEPROM_LOAD_TIMEOUT) {
+            fsm->retries = EC_FSM_RETRIES;
+            ec_datagram_repeat(datagram, fsm->datagram);
+        } else {
+            EC_SLAVE_ERR(fsm->slave, 
+                    "Timeout waiting for EEPROM to load.\n");
+            fsm->state = ec_fsm_slave_scan_state_error;
+        }
+        return;
+    } else if (fsm->eeprom_loaded_retry) {
+        EC_SLAVE_INFO(slave, "EEPROM loaded, continuing.\n");
+    }
 
     ec_slave_set_dl_status(slave, EC_READ_U16(fsm->datagram->data));
 
+    if (slave->base_dc_supported) {
+        // read DC capabilities
+        ec_datagram_fprd(datagram, slave->station_address, 0x0910,
+                slave->base_dc_range == EC_DC_64 ? 8 : 4);
+        ec_datagram_zero(datagram);
+        fsm->retries = EC_FSM_RETRIES;
+        fsm->state = ec_fsm_slave_scan_state_dc_cap;
+    } else {
 #ifdef EC_SII_ASSIGN
-    ec_fsm_slave_scan_enter_assign_sii(fsm, datagram);
+        ec_fsm_slave_scan_enter_assign_sii(fsm, datagram);
 #elif defined(EC_SII_CACHE)
-    ec_fsm_slave_scan_enter_sii_identity(fsm, datagram);
+        ec_fsm_slave_scan_enter_sii_identity(fsm, datagram);
 #else
-    ec_fsm_slave_scan_enter_attach_sii(fsm, datagram);
+        ec_fsm_slave_scan_enter_attach_sii(fsm, datagram);
 #endif
+    }
 }
 
 /*****************************************************************************/
diff --git a/master/fsm_slave_scan.h b/master/fsm_slave_scan.h
--- a/master/fsm_slave_scan.h
+++ b/master/fsm_slave_scan.h
@@ -62,6 +62,7 @@
     unsigned int retries; /**< Retries on datagram timeout. */
     unsigned int scan_retries; /**< Retries on scan read error. */
     unsigned long scan_jiffies_start; /**< scan retry start timestamp. */
+    uint8_t eeprom_loaded_retry; /**< rechecking EEPROM loaded */
 
     void (*state)(ec_fsm_slave_scan_t *, ec_datagram_t *); /**< State function. */
     uint16_t sii_offset; /**< SII offset in words. */
