<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    Hi, <br>
    <br>
    I didn't check the codes. But is it OK to have the first device in
    the bus a EK1100? <br>
    I can't find it now, but a message in this list was telling me
    EK1100 does not support DC fully.<br>
    The fist node on the bus should be a drive or some other device
    which can support DC fully.<br>
    <br>
    Best regards,<br>
    Oguz.<br>
    <br>
    <div class="moz-cite-prefix">22.2.2016 11:52 tarihinde Richard
      Hacker yazdı:<br>
    </div>
    <blockquote cite="mid:56CADA50.8070601@igh.de" type="cite">I do not
      have the patience to look into your code in detail to find out
      what you're doing wrong, but here is an excerpt of my code I use
      in etherlab Simulink Coder (ecrt_support.c):
      <br>
      <br>
      void
      <br>
      ecs_send()
      <br>
      {
      <br>
          //...
      <br>
      <br>
          list_for_each(master, &ecat_data.master_list, list) {
      <br>
              list_for_each(domain, &master->domain_list, list) {
      <br>
                  // ...
      <br>
      <br>
                  ecrt_domain_queue(domain->handle);
      <br>
              }
      <br>
      <br>
              if (/* send frames */) {
      <br>
                  struct timespec tp;
      <br>
      <br>
                  clock_gettime(CLOCK_MONOTONIC, &tp);
      <br>
                  ecrt_master_application_time(master->handle,
      <br>
                          EC_TIMESPEC2NANO(tp));
      <br>
      <br>
                  if (/* sync_clocks */)) {
      <br>
                     
      ecrt_master_sync_reference_clock(master->handle);
      <br>
                      //...
      <br>
                  }
      <br>
      <br>
                  ecrt_master_sync_slave_clocks(master->handle);
      <br>
                  ecrt_master_send(master->handle);
      <br>
              }
      <br>
          }
      <br>
      }
      <br>
      <br>
      void
      <br>
      ecs_receive()
      <br>
      {
      <br>
          //...
      <br>
      <br>
          list_for_each(master, &ecat_data.master_list, list) {
      <br>
      <br>
              if (/* receive frames */) {
      <br>
                  ecrt_master_receive(master->handle);
      <br>
              }
      <br>
      <br>
              list_for_each(domain, &master->domain_list, list) {
      <br>
      <br>
                  ecrt_domain_process(domain->handle);
      <br>
                  ecrt_domain_state(domain->handle,
      &domain->state);
      <br>
      <br>
              }
      <br>
          }
      <br>
      }
      <br>
      <br>
      void
      <br>
      calculate()
      <br>
      {
      <br>
          while (forever) {
      <br>
              ecs_receive();
      <br>
              // do calculations
      <br>
              ecs_send();
      <br>
              sleep();
      <br>
          }
      <br>
      }
      <br>
      <br>
      Some of this is pseudo code, but I trust in your programming
      capabilities to be able to adapt this to your code ;)
      <br>
      <br>
      It is very important to call clock_gettime() and
      ecrt_master_application_time() as close to ecrt_master_send() as
      possible.
      <br>
      <br>
      As you can see, it is not necessary to call
      ecrt_master_sync_reference_clock() with every ecrt_master_send().
      In fact, ~100Hz of syncing should be enough, provided that your
      call to clock_gettime() is accurate. On the other hand, if
      clock_gettime() is inaccurate, you're in trouble when using DC
      anyway!
      <br>
      <br>
      - Richard
      <br>
      <br>
      Am 2016-02-22 um 04:23 schrieb Thomas Bitsky Jr:
      <br>
      <blockquote type="cite">Ok, after following all your advice, plus
        the clock adjustment from
        <br>
        Mattieu, I’m pretty close. I enable the DC on the drive, get
        everything
        <br>
        into op, the domains all come up and it would appear that the
        clocks are
        <br>
        syncing. Except for one thing:
        <br>
        <br>
        [10248.633619] EtherCAT 0: Domain 0: Working counter changed to
        1/17.
        <br>
        [10249.535776] EtherCAT WARNING 0: 3989 datagrams UNMATCHED!
        <br>
        [10249.539861] EtherCAT WARNING: Datagram f3bf2d0c
        (domain0-0-main) was
        <br>
        SKIPPED 1 time.
        <br>
        [10249.539887] EtherCAT WARNING: Datagram f3bf2a8c
        (domain2-120-main)
        <br>
        was SKIPPED 1 time.
        <br>
        [10249.539918] EtherCAT WARNING: Datagram f3bf2e8c
        (domain1-114-main)
        <br>
        was SKIPPED 1 time.
        <br>
        [10249.635934] EtherCAT 0: Domain 0: 9 working counter changes -
        now 17/17.
        <br>
        [10249.919163] EtherCAT 0: Domain 2: Working counter changed to
        1/1.
        <br>
        [10250.018245] EtherCAT 0: Domain 1: Working counter changed to
        1/1.
        <br>
        [10250.040259] EtherCAT 0: Slave states on main device: OP.
        <br>
        [10250.536654] EtherCAT WARNING 0: 4001 datagrams UNMATCHED!
        <br>
        [10251.537469] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
        <br>
        [10252.538282] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
        <br>
        [10252.538296] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
        <br>
        [10253.539097] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
        <br>
        [10254.539909] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
        <br>
        [10255.540723] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
        <br>
        [10256.541537] EtherCAT WARNING 0: 4000 datagrams
        UNMATCHED!<— This
        <br>
        continues indefinitely
        <br>
        <br>
        <br>
        Everything else seems okay:
        <br>
        <br>
        user@core:~/dist$ ethercat slaves
        <br>
        0  0:0  OP  +  EK1100 EtherCAT-Koppler (2A E-Bus)
        <br>
        1  0:1  OP  +  EL1104 4K. Dig. Eingang 24V, 3ms,
        Sensorversorgung
        <br>
        2  0:2  OP  +  EL1104 4K. Dig. Eingang 24V, 3ms,
        Sensorversorgung
        <br>
        3  0:3  OP  +  EL5101 1K. Inc. Encoder 5V
        <br>
        4  0:4  OP  +  EL7041 1K. Schrittmotor-Endstufe (50V, 5A)
        <br>
        5  0:5  OP  +  EL7041 1K. Schrittmotor-Endstufe (50V, 5A)
        <br>
        6  0:6  OP  +  EL2004 4K. Dig. Ausgang 24V, 0.5A
        <br>
        7  0:7  OP  +  EL2004 4K. Dig. Ausgang 24V, 0.5A
        <br>
        8  0:8  OP  +  EL4001 1K. Ana. Ausgang 0-10V, 12bit
        <br>
        9  1:0  OP  +  0x00000539:0x02200001
        <br>
        user@core:~/dist$ ethercat master
        <br>
        Master0
        <br>
           Phase: Operation
        <br>
           Active: yes
        <br>
           Slaves: 10
        <br>
           Ethernet devices:
        <br>
             Main: 00:30:18:c8:d4:92 (attached)
        <br>
               Link: UP
        <br>
               Tx frames:   5204542
        <br>
               Tx bytes:    733318966
        <br>
               Rx frames:   5204539
        <br>
               Rx bytes:    733318636
        <br>
               Tx errors:   0
        <br>
               Tx frame rate [1/s]:   4000   3944   2090
        <br>
               Tx rate [KByte/s]:    823.7  811.9  412.9
        <br>
               Rx frame rate [1/s]:   4000   3944   2090
        <br>
               Rx rate [KByte/s]:    823.7  811.9  412.9
        <br>
             Common:
        <br>
               Tx frames:   5204542
        <br>
               Tx bytes:    733318966
        <br>
               Rx frames:   5204539
        <br>
               Rx bytes:    733318636
        <br>
               Lost frames: 3
        <br>
               Tx frame rate [1/s]:   4000   3944   2090
        <br>
               Tx rate [KByte/s]:    823.7  811.9  412.9
        <br>
               Rx frame rate [1/s]:   4000   3944   2090
        <br>
               Rx rate [KByte/s]:    823.7  811.9  412.9
        <br>
               Loss rate [1/s]:          0      0      0
        <br>
               Frame loss [%]:         0.0    0.0    0.0
        <br>
           Distributed clocks:
        <br>
             Reference clock: Slave 0
        <br>
             Application time: 509424243322706771
        <br>
                               2016-02-22 02:44:03.322706771
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        I must have something out of sync. Is there something more I’m
        supposed
        <br>
        to do to adjust the clock? I can make the number of dropped
        packets
        <br>
        worse by simplifying the time adjustment, but I can’t seem to
        get it any
        <br>
        better. I think I’m not understanding something about the clock
        <br>
        adjustment. Can you see what I’m doing wrong?
        <br>
        <br>
        Thanks!
        <br>
        <br>
        My cyclic task:
        <br>
        <br>
        <br>
        static void
        <br>
        sync_distributed_clocks(void)
        <br>
        {
        <br>
             uint32_t ref_time = 0;
        <br>
             uint64_t prev_app_time = dc_time_ns;
        <br>
        <br>
             dc_time_ns = system_time_ns();
        <br>
        <br>
             // set master time in nano-seconds
        <br>
             ecrt_master_application_time(master_, dc_time_ns);
        <br>
        <br>
             // get reference clock time to synchronize master cycle
        <br>
             ecrt_master_reference_clock_time(master_, &ref_time);
        <br>
             dc_diff_ns = (uint32_t) prev_app_time - ref_time;
        <br>
        <br>
        <br>
             // call to sync slaves to ref slave
        <br>
             ecrt_master_sync_slave_clocks(master_);
        <br>
        }
        <br>
        <br>
        static unsigned int cycle_ns = 1000000;  // 1 millisecond
        <br>
        <br>
        void update_master_clock(void)
        <br>
        {
        <br>
             // calc drift (via un-normalised time diff)
        <br>
             int32_t delta = dc_diff_ns - prev_dc_diff_ns;
        <br>
             prev_dc_diff_ns = dc_diff_ns;
        <br>
        <br>
             // normalise the time diff
        <br>
             dc_diff_ns =
        <br>
                 ((dc_diff_ns + (cycle_ns / 2)) % cycle_ns) - (cycle_ns
        / 2);
        <br>
        <br>
             // only update if primary master
        <br>
             if (dc_started)
        <br>
        {
        <br>
        <br>
                 // add to totals
        <br>
                 dc_diff_total_ns += dc_diff_ns;
        <br>
                 dc_delta_total_ns += delta;
        <br>
                 dc_filter_idx++;
        <br>
        <br>
                 if (dc_filter_idx >= DC_FILTER_CNT)
        <br>
        {
        <br>
                     // add rounded delta average
        <br>
                     dc_adjust_ns +=
        <br>
                         ((dc_delta_total_ns + (DC_FILTER_CNT / 2)) /
        <br>
        DC_FILTER_CNT);
        <br>
        <br>
                     // and add adjustment for general diff (to pull in
        drift)
        <br>
                     dc_adjust_ns += sign(dc_diff_total_ns /
        DC_FILTER_CNT);
        <br>
        <br>
                     // limit crazy numbers (0.1% of std cycle time)
        <br>
                     if (dc_adjust_ns < -1000) {
        <br>
                         dc_adjust_ns = -1000;
        <br>
                     }
        <br>
                     if (dc_adjust_ns > 1000) {
        <br>
                         dc_adjust_ns =  1000;
        <br>
                     }
        <br>
        <br>
                     // reset
        <br>
                     dc_diff_total_ns = 0LL;
        <br>
                     dc_delta_total_ns = 0LL;
        <br>
                     dc_filter_idx = 0;
        <br>
                 }
        <br>
        <br>
                 // add cycles adjustment to time base (including a spot
        adjustment)
        <br>
                 system_time_base += dc_adjust_ns + sign(dc_diff_ns);
        <br>
             }
        <br>
             else
        <br>
        {
        <br>
                 dc_started = (dc_diff_ns != 0);
        <br>
        <br>
                 if (dc_started)
        <br>
        {
        <br>
                     // output first diff
        <br>
                     PRINT("First master diff: %d.\n", dc_diff_ns);
        <br>
        <br>
                     // record the time of this initial cycle
        <br>
                     dc_start_time_ns = dc_time_ns;
        <br>
                 }
        <br>
             }
        <br>
        <br>
        }
        <br>
        <br>
        <br>
        int
        <br>
        <br>
        ecatMain_process(void* lp)
        <br>
        <br>
        {
        <br>
        <br>
        <br>
        sync_distributed_clocks();
        <br>
        <br>
        update_master_clock();
        <br>
        <br>
        <br>
        ecrt_master_receive(master_);
        <br>
        <br>
        ecrt_domain_process(lrwDomainMgr_.domain);
        <br>
        <br>
        ecrt_domain_process(noLrwWriteDomainMgr_.domain);
        <br>
        <br>
        ecrt_domain_process(noLrwReadDomainMgr_.domain);
        <br>
        <br>
        … // handle my business
        <br>
        <br>
        <br>
        // send process data
        <br>
        <br>
        ecrt_domain_queue(lrwDomainMgr_.domain);
        <br>
        <br>
        ecrt_domain_queue(noLrwWriteDomainMgr_.domain);
        <br>
        <br>
        ecrt_domain_queue(noLrwReadDomainMgr_.domain);
        <br>
        <br>
        // send EtherCAT data
        <br>
        <br>
        ecrt_master_send(master_);
        <br>
        <br>
        return 1;
        <br>
        <br>
        }
        <br>
        <br>
        <br>
        <br>
        <br>
        I made my sync0 time half of the can rate, as you prescribed:
        <br>
        <br>
        void
        <br>
        ecatModule_registerDcClock( Slave* slave, uint16_t addr )
        <br>
        {
        <br>
        struct timespec cur_time;
        <br>
        clock_gettime(CLOCK_REALTIME, &cur_time);
        <br>
        uint16_t sync0time = (uint16_t)((globalScanRate_us * 1000) / 2);
        <br>
        ecrt_slave_config_dc(
        <br>
        slave->sc,
        <br>
        addr,
        <br>
        (globalScanRate_us * 1000),
        <br>
        sync0time,
        <br>
        0,
        <br>
        0);
        <br>
        }
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        From: Graeme Foot <<a class="moz-txt-link-abbreviated" href="mailto:Graeme.Foot@touchcut.com">Graeme.Foot@touchcut.com</a>
        <br>
        <a class="moz-txt-link-rfc2396E" href="mailto:Graeme.Foot@touchcut.com"><mailto:Graeme.Foot@touchcut.com></a>>
        <br>
        Date: Sunday, February 21, 2016 at 4:07 PM
        <br>
        To: Thomas Bitsky <<a class="moz-txt-link-abbreviated" href="mailto:tbj@automateddesign.com">tbj@automateddesign.com</a>
        <a class="moz-txt-link-rfc2396E" href="mailto:tbj@automateddesign.com"><mailto:tbj@automateddesign.com></a>>
        <br>
        Cc: "<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>"
        <br>
        <<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>>
        <br>
        Subject: RE: Distributed Clocks
        <br>
        <br>
        Hi,
        <br>
        <br>
        I build and patch against revision 2526, so don’t know what
        patches /
        <br>
        fixes have made it through to the latest release.  However for
        my
        <br>
        revision I need fixes for reference clock selections and dc
        <br>
        synchronization issues.
        <br>
        <br>
        I’ve attached the dc related patches I use, but these are
        applied after
        <br>
        some other patches so you may get some conflicts or offsetting.
        <br>
        <br>
        *01 - Distributed Clock fixes and helpers.patch*
        <br>
        <br>
        This sorts out some ref slave issues, allowing a user selected
        ref
        <br>
        slave.  It also adds some helper functions:
        <br>
        <br>
        - ecrt_master_setup_domain_memory() : this allows me to set up
        the
        <br>
        domain memory and do stuff with it before calling
        ecrt_master_activate()
        <br>
        (for user space apps)
        <br>
        <br>
        - ecrt_master_deactivate_slaves() : this lets me deactivate the
        slaves
        <br>
        while still in realtime to avoid the slaves getting some
        shutdown sync
        <br>
        errors
        <br>
        <br>
        *02 - Distributed Clock fixes from Jun Yuan - dc sync
        issues.patch*
        <br>
        <br>
        This sorts out some timing issues to do with slave dc syncing. 
        Without
        <br>
        it they can start syncing from one cycle out causing a large
        syncing
        <br>
        time overhead, one slave at a time.
        <br>
        <br>
        Regards,
        <br>
        <br>
        Graeme.
        <br>
        <br>
        *From:*Thomas Bitsky Jr [<a class="moz-txt-link-freetext" href="mailto:tbj@automateddesign.com">mailto:tbj@automateddesign.com</a>]
        <br>
        *Sent:* Sunday, 21 February 2016 10:27 a.m.
        <br>
        *To:* Graeme Foot
        <br>
        *Cc:* <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>
        <br>
        *Subject:* Re: Distributed Clocks
        <br>
        <br>
        Graeme,
        <br>
        <br>
        Thank you so much for the detailed response. I'm away from my
        computer
        <br>
        right now, so I can't try out your advice, but I noticed you
        asked about
        <br>
        patches. I am not running any patches; which should I get?
        <br>
        <br>
        Thanks!
        <br>
        Thomas Bitsky Jr
        <br>
        <br>
        On Feb 20, 2016, at 3:04 PM, Graeme Foot
        <<a class="moz-txt-link-abbreviated" href="mailto:Graeme.Foot@touchcut.com">Graeme.Foot@touchcut.com</a>
        <br>
        <a class="moz-txt-link-rfc2396E" href="mailto:Graeme.Foot@touchcut.com"><mailto:Graeme.Foot@touchcut.com></a>> wrote:
        <br>
        <br>
            Hi,
        <br>
        <br>
            The slave clocks get synced via the distributed clock system
        using
        <br>
            the master methods: ecrt_master_reference_clock_time(),
        <br>
            ecrt_master_sync_slave_clocks(),
        ecrt_master_application_time(),
        <br>
            ecrt_master_sync_reference_clock().
        <br>
        <br>
            However each individual slave can choose (if it is capable
        of it)
        <br>
            whether to synchronize its reading and writing of data to a
        <br>
            particular point in time within the dc cycle.  If that slave
        does
        <br>
            not choose to do so then the reading and writing of the data
        occurs
        <br>
            at the time the EtherCAT frame goes past, resulting in a
        progressive
        <br>
            update and application of data as the frame progresses
        through all
        <br>
            of the slaves.
        <br>
        <br>
            If a slave is registered to use the dc clock then it caches
        the
        <br>
            frame data until the sync0 interrupt so in theory all dc
        slaves
        <br>
            apply the data at the same time.  It also means you don’t
        have to
        <br>
            worry about jitter as to the time the frame is sent over the
        wire.
        <br>
            The only thing is to choose a good sync0 time to ensure your
        frames
        <br>
            are always sent out and have reached all of the slaves
        before the
        <br>
            sync0 time occurs, and that the next frame is not sent out
        before
        <br>
            the previous sync0 time occurs.
        <br>
        <br>
            In my application my cycle time is 1000us.  I choose a sync0
        time of
        <br>
            500us.  I also send my frame as close as possible to the
        beginning
        <br>
            of the cycle. This gives the frame up to half the cycle time
        to
        <br>
            reach all of the slaves and then the other half of the cycle
        for the
        <br>
            frame to return in time for the master receive call.  I
        could choose
        <br>
            a sync0 time later than 500us but I want it processed as
        soon as
        <br>
            possible after the frame is received while still allowing
        for a bus
        <br>
            with a large number of terminals.
        <br>
        <br>
            So below where you are calculating loop_shift based on the
        current
        <br>
            time is wrong.  Just choose a time within the dc cycle and
        use that
        <br>
            value for all slaves.  Note: the beginning of the dc cycle
        is in
        <br>
            phase with the first call to ecrt_master_application_time(),
        so all
        <br>
            of your realtime looping should also be in phase with that
        initial time.
        <br>
        <br>
            Note, when selecting a slave to be the DC reference slave
        you should
        <br>
            generally choose the first slave on your bus, regardless of
        whether
        <br>
            it will be (or can be) registered to use the dc
        synchronization.  At
        <br>
            the very least it must be before, or be the, first slave
        that will
        <br>
            be registered as a dc slave.
        <br>
        <br>
            Also note that some slaves clocks are not very stable and
        shouldn’t
        <br>
            be used as the DC reference slave.  My original testing was
        on a
        <br>
            Beckhoff CX1020 with a CX1100-0004, this could not be used
        as a
        <br>
            reference slave as its clock was not stable.
        <br>
        <br>
            I see you are configuring the slaves via
        ecrt_slave_config_*()then
        <br>
            calling ecrt_slave_config_pdos()at the end.  If you call
        <br>
            ecrt_slave_config_pdos() at the beginning you don’t need all
        the
        <br>
            other config calls. However I hear AKD drives and some other
        slaves
        <br>
            prefer explicit slave config calls but most slaves are happy
        with
        <br>
            just the ecrt_slave_config_reg_pdo_entry()methods.
        <br>
        <br>
            This also leads to another issue.  One of the configured PDO
        items
        <br>
            is the “mode of operation” value (0x6060 0x00).  You are
        also
        <br>
            configuring this with: ecrt_slave_config_sdo8( sc, 0x6060,
        0, 8 ).
        <br>
            This value should be instead be set via the PDO value.  Use
        <br>
            ecrt_slave_config_reg_pdo_entry()to get the offset to the
        value and
        <br>
            set the value there.
        <br>
        <br>
            Sorry if that was a bit long but DC’s is not an easy topic
        to get
        <br>
            your head around.  Here’s a bit of a summary:
        <br>
        <br>
            - You can choose which slaves get registered with
        <br>
            ecrt_slave_config_dc(). But each slave you want synced must
        get its
        <br>
            own call to ecrt_slave_config_dc().
        <br>
        <br>
            - If your yaskawa drives get to OP without
        <br>
            ecrt_slave_config_dc()then they should get to OP with
        <br>
            ecrt_slave_config_dc().
        <br>
        <br>
            - The yaskawa drives require a very stable reference slave
        time,
        <br>
            which is why we sync the EtherCAT master to the reference
        slave
        <br>
            rather than the other way around.
        <br>
        <br>
            And some other comments:
        <br>
        <br>
            - Never use anEL9010 endcap module.  These break the
        distributed
        <br>
            clock calculations.  I don’t think they are available
        anymore though.
        <br>
        <br>
            - There are some patches out there that fix various DC clock
        issues,
        <br>
            are you using any of these?
        <br>
        <br>
            Regards,
        <br>
        <br>
            Graeme.
        <br>
        <br>
            *From:*Thomas Bitsky Jr [<a class="moz-txt-link-freetext" href="mailto:tbj@automateddesign.com">mailto:tbj@automateddesign.com</a>]
        <br>
            *Sent:* Sunday, 21 February 2016 7:15 a.m.
        <br>
            *To:* Graeme Foot; <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <br>
            <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>
        <br>
            *Subject:* Re: Distributed Clocks
        <br>
        <br>
            [snip]
        <br>
        <br>
            I’ve never been able to get the EL7041 stepper modules to
        work in dc
        <br>
            mode.
        <br>
        <br>
            [/snip]
        <br>
        <br>
            Is it all or nothing? I need the servo drives, the LVDT and
        the
        <br>
            EL3356 tied to a distributed clock. The EL7041 is optional
        for me.
        <br>
        <br>
            [snip]
        <br>
        <br>
            I don’t see in your code calls to ecrt_slave_config_dc().
        <br>
        <br>
            For the yaskawa drive, during the config stage, I use the
        following
        <br>
            calls…
        <br>
        <br>
            [/snip]
        <br>
        <br>
            Forgot to put that part; my bad. This is what I had for the
        <br>
            Yaskawa/AKD, although I was only doing it to one of the
        drives. I
        <br>
            thought I was supposed to set up one distributed clock, and
        it
        <br>
            became the master and handled the rest. Am I supposed to do
        this for
        <br>
            all the cards, or do I select?
        <br>
        <br>
            Yaskawa(AKD drive code is pretty much the same):
        <br>
        <br>
               if (!(sc = ecrt_master_slave_config(
        <br>
        <br>
                                 master,
        <br>
        <br>
            slavePosDomain,
        <br>
        <br>
            slavePosIndex,
        <br>
        <br>
            vendorId, productCode)))
        <br>
        <br>
            {
        <br>
        <br>
            return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1C12, 0, 0 ); /* clear sm pdo
        0x1c12 */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1C13, 0, 0 ); /* clear sm pdo
        0x1c12 */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A00, 0, 0 ); /* clear TxPDO0
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A01, 0, 0 ); /* clear TxPDO1
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A02, 0, 0 ); /* clear TxPDO2
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A03, 0, 0 ); /* clear TxPDO3
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1600, 0, 0 ); /* number of var
        in this
        <br>
            PDO */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1601, 0, 0 ); /* clear RxPdo
        0x1601 */
        <br>
        <br>
                 ecrt_slave_config_sdo8( sc, 0x1602, 0, 0 ); /* clear
        RxPdo
        <br>
            0x1602 */
        <br>
        <br>
                 ecrt_slave_config_sdo8( sc, 0x1603, 0, 0 ); /* clear
        RxPdo
        <br>
            0x1603 */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A00, 0, 0 ); /* clear TxPDO0
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 1, 0x60410010 ); //
        Status word
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 2,0x60640020 );//
        Position
        <br>
            actual value, per encoder
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 3,0x60770010 );//
        Torque,
        <br>
            actual value
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 4,0x60F40020 );//
        Following
        <br>
            error, actual value
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 5,0x60610008 );// Modes
        of
        <br>
            operation display
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 6,0x00000008 );// GAP
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 7,0x60B90010 );// Touch
        probe
        <br>
            status
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A00, 8, 0x60BA0020 ); //
        Touch probe
        <br>
            1 position
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A00, 0, 8 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A01, 0, 0 ); /* clear TxPDO1
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A01,1,0x60410010 ); //
        Status word
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A01,2,0x60640020 );//
        Position
        <br>
            actual value, per encoder
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A01, 0, 2 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A02, 0, 0 ); /* clear TxPDO2
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A02,1,0x60410010 ); //
        Status word
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A02,2,0x60640020 );//
        Position
        <br>
            actual value, per encoder
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A02, 0, 2 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A03, 0, 0 ); /* clear TxPDO2
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A03,1,0x60410010 ); //
        Status word
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A03,2,0x60640020 );//
        Position
        <br>
            actual value, per encoder
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1A03,3,0x60770010 );//
        Torque, actual
        <br>
            value
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1A03, 0, 3 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1600, 0, 0 ); /* clear entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 1, 0x60400010  ); /*
        control
        <br>
            word */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 2, 0x607A0020  ); /*
        target
        <br>
            position */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 3, 0x60FF0020  ); /*
        target
        <br>
            velocity */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 4, 0x60710010  ); /*
        target
        <br>
            torque */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 5, 0x60720010  ); /*
        max torque */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 6, 0x60600008  ); /*
        modes of
        <br>
            operation */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 7, 0x00000008  ); /*
        gap */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1600, 8, 0x60B80010  ); /*
        touch
        <br>
            probe function */
        <br>
        <br>
            ecrt_slave_config_sdo8(sc, 0x1600, 0, 8 ); /* pdo entries */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1601, 0, 0 ); /* clear entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1601, 1, 0x60400010  ); /*
        control
        <br>
            word */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1601, 2, 0x607A0020  ); /*
        target
        <br>
            position */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1601, 0, 2 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1602, 0, 0 ); /* clear entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1602, 1, 0x60400010  ); /*
        control
        <br>
            word */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1602, 2, 0x60FF0020  ); /*
        target
        <br>
            position */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1602, 0, 2 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1603, 0, 0 ); /* clear entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1603, 1, 0x60400010  ); /*
        control
        <br>
            word */
        <br>
        <br>
            ecrt_slave_config_sdo32( sc, 0x1603, 2, 0x60710020  ); /*
        target
        <br>
            position */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1603, 0, 2 ); /* pdo entries
        */
        <br>
        <br>
            ecrt_slave_config_sdo16( sc, 0x1C12, 1, 0x1601 ); /*
        download pdo
        <br>
            1C12 index */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1C12, 0, 1 ); /* set number of
        RxPDO */
        <br>
        <br>
            ecrt_slave_config_sdo16( sc, 0x1C13, 1, 0x1A01 ); /*
        download pdo
        <br>
            1C13 index */
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x1C13, 0, 1 ); /* set number of
        TxPDO */
        <br>
        <br>
            // OPMODE
        <br>
        <br>
            // Yaskawa recommends 8
        <br>
        <br>
            ecrt_slave_config_sdo8( sc, 0x6060, 0, 8 );
        <br>
        <br>
            unsigned char interpolationTime = 0xFF;
        <br>
        <br>
            // 250
        <br>
        <br>
            unsigned char cycleExponent = 0xFA;
        <br>
        <br>
            // microseconds
        <br>
        <br>
            // globalSCanRate_us equals either 250 or 125.
        <br>
        <br>
            unsigned int us = globalScanRate_us;
        <br>
        <br>
            size_t i;
        <br>
        <br>
            for ( i=0;i<6, us > 0xFF;++i )
        <br>
        <br>
            {
        <br>
        <br>
            us /= 10;
        <br>
        <br>
            cycleExponent += 1;
        <br>
        <br>
            }
        <br>
        <br>
            interpolationTime = us;
        <br>
        <br>
            ecrt_slave_config_sdo8( akd->sc_akd, 0x60C2, 1,
        interpolationTime );
        <br>
            /* Interpolation time */
        <br>
        <br>
            ecrt_slave_config_sdo8( akd->sc_akd, 0x60C2, 2,
        cycleExponent ); /*
        <br>
            Cycle exponent */
        <br>
        <br>
                 PRINT("Configuring PDOs...\n");
        <br>
        <br>
                 if (ecrt_slave_config_pdos(sc, EC_END, slave_syncs))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT("Failed to configure Yaskawa Sigma PDOs.\n");
        <br>
        <br>
                     return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            *struct timespec cur_time;*
        <br>
        <br>
            *clock_gettime(CLOCK_REALTIME, &cur_time);*
        <br>
        <br>
            *size_t loop_period = globalScanRate_us * 1000;*
        <br>
        <br>
            *if ( loop_period == 0 ) loop_period = 1;*
        <br>
        <br>
            *size_t loop_shift *
        <br>
        <br>
            *= loop_period - (cur_time.tv_nsec % loop_period);*
        <br>
        <br>
            *ecrt_slave_config_dc(*
        <br>
        <br>
            *sc, *
        <br>
        <br>
            *0x0300, *
        <br>
        <br>
            *loop_period, *
        <br>
        <br>
            *loop_shift, *
        <br>
        <br>
            *0, *
        <br>
        <br>
            *0);*
        <br>
        <br>
            For the EL3356, would I then?
        <br>
        <br>
            KL3356StrainGauge* sg =
        (KL3356StrainGauge*)slave->instance;
        <br>
        <br>
            printf( "Begin kl3356_ecConfigure...\n");
        <br>
        <br>
            //
        <br>
        <br>
            // Create the slave configuration
        <br>
        <br>
            //
        <br>
        <br>
            if (!(sg->sc = ecrt_master_slave_config(
        <br>
        <br>
            master,
        <br>
        <br>
            slavePosDomain, slavePosIndex, // Bus position
        <br>
        <br>
            vendorId, productCode
        <br>
        <br>
            // Slave type
        <br>
        <br>
            )))
        <br>
        <br>
            {
        <br>
        <br>
            printf(
        <br>
        <br>
            "kl3356_ecConfigure -- Failed to get slave
        configuration.\n");
        <br>
        <br>
                return FALSE;
        <br>
        <br>
            }
        <br>
        <br>
            //
        <br>
        <br>
            // Register startup configuration for the hardware
        <br>
        <br>
            //
        <br>
        <br>
            ecrt_slave_config_sdo8( sg->sc, 0x1C12, 0, 0 ); /* clear
        sm pdo
        <br>
            0x1c12 */
        <br>
        <br>
            ecrt_slave_config_sdo8( sg->sc, 0x1C13, 0, 0 ); /* clear
        sm pdo
        <br>
            0x1c12 */
        <br>
        <br>
            ecrt_slave_config_sdo16( sg->sc, 0x1C12, 1, 0x1600 ); /*
        download
        <br>
            pdo 1C12 index */
        <br>
        <br>
            ecrt_slave_config_sdo8( sg->sc, 0x1C12, 0, 1 ); /* set
        number of
        <br>
            RxPDO */
        <br>
        <br>
            ecrt_slave_config_sdo16( sg->sc, 0x1C13, 1, 0x1A00 ); /*
        download
        <br>
            pdo 1C13 index */
        <br>
        <br>
            ecrt_slave_config_sdo16( sg->sc, 0x1C13, 2, 0x1A02 ); /*
        download
        <br>
            pdo 1C13 index */
        <br>
        <br>
            ecrt_slave_config_sdo8( sg->sc, 0x1C13, 0, 2 ); /* set
        number of
        <br>
            TxPDO */
        <br>
        <br>
            //
        <br>
        <br>
            // Configure the hardware's PDOs
        <br>
        <br>
            //
        <br>
        <br>
            if (ecrt_slave_config_pdos(sg->sc, EC_END, kl3356_syncs))
        <br>
        <br>
            {
        <br>
        <br>
                printf(
        <br>
        <br>
            "kl3356_ecConfigure -- Failed to configure PDOs.\n");
        <br>
        <br>
                return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            *struct timespec cur_time;*
        <br>
        <br>
            *clock_gettime(CLOCK_REALTIME, &cur_time);*
        <br>
        <br>
            *size_t loop_period = globalScanRate_us * 1000;*
        <br>
        <br>
            *if ( loop_period == 0 ) loop_period = 1;*
        <br>
        <br>
            *size_t loop_shift *
        <br>
        <br>
            *= loop_period - (cur_time.tv_nsec % loop_period);*
        <br>
        <br>
            *ecrt_slave_config_dc(*
        <br>
        <br>
            *s**g->sc, *
        <br>
        <br>
            *0x0300, *
        <br>
        <br>
            *loop_period, *
        <br>
        <br>
            *loop_shift, *
        <br>
        <br>
            *0, *
        <br>
        <br>
            *0);*
        <br>
        <br>
            Thanks!
        <br>
        <br>
            Thomas C. Bitsky Jr. | Lead Developer
        <br>
        <br>
            ADC | automateddesign.com
        <a class="moz-txt-link-rfc2396E" href="http://automateddesign.com/"><http://automateddesign.com/></a>
        <br>
        <br>
            P: 630-783-1150 F: 630-783-1159 M: 630-632-6679
        <br>
        <br>
            Follow ADC news and media:
        <br>
        <br>
            Facebook <a class="moz-txt-link-rfc2396E" href="https://facebook.com/automateddesigncorp"><https://facebook.com/automateddesigncorp></a> |
        Twitter
        <br>
            <a class="moz-txt-link-rfc2396E" href="https://twitter.com/ADCSportsLogic"><https://twitter.com/ADCSportsLogic></a> | YouTube
        <br>
            <a class="moz-txt-link-rfc2396E" href="https://www.youtube.com/user/ADCSportsLogic"><https://www.youtube.com/user/ADCSportsLogic></a>
        <br>
        <br>
            *From: *Graeme Foot <<a class="moz-txt-link-abbreviated" href="mailto:Graeme.Foot@touchcut.com">Graeme.Foot@touchcut.com</a>
        <br>
            <a class="moz-txt-link-rfc2396E" href="mailto:Graeme.Foot@touchcut.com"><mailto:Graeme.Foot@touchcut.com></a>>
        <br>
            *Date: *Friday, February 19, 2016 at 7:24 PM
        <br>
            *To: *Thomas Bitsky <<a class="moz-txt-link-abbreviated" href="mailto:tbj@automateddesign.com">tbj@automateddesign.com</a>
        <br>
            <a class="moz-txt-link-rfc2396E" href="mailto:tbj@automateddesign.com"><mailto:tbj@automateddesign.com></a>>,
        "<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <br>
            <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>"
        <<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <br>
            <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>>
        <br>
            *Subject: *RE: Distributed Clocks
        <br>
        <br>
            Hi,
        <br>
        <br>
            I don’t see in your code calls to ecrt_slave_config_dc().
        <br>
        <br>
            For the yaskawa drive, during the config stage, I use the
        following
        <br>
            calls:
        <br>
        <br>
                 // set interpolation time period (free run mode)
        <br>
        <br>
                 // where 0x60C2 is time in seconds = (0x60C2, 0x01) x
        <br>
            10^(0x60C2, 0x02)
        <br>
        <br>
                 // eg period of 1ms:
        <br>
        <br>
                 //   (0x60C2, 0x01) = 1
        <br>
        <br>
                 //   (0x60C2, 0x02) = -3
        <br>
        <br>
                 // => 1 x 10^(-3) = 0.001s
        <br>
        <br>
                 ecrt_slave_config_sdo8(dev->slaveConfig, 0x60C2,
        0x01,
        <br>
            (uint8_t)g_app.scanTimeMS);
        <br>
        <br>
                 ecrt_slave_config_sdo8(dev->slaveConfig, 0x60C2,
        0x02,
        <br>
            (int8_t)(-3));
        <br>
        <br>
                 // set up the distributed clock
        <br>
        <br>
                 // 0x0000 = free run, 0x0300 = dc
        <br>
        <br>
                 // (Supported DC cycle: 125us to 4ms (every 125us
        cycle))
        <br>
        <br>
                 ecrt_slave_config_dc(dev->slaveConfig, 0x0300,
        <br>
            g_app.scanTimeNS, 500000, 0, 0);
        <br>
        <br>
            0x60C2 shouldn’t be necessary for dc mode, but I used it
        before I
        <br>
            had dc mode working and have never tried it without and it
        doesn’t
        <br>
            harm anything having it in.
        <br>
        <br>
            The second value that is being passed to the
        <br>
            ecrt_slave_config_dcmethod is a value that is written to the
        ESC
        <br>
            register 0x980. The Yaskawa SGDV doco says this value should
        be
        <br>
            0x0000 for free run mode and 0x0300 for dc mode.  Other
        ESC’s may
        <br>
            required different values.
        <br>
        <br>
            I’ve never been able to get the EL7041 stepper modules to
        work in dc
        <br>
            mode.
        <br>
        <br>
            Graeme.
        <br>
        <br>
            *From:*etherlab-users
        [<a class="moz-txt-link-freetext" href="mailto:etherlab-users-bounces@etherlab.org">mailto:etherlab-users-bounces@etherlab.org</a>]
        <br>
            *On Behalf Of *Thomas Bitsky Jr
        <br>
            *Sent:* Saturday, 20 February 2016 1:09 p.m.
        <br>
            *To:* <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>
        <br>
            *Subject:* [etherlab-users] Distributed Clocks
        <br>
        <br>
            Hello.
        <br>
        <br>
            I’ve been using the EtherCAT master for years to great
        success, but
        <br>
            I’m stuck on a problem I can’t figure out that I think
        several
        <br>
            people here are doing successfully. I can’t implement
        distributed
        <br>
            clocks in my application.
        <br>
        <br>
            I am having the same problem on two systems I have up and
        running:
        <br>
        <br>
            SYSTEM ONE:
        <br>
        <br>
            EtherLAB Master 1.52, E1000E Driver, Scan Rate 4Khz, Ubuntu
        Server
        <br>
            14.04LTS, RT-PREEMPT 3.12.50-rt68
        <br>
        <br>
            alias=0, position=0, device=EK1100
        <br>
        <br>
            alias=0, position=1, device=EL1104
        <br>
        <br>
            alias=0, position=2, device=EL2004
        <br>
        <br>
            alias=0, position=3, device=EL9510
        <br>
        <br>
            alias=0, position=4, device=EL3356
        <br>
        <br>
            alias=0, position=5, device=Kollmorgen AKD
        <br>
        <br>
            alias=0, position=6, device=MTS LVDT
        <br>
        <br>
            SYSTEM TWO:
        <br>
        <br>
            EtherLAB Master 1.52, E1000E Driver, Scan Rate 8Khz, Ubuntu
        Server
        <br>
            14.04LTS, RT-PREEMPT 3.12.50-rt68
        <br>
        <br>
            alias=0, position=0, device=EK1100
        <br>
        <br>
            alias=0, position=1, device=EL3001
        <br>
        <br>
            alias=0, position=2, device=EL1104
        <br>
        <br>
            alias=0, position=3, device=EL1104
        <br>
        <br>
            alias=0, position=4, device=EL1104
        <br>
        <br>
            alias=0, position=5, device=EL2004
        <br>
        <br>
            alias=0, position=6, device=EL2004
        <br>
        <br>
            alias=0, position=7, device=EL9505
        <br>
        <br>
            alias=0, position=8, device=EL7041
        <br>
        <br>
            alias=0, position=9, device=EL7041
        <br>
        <br>
            alias=0, position=10, device=EL7041
        <br>
        <br>
            alias=0, position=11, device=EL7041
        <br>
        <br>
            alias=0, position=12, device=EL7041
        <br>
        <br>
            alias=0, position=13, device=EL7041
        <br>
        <br>
            alias=0, position=14, device=EK1110
        <br>
        <br>
            alias=1, position=0, device=SIGMA5-05
        <br>
        <br>
            alias=2, position=0, device=Yaskawa SIGMA5-05
        <br>
        <br>
            alias=3, position=0, device=Yaskawa SIGMA5-05
        <br>
        <br>
            Both of the system are fully operational. However, for
        various
        <br>
            reasons, I need to implement distributed clocks on these
        systems.
        <br>
            I’ve never been able to get this to work.
        <br>
        <br>
            What follows is the code I used for both systems to try
        this. I read
        <br>
            through examples on the mailing list, plus the examples, but
        I’m not
        <br>
            seeing what I’m doing wrong. The result is always the same:
        all the
        <br>
            fieldbus cards go into operation, but the servo drives won’t
        because
        <br>
            of “bad configuration.” Take out the distributed clock code,
        and
        <br>
            they work fine. I’m getting away with it for now, but I do
        need
        <br>
            better clock resolution.
        <br>
        <br>
            The systems have an LRW domain, then a separate read domain
        and
        <br>
            write domain for the servo drive(s) for a total of three
        domains
        <br>
            (LRW, read, write). The yaskawa drives necessitate this. The
        scan
        <br>
            rate is usually 4Khz, but I have tried it at both 1Khz and
        8Khz and
        <br>
            gotten the same results. Everything about the implementation
        is
        <br>
            fairly straight-forward. There’s just something fundamental
        about
        <br>
            the DC configuration that I’m not understanding.
        <br>
        <br>
            Almost all the code below is taken right from the examples
        or the
        <br>
            message boards (thanks, everybody!). If anyone could tell me
        what
        <br>
            I’m going wrong or offer any insights, it’s greatly
        appreciated. For
        <br>
            brevity, I tried to narrow it down to relevant parts, but
        please let
        <br>
            me know any additional information or code I can provide.
        <br>
        <br>
            Thank you in advance,
        <br>
        <br>
            Tom
        <br>
        <br>
            **********************************************************
        <br>
        <br>
            // EtherCAT distributed clock variables
        <br>
        <br>
            #define DC_FILTER_CNT          1024
        <br>
        <br>
            #define SYNC_MASTER_TO_REF        1
        <br>
        <br>
            static uint64_t dc_start_time_ns = 0LL;
        <br>
        <br>
            static uint64_t dc_time_ns = 0;
        <br>
        <br>
            static uint8_t  dc_started = 0;
        <br>
        <br>
            static int32_t  dc_diff_ns = 0;
        <br>
        <br>
            static int32_t  prev_dc_diff_ns = 0;
        <br>
        <br>
            static int64_t  dc_diff_total_ns = 0LL;
        <br>
        <br>
            static int64_t  dc_delta_total_ns = 0LL;
        <br>
        <br>
            static int      dc_filter_idx = 0;
        <br>
        <br>
            static int64_t  dc_adjust_ns;
        <br>
        <br>
            static int64_t  system_time_base = 0LL;
        <br>
        <br>
            static uint64_t wakeup_time = 0LL;
        <br>
        <br>
            static uint64_t overruns = 0LL;
        <br>
        <br>
            /** Get the time in ns for the current cpu, adjusted by
        <br>
            system_time_base.
        <br>
        <br>
              *
        <br>
        <br>
              * \attention Rather than calling rt_get_time_ns()
        directly, all
        <br>
            application
        <br>
        <br>
              * time calls should use this method instead.
        <br>
        <br>
              *
        <br>
        <br>
              * \ret The time in ns.
        <br>
        <br>
              */
        <br>
        <br>
            uint64_t system_time_ns(void)
        <br>
        <br>
            {
        <br>
        <br>
            struct timespec ts;
        <br>
        <br>
            clock_gettime(GLOBAL_CLOCK_TO_USE, &ts);
        <br>
        <br>
            return TIMESPEC2NS(ts);
        <br>
        <br>
            }
        <br>
        <br>
            static
        <br>
        <br>
            void sync_distributed_clocks(void)
        <br>
        <br>
            {
        <br>
        <br>
                 uint32_t ref_time = 0;
        <br>
        <br>
                 uint64_t prev_app_time = dc_time_ns;
        <br>
        <br>
                 dc_time_ns = system_time_ns();
        <br>
        <br>
                 // set master time in nano-seconds
        <br>
        <br>
                 ecrt_master_application_time(master_, dc_time_ns);
        <br>
        <br>
                 // get reference clock time to synchronize master cycle
        <br>
        <br>
                 ecrt_master_reference_clock_time(master_,
        &ref_time);
        <br>
        <br>
                 dc_diff_ns = (uint32_t) prev_app_time - ref_time;
        <br>
        <br>
                 // call to sync slaves to ref slave
        <br>
        <br>
                 ecrt_master_sync_slave_clocks(master_);
        <br>
        <br>
            }
        <br>
        <br>
            /** Return the sign of a number
        <br>
        <br>
              *
        <br>
        <br>
              * ie -1 for -ve value, 0 for 0, +1 for +ve value
        <br>
        <br>
              *
        <br>
        <br>
              * \retval the sign of the value
        <br>
        <br>
              */
        <br>
        <br>
            #define sign(val) \
        <br>
        <br>
                 ({ typeof (val) _val = (val); \
        <br>
        <br>
                 ((_val > 0) - (_val < 0)); })
        <br>
        <br>
           
/*****************************************************************************/<br>
        <br>
            /** Update the master time based on ref slaves time diff
        <br>
        <br>
              *
        <br>
        <br>
              * called after the ethercat frame is sent to avoid time
        jitter in
        <br>
        <br>
              * sync_distributed_clocks()
        <br>
        <br>
              */
        <br>
        <br>
            static unsigned int cycle_ns = 1000000;  // 1 millisecond
        <br>
        <br>
            void update_master_clock(void)
        <br>
        <br>
            {
        <br>
        <br>
                 // calc drift (via un-normalised time diff)
        <br>
        <br>
                 int32_t delta = dc_diff_ns - prev_dc_diff_ns;
        <br>
        <br>
                 prev_dc_diff_ns = dc_diff_ns;
        <br>
        <br>
                 // normalise the time diff
        <br>
        <br>
                 dc_diff_ns =
        <br>
        <br>
                     ((dc_diff_ns + (cycle_ns / 2)) % cycle_ns) -
        (cycle_ns / 2);
        <br>
        <br>
                 // only update if primary master
        <br>
        <br>
                 if (dc_started) {
        <br>
        <br>
                     // add to totals
        <br>
        <br>
                     dc_diff_total_ns += dc_diff_ns;
        <br>
        <br>
                     dc_delta_total_ns += delta;
        <br>
        <br>
                     dc_filter_idx++;
        <br>
        <br>
                     if (dc_filter_idx >= DC_FILTER_CNT) {
        <br>
        <br>
                         // add rounded delta average
        <br>
        <br>
                         dc_adjust_ns +=
        <br>
        <br>
                             ((dc_delta_total_ns + (DC_FILTER_CNT / 2))
        /
        <br>
            DC_FILTER_CNT);
        <br>
        <br>
                         // and add adjustment for general diff (to pull
        in drift)
        <br>
        <br>
                         dc_adjust_ns += sign(dc_diff_total_ns /
        DC_FILTER_CNT);
        <br>
        <br>
                         // limit crazy numbers (0.1% of std cycle time)
        <br>
        <br>
                         if (dc_adjust_ns < -1000) {
        <br>
        <br>
                             dc_adjust_ns = -1000;
        <br>
        <br>
                         }
        <br>
        <br>
                         if (dc_adjust_ns > 1000) {
        <br>
        <br>
                             dc_adjust_ns =  1000;
        <br>
        <br>
                         }
        <br>
        <br>
                         // reset
        <br>
        <br>
                         dc_diff_total_ns = 0LL;
        <br>
        <br>
                         dc_delta_total_ns = 0LL;
        <br>
        <br>
                         dc_filter_idx = 0;
        <br>
        <br>
                     }
        <br>
        <br>
                     // add cycles adjustment to time base (including a
        spot
        <br>
            adjustment)
        <br>
        <br>
                     system_time_base += dc_adjust_ns +
        sign(dc_diff_ns);
        <br>
        <br>
                 }
        <br>
        <br>
                 else {
        <br>
        <br>
                     dc_started = (dc_diff_ns != 0);
        <br>
        <br>
                     if (dc_started)
        <br>
        <br>
            {
        <br>
        <br>
                         // record the time of this initial cycle
        <br>
        <br>
                         dc_start_time_ns = dc_time_ns;
        <br>
        <br>
                     }
        <br>
        <br>
                 }
        <br>
        <br>
            }
        <br>
        <br>
            struct timespec dcTime_;
        <br>
        <br>
            int
        <br>
        <br>
            ecatMain_process(void* lp)
        <br>
        <br>
            {
        <br>
        <br>
            ecrt_master_receive(master_);
        <br>
        <br>
            clock_gettime(CLOCK_REALTIME, &dcTime_);
        <br>
        <br>
            ecrt_master_application_time(master_, TIMESPEC2NS(dcTime_));
        <br>
        <br>
            ecrt_master_sync_reference_clock(master_);
        <br>
        <br>
            ecrt_master_sync_slave_clocks(master_);
        <br>
        <br>
            ecrt_domain_process(lrwDomainMgr_.domain);
        <br>
        <br>
            ecrt_domain_process(noLrwWriteDomainMgr_.domain);
        <br>
        <br>
            ecrt_domain_process(noLrwReadDomainMgr_.domain);
        <br>
        <br>
            … // handle my business
        <br>
        <br>
            // write application time to master
        <br>
        <br>
            clock_gettime(CLOCK_REALTIME, &dcTime_);
        <br>
        <br>
            ecrt_master_application_time(master_, TIMESPEC2NS(dcTime_));
        <br>
        <br>
            if (sync_ref_counter_)
        <br>
        <br>
            {
        <br>
        <br>
            sync_ref_counter_--;
        <br>
        <br>
            }
        <br>
        <br>
            else
        <br>
        <br>
            {
        <br>
        <br>
            sync_ref_counter_ = 1; // sync every cycle
        <br>
        <br>
            ecrt_master_sync_reference_clock(master_);
        <br>
        <br>
            }
        <br>
        <br>
            // send process data
        <br>
        <br>
            ecrt_domain_queue(lrwDomainMgr_.domain);
        <br>
        <br>
            ecrt_domain_queue(noLrwWriteDomainMgr_.domain);
        <br>
        <br>
            ecrt_domain_queue(noLrwReadDomainMgr_.domain);
        <br>
        <br>
            // sync distributed clock just before master_send to set
        <br>
        <br>
            // most accurate master clock time
        <br>
        <br>
            sync_distributed_clocks();
        <br>
        <br>
            // send EtherCAT data
        <br>
        <br>
            ecrt_master_send(master_);
        <br>
        <br>
            // update the master clock
        <br>
        <br>
            // Note: called after ecrt_master_send() to reduce time
        <br>
        <br>
            // jitter in the sync_distributed_clocks() call
        <br>
        <br>
            update_master_clock();
        <br>
        <br>
            return 1;
        <br>
        <br>
            }
        <br>
        <br>
            int
        <br>
        <br>
            ecatMain_start(void* lp)
        <br>
        <br>
            {
        <br>
        <br>
            //
        <br>
        <br>
            // domain regs must end in a null entry
        <br>
        <br>
            //
        <br>
        <br>
            lrwDomainMgr_.domainRegs = realloc(
        <br>
        <br>
            lrwDomainMgr_.domainRegs,
        <br>
        <br>
            sizeof(ec_pdo_entry_reg_t) * (lrwDomainMgr_.size + 1)  );
        <br>
        <br>
            memset(
        <br>
        <br>
            &(lrwDomainMgr_.domainRegs[lrwDomainMgr_.size]),
        <br>
        <br>
            0,
        <br>
        <br>
            sizeof(ec_pdo_entry_reg_t) );
        <br>
        <br>
            noLrwReadDomainMgr_.domainRegs = realloc(
        <br>
        <br>
            noLrwReadDomainMgr_.domainRegs,
        <br>
        <br>
            sizeof(ec_pdo_entry_reg_t) * (noLrwReadDomainMgr_.size + 1) 
        );
        <br>
        <br>
            memset(
        <br>
        <br>
           
        &(noLrwReadDomainMgr_.domainRegs[noLrwReadDomainMgr_.size]),
        <br>
        <br>
            0,
        <br>
        <br>
            sizeof(ec_pdo_entry_reg_t) );
        <br>
        <br>
            noLrwWriteDomainMgr_.domainRegs = realloc(
        <br>
        <br>
            noLrwWriteDomainMgr_.domainRegs,
        <br>
        <br>
            sizeof(ec_pdo_entry_reg_t) * (noLrwWriteDomainMgr_.size +
        1)  );
        <br>
        <br>
            memset(
        <br>
        <br>
           
        &(noLrwWriteDomainMgr_.domainRegs[noLrwWriteDomainMgr_.size]),
        <br>
        <br>
            0,
        <br>
        <br>
            sizeof(ec_pdo_entry_reg_t) );
        <br>
        <br>
            //
        <br>
        <br>
            // NOTE: the Output Domain must be registered with
        <br>
        <br>
            // ecrt_domain_reg_pdo_entry_list before the Input Domain
        otherwise you
        <br>
        <br>
            // will not have any data exchanged even though the drive
        goes into OP
        <br>
        <br>
            // mode.
        <br>
        <br>
            //
        <br>
        <br>
            PRINT("\nAttempting to register PDOs on WRITE ONLY
        domain...\n");
        <br>
        <br>
            if (ecrt_domain_reg_pdo_entry_list(
        <br>
        <br>
            noLrwWriteDomainMgr_.domain,
        noLrwWriteDomainMgr_.domainRegs))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT("WRITE ONLY PDO entry registration failed!\n");
        <br>
        <br>
            return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            PRINT("\nAttempting to register PDOs on READ ONLY
        domain...\n");
        <br>
        <br>
            if (ecrt_domain_reg_pdo_entry_list(
        <br>
        <br>
            noLrwReadDomainMgr_.domain, noLrwReadDomainMgr_.domainRegs))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT("READ ONLY PDO entry registration failed!\n");
        <br>
        <br>
            return FALSE;
        <br>
        <br>
              }
        <br>
        <br>
            //
        <br>
        <br>
            // And now we register the bi-directional domain.
        <br>
        <br>
            //
        <br>
        <br>
            PRINT("\nAttempting to register PDOs on LRW domain...\n");
        <br>
        <br>
            if (ecrt_domain_reg_pdo_entry_list(
        <br>
        <br>
            lrwDomainMgr_.domain, lrwDomainMgr_.domainRegs))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT("LRW PDO entry registration failed!\n");
        <br>
        <br>
            return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            /*
        <br>
        <br>
            * Finishes the configuration phase and prepares for cyclic
        operation.
        <br>
        <br>
            * This function tells the master that the configuration
        phase
        <br>
        <br>
            * is finished and the realtime operation will begin.
        <br>
        <br>
            * The function allocates internal memory for the domains and
        calculates
        <br>
        <br>
            * the logical FMMU addresses for domain members.
        <br>
        <br>
            * It tells the master state machine that the bus
        configuration is
        <br>
        <br>
            * now to be applied
        <br>
        <br>
            */
        <br>
        <br>
            PRINT("\nAttempting to activate ECAT master...\n");
        <br>
        <br>
            if (ecrt_master_activate(master_))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT(
        <br>
        <br>
            "%s Failed to activate master!\n",
        <br>
        <br>
            __FUNCTION__ );
        <br>
        <br>
            return FALSE;
        <br>
        <br>
            }
        <br>
        <br>
            /*
        <br>
        <br>
            * Returns the domain's process data.
        <br>
        <br>
            */
        <br>
        <br>
            PRINT( "%s getting LRW process data from master.\n",
        __FUNCTION__ );
        <br>
        <br>
            if (!(lrwDomainMgr_.processData
        <br>
        <br>
            = ecrt_domain_data(lrwDomainMgr_.domain)))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT(
        <br>
        <br>
            "%s set ecProcessData -- domain data is NULL!\n",
        <br>
        <br>
            __FUNCTION__ );
        <br>
        <br>
            return FALSE;
        <br>
        <br>
              }
        <br>
        <br>
            if (!(noLrwReadDomainMgr_.processData
        <br>
        <br>
            = ecrt_domain_data(noLrwReadDomainMgr_.domain)))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT(
        <br>
        <br>
            "%s set read ProcessData -- domain data is NULL!\n",
        <br>
        <br>
            __FUNCTION__ );
        <br>
        <br>
            return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            if (!(noLrwWriteDomainMgr_.processData
        <br>
        <br>
            = ecrt_domain_data(noLrwWriteDomainMgr_.domain)))
        <br>
        <br>
            {
        <br>
        <br>
            PRINT(
        <br>
        <br>
            "%s set write ProcessData -- domain data is NULL!\n",
        <br>
        <br>
            __FUNCTION__ );
        <br>
        <br>
            return FALSE;
        <br>
        <br>
                 }
        <br>
        <br>
            … // blah blah blah
        <br>
        <br>
            doScan_ = TRUE;
        <br>
        <br>
            PRINT( "%s completed successfully.\n", __FUNCTION__ );
        <br>
        <br>
            return TRUE;
        <br>
        <br>
            }
        <br>
        <br>
        <br>
        <br>
        _______________________________________________
        <br>
        etherlab-users mailing list
        <br>
        <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
        <br>
        <a class="moz-txt-link-freetext" href="http://lists.etherlab.org/mailman/listinfo/etherlab-users">http://lists.etherlab.org/mailman/listinfo/etherlab-users</a>
        <br>
        <br>
      </blockquote>
      _______________________________________________
      <br>
      etherlab-users mailing list
      <br>
      <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
      <br>
      <a class="moz-txt-link-freetext" href="http://lists.etherlab.org/mailman/listinfo/etherlab-users">http://lists.etherlab.org/mailman/listinfo/etherlab-users</a>
      <br>
      <br>
      <br>
    </blockquote>
    <br>
    <div class="moz-signature">-- <br>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <title></title>
      <br>
      <pre class="moz-signature" cols="72">Oguz Dilmac
ARGE Bolumu

Bilko AS, R&D Department
====================================
Perpa Ticaret Merkezi B Blok Kat 13 Nr. 2568
TR-34384 Okmeydani Istanbul Turkey
Tel : +90 212 220 07 40  Fax :   +90 212 210 47 01
e-mail : <a class="moz-txt-link-abbreviated" href="mailto:odilmac@bilko-automation.com">odilmac@bilko-automation.com</a>
web site : <a class="moz-txt-link-freetext" href="http://www.bilko-automation.com">http://www.bilko-automation.com</a>
        </pre>
    </div>
  </body>
</html>