SII writing workaround for some slaves, that don't respond correctly;
authorFlorian Pose <fp@igh-essen.com>
Mon, 24 Sep 2007 08:56:50 +0000
changeset 755 178353fc47e5
parent 754 0b47b49c5976
child 756 fc4693f251c7
SII writing workaround for some slaves, that don't respond correctly;
improved SII code.
NEWS
TODO
master/fsm_sii.c
master/fsm_sii.h
--- a/NEWS	Mon Sep 24 07:54:51 2007 +0000
+++ b/NEWS	Mon Sep 24 08:56:50 2007 +0000
@@ -6,6 +6,8 @@
 
 Changes in version 1.3.2:
 
+* Implemented SII writing workaround for some slaves, that don't respond
+  correctly.
 * Read dynamic PDO mapping from SDO dictionary.
 * Improved handling for spontaneous AL state changes.
 * Master takes mailbox sync manager configurations from EEPROM words
--- a/TODO	Mon Sep 24 07:54:51 2007 +0000
+++ b/TODO	Mon Sep 24 08:56:50 2007 +0000
@@ -7,15 +7,16 @@
 -------------------------------------------------------------------------------
 
 * Future features:
-  - Interface/buffers for asynchronous domain IO.
   - Distributed clocks.
   - Redundancy with 2 network adapters.
   - Mailbox handler
   - Support slaves, that don't support the LRW datagram, only LRD/LWR.
   - PDO reading in IDLE mode.
   - Replace Sysfs interface with cdev and user space program.
+  - Interface/buffers for asynchronous domain IO.
 
 * Smaller issues:
+  - Datagram debugging flag.
   - Clear sync managers in INIT.
   - Simplify FSMs with <state>_enter() functions.
   - Output intermediate results during lsec.
@@ -30,12 +31,12 @@
   - Interrupt master state machines state scan for other jobs.
   - Master state machine, slave configuration: Do not check every slave on
     a cycle.
-  - Do only execute one EoE handler per EoE cycle.
+  - Only execute one EoE handler per EoE cycle.
 
 * Less important issues:
   - Implement all EtherCAT datagram types.
   - File access over EtherCAT (FoE).
   - Allow VLAN tagging.
-  - Determine number of frames the NIC can handle.
+  - Determine number of frames, the NIC can handle.
 
 -------------------------------------------------------------------------------
--- a/master/fsm_sii.c	Mon Sep 24 07:54:51 2007 +0000
+++ b/master/fsm_sii.c	Mon Sep 24 08:56:50 2007 +0000
@@ -43,6 +43,11 @@
 #include "master.h"
 #include "fsm_sii.h"
 
+#define EEPROM_TIMEOUT 10 // read/write timeout [ms]
+#define EEPROM_INHIBIT  5 // time before evaluating answer at writing [ms]
+
+//#define SII_DEBUG
+
 /*****************************************************************************/
 
 void ec_fsm_sii_state_start_reading(ec_fsm_sii_t *);
@@ -86,13 +91,13 @@
 
 void ec_fsm_sii_read(ec_fsm_sii_t *fsm, /**< finite state machine */
                      ec_slave_t *slave, /**< slave to read from */
-                     uint16_t offset, /**< offset to read from */
+                     uint16_t word_offset, /**< offset to read from */
                      ec_fsm_sii_addressing_t mode /**< addressing scheme */
                      )
 {
     fsm->state = ec_fsm_sii_state_start_reading;
     fsm->slave = slave;
-    fsm->offset = offset;
+    fsm->word_offset = word_offset;
     fsm->mode = mode;
 }
 
@@ -104,14 +109,14 @@
 
 void ec_fsm_sii_write(ec_fsm_sii_t *fsm, /**< finite state machine */
                       ec_slave_t *slave, /**< slave to read from */
-                      uint16_t offset, /**< offset to read from */
+                      uint16_t word_offset, /**< offset to read from */
                       const uint8_t *value, /**< pointer to 2 bytes of data */
                       ec_fsm_sii_addressing_t mode /**< addressing scheme */
                       )
 {
     fsm->state = ec_fsm_sii_state_start_writing;
     fsm->slave = slave;
-    fsm->offset = offset;
+    fsm->word_offset = word_offset;
     fsm->mode = mode;
     memcpy(fsm->value, value, 2);
 }
@@ -168,9 +173,15 @@
             break;
     }
 
-    EC_WRITE_U8 (datagram->data,     0x00); // read-only access
+    EC_WRITE_U8 (datagram->data,     0x80); // two address octets
     EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
-    EC_WRITE_U16(datagram->data + 2, fsm->offset);
+    EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
+
+#ifdef SII_DEBUG
+	EC_DBG("reading SII data:\n");
+	ec_print_data(datagram->data, 4);
+#endif
+
     fsm->retries = EC_FSM_RETRIES;
     fsm->state = ec_fsm_sii_state_read_check;
 }
@@ -256,47 +267,37 @@
         return;
     }
 
+#ifdef SII_DEBUG
+	EC_DBG("checking SII read state:\n");
+	ec_print_data(datagram->data, 10);
+#endif
+
+    if (EC_READ_U8(datagram->data + 1) & 0x20) {
+        EC_ERR("SII: Error on last SII command!\n");
+        fsm->state = ec_fsm_sii_state_error;
+        return;
+    }
+
     // check "busy bit"
-    if (EC_READ_U8(datagram->data + 1) & 0x81) {
+    if (EC_READ_U8(datagram->data + 1) & 0x81) { // busy bit or
+												 // read operation busy
         // still busy... timeout?
         if (datagram->cycles_received
-            - fsm->cycles_start >= (cycles_t) 10 * cpu_khz) {
-            if (!fsm->check_once_more) {
+            - fsm->cycles_start >= (cycles_t) EEPROM_TIMEOUT * cpu_khz) {
+            if (fsm->check_once_more) {
+				fsm->check_once_more = 0;
+			} else {
                 EC_ERR("SII: Read timeout.\n");
                 fsm->state = ec_fsm_sii_state_error;
-#if 0
-                EC_DBG("SII busy: %02X %02X %02X %02X\n",
-                       EC_READ_U8(datagram->data + 0),
-                       EC_READ_U8(datagram->data + 1),
-                       EC_READ_U8(datagram->data + 2),
-                       EC_READ_U8(datagram->data + 3));
-#endif
                 return;
             }
-            fsm->check_once_more = 0;
         }
 
         // issue check/fetch datagram again
-        switch (fsm->mode) {
-            case EC_FSM_SII_POSITION:
-                ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
-                break;
-            case EC_FSM_SII_NODE:
-                ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10);
-                break;
-        }
         fsm->retries = EC_FSM_RETRIES;
         return;
     }
 
-#if 0
-    EC_DBG("SII rec: %02X %02X %02X %02X - %02X %02X %02X %02X\n",
-           EC_READ_U8(datagram->data + 0), EC_READ_U8(datagram->data + 1),
-           EC_READ_U8(datagram->data + 2), EC_READ_U8(datagram->data + 3),
-           EC_READ_U8(datagram->data + 6), EC_READ_U8(datagram->data + 7),
-           EC_READ_U8(datagram->data + 8), EC_READ_U8(datagram->data + 9));
-#endif
-
     // SII value received.
     memcpy(fsm->value, datagram->data + 6, 4);
     fsm->state = ec_fsm_sii_state_end;
@@ -306,7 +307,7 @@
 
 /**
    SII state: START WRITING.
-   Starts reading the slave information interface.
+   Starts writing a word through the slave information interface.
 */
 
 void ec_fsm_sii_state_start_writing(
@@ -317,11 +318,18 @@
 
     // initiate write operation
     ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 8);
-    EC_WRITE_U8 (datagram->data,     0x01); // enable write access
+    EC_WRITE_U8 (datagram->data,     0x81); // two address octets
+											// + enable write access
     EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
-    EC_WRITE_U32(datagram->data + 2, fsm->offset);
+    EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
+	memset(datagram->data + 4, 0x00, 2);
     memcpy(datagram->data + 6, fsm->value, 2);
 
+#ifdef SII_DEBUG
+	EC_DBG("writing SII data:\n");
+	ec_print_data(datagram->data, 8);
+#endif
+
     fsm->retries = EC_FSM_RETRIES;
     fsm->state = ec_fsm_sii_state_write_check;
 }
@@ -360,7 +368,7 @@
     fsm->cycles_start = datagram->cycles_sent;
     fsm->check_once_more = 1;
 
-    // issue check/fetch datagram
+    // issue check datagram
     ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 2);
     fsm->retries = EC_FSM_RETRIES;
     fsm->state = ec_fsm_sii_state_write_check2;
@@ -397,19 +405,44 @@
         return;
     }
 
-    if (EC_READ_U8(datagram->data + 1) & 0x82) {
+#ifdef SII_DEBUG
+	EC_DBG("checking SII write state:\n");
+	ec_print_data(datagram->data, 2);
+#endif
+
+    if (EC_READ_U8(datagram->data + 1) & 0x20) {
+        EC_ERR("SII: Error on last SII command!\n");
+        fsm->state = ec_fsm_sii_state_error;
+        return;
+    }
+
+	/* FIXME: some slaves never answer with the busy flag set...
+	 * wait a few ms for the write operation to complete. */
+	if (datagram->cycles_received - fsm->cycles_start
+			< (cycles_t) EEPROM_INHIBIT * cpu_khz) {
+#ifdef SII_DEBUG
+		EC_DBG("too early.\n");
+#endif
+        // issue check datagram again
+        fsm->retries = EC_FSM_RETRIES;
+        return;
+	}
+
+    if (EC_READ_U8(datagram->data + 1) & 0x82) { // busy bit or
+												 // write operation busy bit
         // still busy... timeout?
         if (datagram->cycles_received
-            - fsm->cycles_start >= (cycles_t) 10 * cpu_khz) {
-            if (!fsm->check_once_more) {
+            - fsm->cycles_start >= (cycles_t) EEPROM_TIMEOUT * cpu_khz) {
+            if (fsm->check_once_more) {
+				fsm->check_once_more = 0;
+			} else {
                 EC_ERR("SII: Write timeout.\n");
                 fsm->state = ec_fsm_sii_state_error;
                 return;
             }
-            fsm->check_once_more = 0;
         }
 
-        // issue check/fetch datagram again
+        // issue check datagram again
         fsm->retries = EC_FSM_RETRIES;
         return;
     }
--- a/master/fsm_sii.h	Mon Sep 24 07:54:51 2007 +0000
+++ b/master/fsm_sii.h	Mon Sep 24 08:56:50 2007 +0000
@@ -70,7 +70,7 @@
     unsigned int retries; /**< retries upon datagram timeout */
 
     void (*state)(ec_fsm_sii_t *); /**< SII state function */
-    uint16_t offset; /**< input: offset in SII */
+    uint16_t word_offset; /**< input: word offset in SII */
     ec_fsm_sii_addressing_t mode; /**< reading via APRD or NPRD */
     uint8_t value[4]; /**< raw SII value (32bit) */
     cycles_t cycles_start; /**< start timestamp */