# HG changeset patch # User Florian Pose # Date 1241100767 0 # Node ID c1322a8793c0d0991da5e0ff9a7248ae3d0dbb4d # Parent cb02dbe4076f1eacf195e8c081653830b34ac582 Transition delay calculation. TBC... diff -r cb02dbe4076f -r c1322a8793c0 TODO --- a/TODO Wed Apr 29 14:03:01 2009 +0000 +++ b/TODO Thu Apr 30 14:12:47 2009 +0000 @@ -11,7 +11,6 @@ Version 1.5.0: * Distributed clocks: - - Delay calculation. - Use common application time offset when setting start times. - Check 32/64 bit operations. - Set system time offset only when application time available. diff -r cb02dbe4076f -r c1322a8793c0 master/cdev.c --- a/master/cdev.c Wed Apr 29 14:03:01 2009 +0000 +++ b/master/cdev.c Thu Apr 30 14:12:47 2009 +0000 @@ -257,21 +257,23 @@ data.general_flags = slave->sii.general_flags; data.current_on_ebus = slave->sii.current_on_ebus; for (i = 0; i < EC_MAX_PORTS; i++) { - data.port_descs[i] = slave->base_ports[i]; - data.ports[i].dl_link = slave->ports[i].dl_link; - data.ports[i].dl_loop = slave->ports[i].dl_loop; - data.ports[i].dl_signal = slave->ports[i].dl_signal; - data.dc_receive_times[i] = slave->dc_receive_times[i]; - if (slave->next_slave[i]) { - data.next_slave[i] = slave->next_slave[i]->ring_position; + data.ports[i].desc = slave->ports[i].desc; + data.ports[i].link.link_up = slave->ports[i].link.link_up; + data.ports[i].link.loop_closed = slave->ports[i].link.loop_closed; + data.ports[i].link.signal_detected = slave->ports[i].link.signal_detected; + data.ports[i].receive_time = slave->ports[i].receive_time; + if (slave->ports[i].next_slave) { + data.ports[i].next_slave = slave->ports[i].next_slave->ring_position; } else { - data.next_slave[i] = 0xffff; + data.ports[i].next_slave = 0xffff; } + data.ports[i].delay_to_next_dc = slave->ports[i].delay_to_next_dc; } data.fmmu_bit = slave->base_fmmu_bit_operation; data.dc_supported = slave->base_dc_supported; data.dc_range = slave->base_dc_range; data.has_dc_system_time = slave->has_dc_system_time; + data.transition_delay = slave->transition_delay; data.al_state = slave->current_state; data.error_flag = slave->error_flag; diff -r cb02dbe4076f -r c1322a8793c0 master/fsm_master.c --- a/master/fsm_master.c Wed Apr 29 14:03:01 2009 +0000 +++ b/master/fsm_master.c Thu Apr 30 14:12:47 2009 +0000 @@ -865,11 +865,7 @@ master->scan_busy = 0; wake_up_interruptible(&master->scan_queue); - // find DC reference clock - ec_master_find_dc_ref_clock(master); - - // calculate bus topology - ec_master_calc_topology(master); + ec_master_calc_dc(master); // Attach slave configurations ec_master_attach_slave_configs(master); diff -r cb02dbe4076f -r c1322a8793c0 master/fsm_slave_scan.c --- a/master/fsm_slave_scan.c Wed Apr 29 14:03:01 2009 +0000 +++ b/master/fsm_slave_scan.c Thu Apr 30 14:12:47 2009 +0000 @@ -311,7 +311,7 @@ octet = EC_READ_U8(datagram->data + 7); for (i = 0; i < EC_MAX_PORTS; i++) { - slave->base_ports[i] = (octet >> (2 * i)) & 0x03; + slave->ports[i].desc = (octet >> (2 * i)) & 0x03; } octet = EC_READ_U8(datagram->data + 8); @@ -417,7 +417,7 @@ } for (i = 0; i < EC_MAX_PORTS; i++) { - slave->dc_receive_times[i] = EC_READ_U32(datagram->data + 4 * i); + slave->ports[i].receive_time = EC_READ_U32(datagram->data + 4 * i); } ec_fsm_slave_scan_enter_datalink(fsm); @@ -478,9 +478,9 @@ dl_status = EC_READ_U16(datagram->data); for (i = 0; i < EC_MAX_PORTS; i++) { - slave->ports[i].dl_link = dl_status & (1 << (4 + i)) ? 1 : 0; - slave->ports[i].dl_loop = dl_status & (1 << (8 + i * 2)) ? 1 : 0; - slave->ports[i].dl_signal = dl_status & (1 << (9 + i * 2)) ? 1 : 0; + slave->ports[i].link.link_up = dl_status & (1 << (4 + i)) ? 1 : 0; + slave->ports[i].link.loop_closed = dl_status & (1 << (8 + i * 2)) ? 1 : 0; + slave->ports[i].link.signal_detected = dl_status & (1 << (9 + i * 2)) ? 1 : 0; } // Start fetching SII size diff -r cb02dbe4076f -r c1322a8793c0 master/globals.h --- a/master/globals.h Wed Apr 29 14:03:01 2009 +0000 +++ b/master/globals.h Thu Apr 30 14:12:47 2009 +0000 @@ -169,10 +169,10 @@ /** EtherCAT slave port information. */ typedef struct { - uint8_t dl_link; /**< Link detected. */ - uint8_t dl_loop; /**< Loop closed. */ - uint8_t dl_signal; /**< Detected signal on RX port. */ -} ec_slave_port_t; + uint8_t link_up; /**< Link detected. */ + uint8_t loop_closed; /**< Loop closed. */ + uint8_t signal_detected; /**< Detected signal on RX port. */ +} ec_slave_port_link_t; /** EtherCAT slave distributed clocks range. */ diff -r cb02dbe4076f -r c1322a8793c0 master/ioctl.h --- a/master/ioctl.h Wed Apr 29 14:03:01 2009 +0000 +++ b/master/ioctl.h Thu Apr 30 14:12:47 2009 +0000 @@ -165,14 +165,18 @@ ec_sii_coe_details_t coe_details; ec_sii_general_flags_t general_flags; int16_t current_on_ebus; - ec_slave_port_desc_t port_descs[EC_MAX_PORTS]; - ec_slave_port_t ports[EC_MAX_PORTS]; - uint16_t next_slave[EC_MAX_PORTS]; + struct { + ec_slave_port_desc_t desc; + ec_slave_port_link_t link; + uint32_t receive_time; + uint16_t next_slave; + uint32_t delay_to_next_dc; + } ports[EC_MAX_PORTS]; uint8_t fmmu_bit; uint8_t dc_supported; ec_slave_dc_range_t dc_range; uint8_t has_dc_system_time; - uint32_t dc_receive_times[EC_MAX_PORTS]; + uint32_t transition_delay; uint8_t al_state; uint8_t error_flag; uint8_t sync_count; diff -r cb02dbe4076f -r c1322a8793c0 master/master.c --- a/master/master.c Wed Apr 29 14:03:01 2009 +0000 +++ b/master/master.c Thu Apr 30 14:12:47 2009 +0000 @@ -77,6 +77,7 @@ #ifdef EC_EOE void ec_master_eoe_run(unsigned long); #endif +void ec_master_find_dc_ref_clock(ec_master_t *); /*****************************************************************************/ @@ -342,6 +343,8 @@ { ec_slave_t *slave; + master->dc_ref_clock = NULL; + for (slave = master->slaves; slave < master->slaves + master->slave_count; slave++) { @@ -1357,20 +1360,22 @@ ec_master_t *master /**< EtherCAT master. */ ) { - ec_slave_t *slave; - uint16_t ref_clock_addr = 0xffff; + ec_slave_t *slave, *ref = NULL; for (slave = master->slaves; slave < master->slaves + master->slave_count; slave++) { - if (slave->base_dc_supported && slave->has_dc_system_time) { - ref_clock_addr = slave->station_address; - break; - } - } - - // This call always succeeds, because the datagram has been pre-allocated. - ec_datagram_frmw(&master->sync_datagram, ref_clock_addr, 0x0910, 4); + if (slave->base_dc_supported && slave->has_dc_system_time) { + ref = slave; + break; + } + } + + master->dc_ref_clock = ref; + + // This call always succeeds, because the datagram has been pre-allocated. + ec_datagram_frmw(&master->sync_datagram, + ref ? ref->station_address : 0xffff, 0x0910, 4); } /*****************************************************************************/ @@ -1387,13 +1392,13 @@ unsigned int i; int ret; - slave->next_slave[0] = port0_slave; + slave->ports[0].next_slave = port0_slave; for (i = 1; i < EC_MAX_PORTS; i++) { - if (!slave->ports[i].dl_loop) { + if (!slave->ports[i].link.loop_closed) { *slave_position = *slave_position + 1; if (*slave_position < master->slave_count) { - slave->next_slave[i] = master->slaves + *slave_position; + slave->ports[i].next_slave = master->slaves + *slave_position; ret = ec_master_calc_topology_rec(master, slave, slave_position); if (ret) @@ -1424,6 +1429,45 @@ EC_ERR("Failed to calculate bus topology.\n"); } +/*****************************************************************************/ + +/** Calculates the bus transition delays. + */ +void ec_master_calc_transition_delays( + ec_master_t *master /**< EtherCAT master. */ + ) +{ + ec_slave_t *slave; + + for (slave = master->slaves; + slave < master->slaves + master->slave_count; + slave++) { + ec_slave_calc_port_delays(slave); + } + + if (master->dc_ref_clock) { + uint32_t delay = 0; + ec_slave_calc_transition_delays_rec(master->dc_ref_clock, &delay); + } +} + +/*****************************************************************************/ + +/** Distributed-clocks calculations. + */ +void ec_master_calc_dc( + ec_master_t *master /**< EtherCAT master. */ + ) +{ + // find DC reference clock + ec_master_find_dc_ref_clock(master); + + // calculate bus topology + ec_master_calc_topology(master); + + ec_master_calc_transition_delays(master); +} + /****************************************************************************** * Application interface *****************************************************************************/ diff -r cb02dbe4076f -r c1322a8793c0 master/master.h --- a/master/master.h Wed Apr 29 14:03:01 2009 +0000 +++ b/master/master.h Thu Apr 30 14:12:47 2009 +0000 @@ -122,6 +122,7 @@ reference clock to the master clock. */ ec_datagram_t sync_datagram; /**< Datagram used for DC drift compensation. */ + ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */ unsigned int scan_busy; /**< Current scan state. */ unsigned int allow_scan; /**< \a True, if slave scanning is allowed. */ @@ -233,9 +234,8 @@ ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *, uint16_t, uint16_t, uint32_t, uint32_t); -void ec_master_find_dc_ref_clock(ec_master_t *); -void ec_master_calc_topology(ec_master_t *); - -/*****************************************************************************/ - -#endif +void ec_master_calc_dc(ec_master_t *); + +/*****************************************************************************/ + +#endif diff -r cb02dbe4076f -r c1322a8793c0 master/slave.c --- a/master/slave.c Wed Apr 29 14:03:01 2009 +0000 +++ b/master/slave.c Thu Apr 30 14:12:47 2009 +0000 @@ -89,22 +89,24 @@ slave->base_sync_count = 0; for (i = 0; i < EC_MAX_PORTS; i++) { - slave->base_ports[i] = EC_PORT_NOT_IMPLEMENTED; - - slave->ports[i].dl_link = 0; - slave->ports[i].dl_loop = 0; - slave->ports[i].dl_signal = 0; + slave->ports[i].desc = EC_PORT_NOT_IMPLEMENTED; + + slave->ports[i].link.link_up = 0; + slave->ports[i].link.loop_closed = 0; + slave->ports[i].link.signal_detected = 0; slave->sii.physical_layer[i] = 0xFF; - slave->dc_receive_times[i] = 0U; - - slave->next_slave[i] = NULL; + slave->ports[i].receive_time = 0U; + + slave->ports[i].next_slave = NULL; + slave->ports[i].delay_to_next_dc = 0U; } slave->base_fmmu_bit_operation = 0; slave->base_dc_supported = 0; slave->base_dc_range = EC_DC_32; slave->has_dc_system_time = 0; + slave->transition_delay = 0U; slave->sii_words = NULL; slave->sii_nwords = 0; @@ -740,3 +742,126 @@ } /*****************************************************************************/ + +/** Calculates the sum of round-trip-times of connected ports 1-3. + */ +uint32_t ec_slave_calc_rtt_sum( + ec_slave_t *slave /**< EtherCAT slave. */ + ) +{ + uint32_t rtt_sum = 0, rtt; + unsigned int i; + + for (i = 1; i < EC_MAX_PORTS; i++) { + if (slave->ports[i].next_slave) { + rtt = slave->ports[i].receive_time - slave->ports[i - 1].receive_time; + rtt_sum += rtt; + } + } + + return rtt_sum; +} + +/*****************************************************************************/ + +/** Finds the next slave supporting DC delay measurement. + */ +ec_slave_t *ec_slave_find_next_dc_slave( + ec_slave_t *slave /**< EtherCAT slave. */ + ) +{ + ec_slave_t *dc_slave = NULL; + + if (slave->base_dc_supported) { + dc_slave = slave; + } else { + unsigned int i; + + for (i = 1; i < EC_MAX_PORTS; i++) { + ec_slave_t *next = slave->ports[i].next_slave; + if (next) { + dc_slave = ec_slave_find_next_dc_slave(next); + if (dc_slave) + break; + } + } + } + + return dc_slave; +} + +/*****************************************************************************/ + +/** Calculates the port transition delays. + */ +void ec_slave_calc_port_delays( + ec_slave_t *slave /**< EtherCAT slave. */ + ) +{ + unsigned int i; + ec_slave_t *next, *next_dc; + uint32_t rtt, next_rtt_sum; + + if (!slave->base_dc_supported) + return; + + for (i = 1; i < EC_MAX_PORTS; i++) { + next = slave->ports[i].next_slave; + if (!next) + continue; + next_dc = ec_slave_find_next_dc_slave(next); + if (!next_dc) + continue; + + rtt = slave->ports[i].receive_time - slave->ports[i - 1].receive_time; + next_rtt_sum = ec_slave_calc_rtt_sum(next_dc); + + slave->ports[i].delay_to_next_dc = (rtt - next_rtt_sum) / 2; // FIXME + next_dc->ports[0].delay_to_next_dc = (rtt - next_rtt_sum) / 2; + +#if 0 + EC_DBG("delay %u:%u rtt=%u next_rtt_sum=%u delay=%u\n", + slave->ring_position, i, rtt, next_rtt_sum, + slave->ports[i].delay_to_next_dc); +#endif + } +} + +/*****************************************************************************/ + +/** Calculates the bus topology; recursion function. + */ +void ec_slave_calc_transition_delays_rec( + ec_slave_t *slave, /**< Current slave. */ + uint32_t *delay /**< Sum of delays. */ + ) +{ + unsigned int i; + ec_slave_t *next, *next_dc; + +#if 0 + EC_DBG("%u: %u\n", slave->ring_position, *delay); +#endif + + slave->transition_delay = *delay; + + for (i = 1; i < EC_MAX_PORTS; i++) { + ec_slave_port_t *port = &slave->ports[i]; + next = port->next_slave; + if (!next) + continue; + next_dc = ec_slave_find_next_dc_slave(next); + if (!next_dc) + continue; + + *delay = *delay + port->delay_to_next_dc; +#if 0 + EC_DBG("%u:%u %u\n", slave->ring_position, i, *delay); +#endif + ec_slave_calc_transition_delays_rec(next_dc, delay); + } + + *delay = *delay + slave->ports[0].delay_to_next_dc; +} + +/*****************************************************************************/ diff -r cb02dbe4076f -r c1322a8793c0 master/slave.h --- a/master/slave.h Wed Apr 29 14:03:01 2009 +0000 +++ b/master/slave.h Thu Apr 30 14:12:47 2009 +0000 @@ -48,6 +48,20 @@ /*****************************************************************************/ +/** Slave port. + */ +typedef struct { + ec_slave_port_desc_t desc; /**< Port descriptors. */ + ec_slave_port_link_t link; /**< Port link status. */ + ec_slave_t *next_slave; /**< Connected slaves. */ + uint32_t receive_time; /**< Port receive times for delay + measurement. */ + uint32_t delay_to_next_dc; /**< Delay to next slave with DC support behind + this port [ns]. */ +} ec_slave_port_t; + +/*****************************************************************************/ + /** Slave information interface data. */ typedef struct { @@ -102,6 +116,8 @@ uint16_t ring_position; /**< Ring position. */ uint16_t station_address; /**< Configured station address. */ + ec_slave_port_t ports[EC_MAX_PORTS]; /**< Ports. */ + // configuration ec_slave_config_t *config; /**< Current configuration. */ ec_slave_state_t requested_state; /**< Requested application state. */ @@ -119,19 +135,14 @@ uint16_t base_build; /**< Build number. */ uint8_t base_fmmu_count; /**< Number of supported FMMUs. */ uint8_t base_sync_count; /**< Number of supported sync managers. */ - ec_slave_port_desc_t base_ports[EC_MAX_PORTS]; /**< Port descriptors. */ uint8_t base_fmmu_bit_operation; /**< FMMU bit operation is supported. */ uint8_t base_dc_supported; /**< Distributed clocks are supported. */ ec_slave_dc_range_t base_dc_range; /**< DC range. */ uint8_t has_dc_system_time; /**< The slave supports the DC system time register. Otherwise it can only be used for delay measurement. */ - uint32_t dc_receive_times[EC_MAX_PORTS]; /**< Port receive times for delay - measurement. */ - - // data link status - ec_slave_port_t ports[EC_MAX_PORTS]; /**< Port link status. */ - ec_slave_t *next_slave[EC_MAX_PORTS]; /**< Connected slaves. */ + uint32_t transition_delay; /**< DC transition delay (from reference + clock). */ // SII uint16_t *sii_words; /**< Complete SII image. */ @@ -175,6 +186,9 @@ const ec_pdo_t *ec_slave_find_pdo(const ec_slave_t *, uint16_t); void ec_slave_attach_pdo_names(ec_slave_t *); +void ec_slave_calc_port_delays(ec_slave_t *); +void ec_slave_calc_transition_delays_rec(ec_slave_t *, uint32_t *); + /*****************************************************************************/ #endif diff -r cb02dbe4076f -r c1322a8793c0 tool/CommandGraph.cpp --- a/tool/CommandGraph.cpp Wed Apr 29 14:03:01 2009 +0000 +++ b/tool/CommandGraph.cpp Thu Apr 30 14:12:47 2009 +0000 @@ -72,7 +72,6 @@ SlaveVector slaves; ec_ioctl_slave_t slave; SlaveVector::const_iterator si; - string font("fontname=\"Helvetica\""); map portMedia; map::const_iterator mi; map mediaWeights; @@ -102,51 +101,84 @@ << endl << "strict graph bus {" << endl << " rankdir=\"LR\"" << endl + << " ranksep=0.8" << endl + << " nodesep=0.8" << endl + << " node [fontname=\"Helvetica\"]" << endl + << " edge [fontname=\"Helvetica\",fontsize=\"10\"]" << endl << endl - << " master [" << font << ",label=\"EtherCAT\\nMaster\"]" << endl; + << " master [label=\"EtherCAT\\nMaster\"]" << endl; if (slaves.size()) { - cout << " master -- slave0 [" << font; + cout << " master -- slave0"; + mi = portMedia.find(slaves.front().ports[0].desc); + if (mi != portMedia.end()) + cout << "[label=\"" << mi->second << "\"]"; - mi = portMedia.find(slaves.front().port_descs[0]); - if (mi != portMedia.end()) - cout << ",label=\"" << mi->second << "\""; - - cout << "]" << endl; + cout << endl; } cout << endl; for (si = slaves.begin(); si != slaves.end(); si++) { - cout << " slave" << si->position << " [" << font << - ",shape=\"box\",label=\"" << si->position; + cout << " slave" << si->position << " [shape=\"box\"" + << ",label=\"" << si->position; if (string(si->order).size()) cout << "\\n" << si->order; + if (si->dc_supported) { + cout << "\\nDC: "; + if (si->has_dc_system_time) { + switch (si->dc_range) { + case EC_DC_32: + cout << "32 bit"; + break; + case EC_DC_64: + cout << "64 bit"; + break; + default: + break; + } + } else { + cout << "Delay meas."; + } + cout << "\\nDelay: " << si->transition_delay << " ns"; + } cout << "\"]" << endl; for (i = 1; i < EC_MAX_PORTS; i++) { - if (si->next_slave[i] == 0xffff) + uint16_t next_pos = si->ports[i].next_slave; + ec_ioctl_slave_t *next = NULL; + + if (next_pos == 0xffff) continue; + if (next_pos < slaves.size()) { + next = &slaves[next_pos]; + } else { + cerr << "Invalid next slave pointer." << endl; + } + cout << " slave" << si->position << " -- " - << "slave" << si->next_slave[i] << " [" << font << "," - << "taillabel=\"" << i << "\""; + << "slave" << next_pos << " [taillabel=\"" << i; - mi = portMedia.find(si->port_descs[i]); - if (mi == portMedia.end()) { + if (si->dc_supported) { + cout << " [" << si->ports[i].delay_to_next_dc << "]"; + } + cout << "\",headlabel=\"0"; + + if (next && next->dc_supported) { + cout << " [" << next->ports[0].delay_to_next_dc << "]"; + } + cout << "\""; + + mi = portMedia.find(si->ports[i].desc); + if (mi == portMedia.end() && next) { /* Try medium of next-hop slave. */ - unsigned int pos = si->next_slave[i]; - if (pos < slaves.size()) { - ec_ioctl_slave_t *next = &slaves[pos]; - mi = portMedia.find(next->port_descs[0]); - } else { - cerr << "Invalid next slave pointer." << endl; - } + mi = portMedia.find(next->ports[0].desc); } if (mi != portMedia.end()) cout << ",label=\"" << mi->second << "\""; - wi = mediaWeights.find(si->port_descs[i]); + wi = mediaWeights.find(si->ports[i].desc); if (wi != mediaWeights.end()) cout << ",weight=\"" << wi->second << "\""; diff -r cb02dbe4076f -r c1322a8793c0 tool/CommandSlaves.cpp --- a/tool/CommandSlaves.cpp Wed Apr 29 14:03:01 2009 +0000 +++ b/tool/CommandSlaves.cpp Thu Apr 30 14:12:47 2009 +0000 @@ -262,18 +262,20 @@ } else { cout << "yes, delay measurement only" << endl; } + cout << " DC transition delay: " + << si->transition_delay << " ns" << endl; } else { cout << "no" << endl; } cout << "Port Type Link Loop Signal NextSlave"; if (si->dc_supported) - cout << " RxTime Diff"; + cout << " RxTime [ns] Diff [ns] NextDc [ns]"; cout << endl; for (i = 0; i < EC_MAX_PORTS; i++) { cout << " " << i << " " << setfill(' ') << left << setw(4); - switch (si->port_descs[i]) { + switch (si->ports[i].desc) { case EC_PORT_NOT_IMPLEMENTED: cout << "N/A"; break; @@ -291,29 +293,35 @@ } cout << " " << setw(4) - << (si->ports[i].dl_link ? "up" : "down") + << (si->ports[i].link.link_up ? "up" : "down") << " " << setw(6) - << (si->ports[i].dl_loop ? "closed" : "open") + << (si->ports[i].link.loop_closed ? "closed" : "open") << " " << setw(6) - << (si->ports[i].dl_signal ? "yes" : "no") + << (si->ports[i].link.signal_detected ? "yes" : "no") << " " << setw(9) << right; - if (si->next_slave[i] != 0xffff) { - cout << dec << si->next_slave[i]; + if (si->ports[i].next_slave != 0xffff) { + cout << dec << si->ports[i].next_slave; } else { cout << "-"; } if (si->dc_supported) { - cout << " " << setw(10) << right; - if (si->ports[i].dl_signal) { - cout << dec << si->dc_receive_times[i]; + cout << " " << setw(11) << right; + if (!si->ports[i].link.loop_closed) { + cout << dec << si->ports[i].receive_time; } else { cout << "-"; } cout << " " << setw(10); - if (si->ports[i].dl_signal) { - cout << si->dc_receive_times[i] - si->dc_receive_times[0]; + if (!si->ports[i].link.loop_closed) { + cout << si->ports[i].receive_time - si->ports[0].receive_time; + } else { + cout << "-"; + } + cout << " " << setw(10); + if (!si->ports[i].link.loop_closed) { + cout << si->ports[i].delay_to_next_dc; } else { cout << "-"; }