Explorar el Código

feat: support single domain and multi domain

Signed-off-by: sakumisu <1203593632@qq.com>
sakumisu hace 18 horas
padre
commit
85de8d7bd4
Se han modificado 9 ficheros con 75 adiciones y 95 borrados
  1. 3 1
      README.md
  2. 3 1
      README_zh.md
  3. 5 4
      cherryecat_config_template.h
  4. 5 4
      demo/hpmicro/inc/ec_config.h
  5. 0 2
      include/ec_datagram.h
  6. 2 12
      include/ec_master.h
  7. 2 0
      include/ec_slave.h
  8. 2 1
      src/ec_cmd.c
  9. 53 70
      src/ec_master.c

+ 3 - 1
README.md

@@ -26,10 +26,11 @@ CherryECAT is a tiny and beautiful, high real-time and low-jitter EtherCAT maste
 - Support Slave SII access
 - Support Slave register access
 - Support multi master
-- **Support backup redundancy(TODO)**
+- Support PDO transfer with single domain or multi domain(single domain:all slaves share one LRW datagram,multi domain:each slave has one LRW datagram)
 - **Minimum PDO cyclic time < 40 us (depends on master and slave hardware)**
 - **DC jitter < 3us (depends on master and slave hardware)**
 - **Support multi cyclic time(every slave can use different proportional cyclic time)**
+- **Support backup redundancy(TODO)**
 - Support ethercat cmd with shell, ref to IgH
 
 The pic shows dc jitter < 3us (hpm6800evk with flash_xip):
@@ -47,6 +48,7 @@ The pic shows dc jitter < 3us (hpm6800evk with flash_xip):
 - **Slave**
 	- Must support DC and system time
 	- Must support sdo complete access
+	- Must support LRW
 	- SII must have sync manager information
 
 ## Shell cmd

+ 3 - 1
README_zh.md

@@ -26,10 +26,11 @@ CherryECAT 是一个小而美的、高实时性、低抖动的 EtherCAT 主机
 - 支持 Slave SII 读写
 - 支持 Slave 寄存器读写
 - 支持多主站
-- **支持备份冗余(TODO)**
+- 支持 PDO 单域和多域通信(单域:所有 slaves 共享一个 LRW datagram,多域:每个 slave 拥有一个 LRW datagram)
 - **最小 PDO cyclic time < 40 us (实际数值受主站硬件和从站硬件影响)**
 - **DC 抖动 < 3us (实际数值受主站硬件和从站硬件影响)**
 - **支持多周期(每个从站可以使用不同的成比例的周期)**
+- **支持备份冗余(TODO)**
 - 支持 ethercat 命令行交互,参考 IgH
 
 下图展示 dc 抖动 < 3us (hpm6800evk + flash_xip):
@@ -47,6 +48,7 @@ CherryECAT 是一个小而美的、高实时性、低抖动的 EtherCAT 主机
 - 从站
 	- 必须支持 DC 和 system time 功能
 	- 必须支持 sdo complete access
+	- 必须支持 LRW 功能
 	- SII 必须携带 sync manager 信息
 
 ## Shell 命令

+ 5 - 4
cherryecat_config_template.h

@@ -21,6 +21,11 @@
 
 #define EC_FAST_CODE_SECTION
 
+// #define CONFIG_EC_PDO_MULTI_DOMAIN
+#define CONFIG_EC_CMD_ENABLE
+// #define CONFIG_EC_TIMESTAMP_CUSTOM
+// #define CONFIG_EC_PHY_CUSTOM
+
 #ifndef CONFIG_EC_MAX_NETDEVS
 #define CONFIG_EC_MAX_NETDEVS 1
 #endif
@@ -61,10 +66,6 @@
 #define CONFIG_EC_PER_PDO_MAX_PDO_ENTRIES 8
 #endif
 
-#define CONFIG_EC_CMD_ENABLE
-// #define CONFIG_EC_TIMESTAMP_CUSTOM
-// #define CONFIG_EC_PHY_CUSTOM
-
 #ifndef CONFIG_EC_MAX_PDO_BUFSIZE
 #define CONFIG_EC_MAX_PDO_BUFSIZE 2048
 #endif

+ 5 - 4
demo/hpmicro/inc/ec_config.h

@@ -21,6 +21,11 @@
 
 #define EC_FAST_CODE_SECTION __attribute__((section(".fast")))
 
+// #define CONFIG_EC_PDO_MULTI_DOMAIN
+#define CONFIG_EC_CMD_ENABLE
+// #define CONFIG_EC_TIMESTAMP_CUSTOM
+// #define CONFIG_EC_PHY_CUSTOM
+
 #ifndef CONFIG_EC_MAX_NETDEVS
 #define CONFIG_EC_MAX_NETDEVS 1
 #endif
@@ -61,10 +66,6 @@
 #define CONFIG_EC_PER_PDO_MAX_PDO_ENTRIES 8
 #endif
 
-#define CONFIG_EC_CMD_ENABLE
-// #define CONFIG_EC_TIMESTAMP_CUSTOM
-// #define CONFIG_EC_PHY_CUSTOM
-
 #ifndef CONFIG_EC_MAX_PDO_BUFSIZE
 #define CONFIG_EC_MAX_PDO_BUFSIZE 2048
 #endif

+ 0 - 2
include/ec_datagram.h

@@ -55,8 +55,6 @@ typedef struct {
     uint8_t index;                    /**< Index (set by master). */
     uint16_t working_counter;         /**< Working counter. */
     ec_datagram_state_t state;        /**< State. */
-    uint32_t lrw_read_offset;         /**< Read Offset in LRW datagram. */
-    uint32_t lrw_read_size;           /**< Read Size in LRW datagram. */
     uint64_t jiffies_sent;            /**< Jiffies [ns], when the datagram was sent. */
     uint64_t jiffies_received;        /**< Jiffies [ns], when the datagram was received. */
     char name[EC_DATAGRAM_NAME_SIZE]; /**< Description of the datagram. */

+ 2 - 12
include/ec_master.h

@@ -44,16 +44,6 @@ typedef enum {
     EC_OPERATION /**< Operation phase. The master was requested by a realtime application. */
 } ec_master_phase_t;
 
-typedef struct {
-    ec_dlist_t queue;
-    ec_datagram_t datagrams[CONFIG_EC_MAX_NETDEVS];
-#if CONFIG_EC_MAX_NETDEVS > 1
-    uint8_t *send_buffer;
-#endif
-    uint32_t expected_working_counter;
-    ec_slave_t *slave;
-} ec_pdo_datagram_t;
-
 typedef struct ec_master {
     uint8_t index;
     ec_netdev_t *netdev[CONFIG_EC_MAX_NETDEVS];
@@ -68,9 +58,9 @@ typedef struct ec_master {
     ec_master_phase_t phase;
 
     ec_datagram_t main_datagram; /**< Main datagram for slave scan & state change & config & sii */
+    ec_datagram_t pdo_datagram;  /**< pdo datagram */
 
-    ec_dlist_t datagram_queue;     /**< Queue of pending datagrams*/
-    ec_dlist_t pdo_datagram_queue; /**< Queue of pdo datagrams*/
+    ec_dlist_t datagram_queue; /**< Queue of pending datagrams*/
     uint8_t datagram_index;
 
     ec_slave_t *dc_ref_clock;           /**< DC reference clock slave. */

+ 2 - 0
include/ec_slave.h

@@ -100,6 +100,8 @@ typedef struct ec_slave {
     uint8_t sm_count; /**< Number of sync managers. */
 
     ec_slave_config_t *config; /**< Slave custom configuration. */
+
+    ec_datagram_t pdo_datagram; /**< PDO datagram for the slave. */
 } ec_slave_t;
 
 void ec_slaves_scanning(ec_master_t *master);

+ 2 - 1
src/ec_cmd.c

@@ -574,7 +574,7 @@ int ethercat(int argc, const char **argv)
                        global_cmd_master->index,
                        global_cmd_master->actual_working_counter,
                        global_cmd_master->expected_working_counter);
-
+#ifdef CONFIG_EC_PDO_MULTI_DOMAIN
             for (uint32_t i = 0; i < global_cmd_master->slave_count; i++) {
                 EC_LOG_RAW("%-3u  %u:%04x         (actual/expect): %u/%u\n",
                            global_cmd_master->index,
@@ -583,6 +583,7 @@ int ethercat(int argc, const char **argv)
                            global_cmd_master->slaves[i].actual_working_counter,
                            global_cmd_master->slaves[i].expected_working_counter);
             }
+#endif
             return 0;
         } else {
         }

+ 53 - 70
src/ec_master.c

@@ -218,12 +218,7 @@ EC_FAST_CODE_SECTION void ec_master_receive_datagrams(ec_master_t *master,
             datagram->type != EC_DATAGRAM_FPWR &&
             datagram->type != EC_DATAGRAM_BWR &&
             datagram->type != EC_DATAGRAM_LWR) {
-            // copy received data into the datagram memory, only copy the read part, do not modify the write part
-            if (datagram->type == EC_DATAGRAM_LRW) {
-                ec_memcpy(datagram->data + datagram->lrw_read_offset, cur_data + datagram->lrw_read_offset, datagram->lrw_read_size);
-            } else {
-                ec_memcpy(datagram->data, cur_data, data_size);
-            }
+            ec_memcpy(datagram->data, cur_data, data_size);
         }
         cur_data += data_size;
 
@@ -351,7 +346,6 @@ int ec_master_init(ec_master_t *master, uint8_t master_index)
     master->datagram_index = 1; // start with index 1
 
     ec_dlist_init(&master->datagram_queue);
-    ec_dlist_init(&master->pdo_datagram_queue);
 
     ec_timestamp_init();
 
@@ -407,8 +401,6 @@ int ec_master_start(ec_master_t *master)
 {
     ec_slave_t *slave;
     uint32_t bitlen;
-    bool used[2] = { false, false };
-    uint8_t netdev_idx;
     uint8_t sm_idx;
 
     EC_ASSERT_MSG(master->cycle_time >= (40 * 1000), "Cycle time %u ns is too small. Minimum is 40000 ns.\n", master->cycle_time);
@@ -490,54 +482,34 @@ int ec_master_start(ec_master_t *master)
             master->actual_pdo_size += (bitlen + 7) / 8;
 
             if (slave->config->sync[i].dir == EC_DIR_INPUT) {
-                used[EC_DIR_INPUT] = true;
                 slave->idata_size += (bitlen + 7) / 8;
             }
             if (slave->config->sync[i].dir == EC_DIR_OUTPUT) {
-                used[EC_DIR_OUTPUT] = true;
                 slave->odata_size += (bitlen + 7) / 8;
             }
         }
-
-        ec_pdo_datagram_t *pdo_datagram;
-
-        pdo_datagram = (ec_pdo_datagram_t *)ec_osal_malloc(sizeof(ec_pdo_datagram_t));
-        if (!pdo_datagram) {
-            return -1;
-        }
-        memset(pdo_datagram, 0, sizeof(ec_pdo_datagram_t));
-
-        for (netdev_idx = EC_NETDEV_MAIN; netdev_idx < CONFIG_EC_MAX_NETDEVS; netdev_idx++) {
-            ec_datagram_init_static(&pdo_datagram->datagrams[netdev_idx], &master->pdo_buffer[netdev_idx][slave->logical_start_address],
-                                    slave->odata_size + slave->idata_size);
-            pdo_datagram->datagrams[netdev_idx].netdev_idx = netdev_idx;
-
-            if (used[EC_DIR_OUTPUT] && used[EC_DIR_INPUT]) {
-                ec_datagram_lrw(&pdo_datagram->datagrams[netdev_idx], slave->logical_start_address, slave->odata_size + slave->idata_size);
-                pdo_datagram->datagrams[netdev_idx].lrw_read_offset = slave->odata_size;
-                pdo_datagram->datagrams[netdev_idx].lrw_read_size = slave->idata_size;
-                pdo_datagram->expected_working_counter = 3;
-            } else if (used[EC_DIR_INPUT]) {
-                ec_datagram_lrd(&pdo_datagram->datagrams[netdev_idx], slave->logical_start_address, slave->idata_size);
-                pdo_datagram->expected_working_counter = 1;
-            } else if (used[EC_DIR_OUTPUT]) {
-                ec_datagram_lwr(&pdo_datagram->datagrams[netdev_idx], slave->logical_start_address, slave->odata_size);
-                pdo_datagram->expected_working_counter = 1;
-            }
-            ec_datagram_zero(&pdo_datagram->datagrams[netdev_idx]);
-        }
-        slave->expected_working_counter = pdo_datagram->expected_working_counter;
+#ifdef CONFIG_EC_PDO_MULTI_DOMAIN
+        ec_datagram_init_static(&slave->pdo_datagram,
+                                &master->pdo_buffer[EC_NETDEV_MAIN][slave->logical_start_address],
+                                slave->odata_size + slave->idata_size);
+        ec_datagram_lrw(&slave->pdo_datagram, slave->logical_start_address, slave->odata_size + slave->idata_size);
+        ec_datagram_zero(&slave->pdo_datagram);
+#endif
+        slave->expected_working_counter = 3;
         master->expected_working_counter += slave->expected_working_counter;
-        pdo_datagram->slave = slave;
 
         EC_SLAVE_LOG_INFO("Slave %u: Logical address 0x%08x, obyte %u, ibyte %u, expected working counter %u\n",
                           slave->index,
                           slave->logical_start_address, slave->odata_size, slave->idata_size,
                           slave->expected_working_counter);
-
-        ec_dlist_add_tail(&master->pdo_datagram_queue, &pdo_datagram->queue);
     }
-
+#ifndef CONFIG_EC_PDO_MULTI_DOMAIN
+    ec_datagram_init_static(&master->pdo_datagram,
+                            &master->pdo_buffer[EC_NETDEV_MAIN][0],
+                            master->actual_pdo_size);
+    ec_datagram_lrw(&master->pdo_datagram, 0, master->actual_pdo_size);
+    ec_datagram_zero(&master->pdo_datagram);
+#endif
     ec_htimer_start(master->cycle_time / 1000, ec_master_period_process, master);
 
     for (uint32_t i = 0; i < master->slave_count; i++) {
@@ -553,7 +525,6 @@ int ec_master_start(ec_master_t *master)
 
 int ec_master_stop(ec_master_t *master)
 {
-    ec_pdo_datagram_t *pdo_datagram, *n;
     uint8_t netdev_idx;
 
     if (!master->started) {
@@ -584,15 +555,13 @@ int ec_master_stop(ec_master_t *master)
 
 out:
     ec_htimer_stop();
-
-    ec_dlist_for_each_entry_safe(pdo_datagram, n, &master->pdo_datagram_queue, queue)
-    {
-        for (netdev_idx = EC_NETDEV_MAIN; netdev_idx < CONFIG_EC_MAX_NETDEVS; netdev_idx++) {
-            ec_datagram_clear(&pdo_datagram->datagrams[netdev_idx]);
-        }
-        ec_dlist_del_init(&pdo_datagram->queue);
-        ec_osal_free(pdo_datagram);
+#ifndef CONFIG_EC_PDO_MULTI_DOMAIN
+    ec_datagram_clear(&master->pdo_datagram);
+#else
+    for (uint32_t i = 0; i < master->slave_count; i++) {
+        ec_datagram_clear(&master->slaves[i].pdo_datagram);
     }
+#endif
 
     ec_master_enter_idle(master);
 
@@ -745,9 +714,8 @@ EC_FAST_CODE_SECTION static void ec_master_dc_sync_with_pi(ec_master_t *master,
 EC_FAST_CODE_SECTION static void ec_master_period_process(void *arg)
 {
     ec_master_t *master = (ec_master_t *)arg;
-    ec_pdo_datagram_t *pdo_datagram, *n;
-    uint8_t netdev_idx;
     uint64_t dc_ref_systime = 0;
+    ec_slave_t *slave;
     int32_t offsettime = 0;
     uint64_t start_time;
     uint32_t period_ns;
@@ -778,33 +746,48 @@ EC_FAST_CODE_SECTION static void ec_master_period_process(void *arg)
     }
 
     master->actual_working_counter = 0;
-    ec_dlist_for_each_entry_safe(pdo_datagram, n, &master->pdo_datagram_queue, queue)
-    {
-        for (netdev_idx = EC_NETDEV_MAIN; netdev_idx < CONFIG_EC_MAX_NETDEVS; netdev_idx++) {
-            if (pdo_datagram->datagrams[netdev_idx].state == EC_DATAGRAM_RECEIVED) {
-                master->actual_working_counter += pdo_datagram->datagrams[netdev_idx].working_counter;
-                pdo_datagram->slave->actual_working_counter = pdo_datagram->datagrams[netdev_idx].working_counter;
+#ifndef CONFIG_EC_PDO_MULTI_DOMAIN
+    if (master->pdo_datagram.state == EC_DATAGRAM_RECEIVED) {
+        for (uint32_t i = 0; i < master->slave_count; i++) {
+            slave = &master->slaves[i];
+
+            if (slave->config && slave->config->pdo_callback) {
+                slave->config->pdo_callback(slave,
+                                            (uint8_t *)&master->pdo_buffer[EC_NETDEV_MAIN][slave->logical_start_address],
+                                            (uint8_t *)&master->pdo_buffer[EC_NETDEV_MAIN][slave->logical_start_address + slave->odata_size]);
             }
         }
+        master->actual_working_counter = master->pdo_datagram.working_counter;
+    }
+#else
+    for (uint32_t i = 0; i < master->slave_count; i++) {
+        slave = &master->slaves[i];
 
-        if (pdo_datagram->slave->config && pdo_datagram->slave->config->pdo_callback) {
-            pdo_datagram->slave->config->pdo_callback(pdo_datagram->slave,
-                                                      (uint8_t *)&master->pdo_buffer[EC_NETDEV_MAIN][pdo_datagram->slave->logical_start_address],
-                                                      (uint8_t *)&master->pdo_buffer[EC_NETDEV_MAIN][pdo_datagram->slave->logical_start_address +
-                                                                                                     pdo_datagram->slave->odata_size]);
+        if (slave->pdo_datagram.state == EC_DATAGRAM_RECEIVED) {
+            if (slave->config && slave->config->pdo_callback) {
+                slave->config->pdo_callback(slave,
+                                            (uint8_t *)&master->pdo_buffer[EC_NETDEV_MAIN][slave->logical_start_address],
+                                            (uint8_t *)&master->pdo_buffer[EC_NETDEV_MAIN][slave->logical_start_address + slave->odata_size]);
+            }
+            master->actual_working_counter += slave->pdo_datagram.working_counter;
+            slave->actual_working_counter = slave->pdo_datagram.working_counter;
         }
     }
+#endif
 
     if (master->dc_ref_clock) {
         ec_datagram_zero(&master->dc_all_sync_datagram);
         ec_master_queue_datagram(master, &master->dc_all_sync_datagram);
     }
 
-    ec_dlist_for_each_entry_safe(pdo_datagram, n, &master->pdo_datagram_queue, queue)
-    {
-        ec_master_queue_datagram(master, &pdo_datagram->datagrams[EC_NETDEV_MAIN]);
+#ifndef CONFIG_EC_PDO_MULTI_DOMAIN
+    ec_master_queue_datagram(master, &master->pdo_datagram);
+#else
+    for (uint32_t i = 0; i < master->slave_count; i++) {
+        slave = &master->slaves[i];
+        ec_master_queue_datagram(master, &slave->pdo_datagram);
     }
-
+#endif
     ec_master_send(master);
 
     period_ns = start_time - master->last_start_time;