[etherlab-users] Distributed Clocks

Richard Hacker ha at igh.de
Thu Mar 3 20:59:04 CET 2016


Hi,

we use CLOCK_MONOTONIC for ecrt_master_application_time(), in fact we 
use it thoughout. Probably not the solution, but worth a try.

- Richard

On 03.03.2016 17:08, Thomas Bitsky Jr wrote:
>
> [snip]
> Are you using the dc_clock_adjust to modify your sleep time?  ie.
> something like
> [/snip]
>
>
> I’ve been trying, but the results are all over the place and I’m obviously not understanding what needs to be done with the clock.
>
> My latest attempt is has the scan time ticking from anywhere between 3930 and 4100 scans per second (reported by ethercat master command) and does nothing to eliminate skipped datagrams. I don’t think I’m fundamentally understanding what needs to be done.
>
> My latest code is below. If anyone has any insights, it would be greatly appreciated.
>
> ========
>
> int64_t  dc_adjust_ns = 0 ;
> int32_t  dc_diff_ns = 0;
>
>
>
> void calculateClockDrift(void) {
>      uint32_t ref_time = 0;
>      uint64_t prev_app_time = dc_time_ns;
>
>      dc_time_ns = system_time_ns();
>      // get reference clock time to synchronize master cycle
>      ecrt_master_reference_clock_time(master_, & ref_time);
>      dc_diff_ns = (uint32_t) prev_app_time - ref_time;
>      // calc drift (via un-normalised time diff)
>      int32_t delta = dc_diff_ns - prev_dc_diff_ns;
>      prev_dc_diff_ns = dc_diff_ns;
>
>
>      dc_diff_ns =
>          ((dc_diff_ns + (cycle_ns_ / 2)) % cycle_ns_) - (cycle_ns_ / 2);
>
> }
>
>
> #define TIMESPEC_ADD_NS(TS, NS)\
>      (TS).tv_nsec += (NS);\
> while ((TS).tv_nsec >= NANOS_PER_SEC) {\
>      (TS).tv_nsec -= NANOS_PER_SEC;\
>      (TS).tv_sec++;
> }
>
> #define TIMESPEC2NSEPOCH2000(T)\
>      ((uint64_t)(((T).tv_sec - 946684800 ULL) * 1000000000 ULL) + (T).tv_nsec)
>
> # define TON struct timespec# define TON_ENDTIME(MS)\
> time_add_ns((MS) * NANOS_PER_MILLISEC)
>
>
> static TON clockSyncTon_;
>
>
> int
> TON_ISDONE(struct timespec ts) {
>      struct timespec now;
>      clock_gettime(CLOCK_MONOTONIC, & now);
>      if (now.tv_sec > ts.tv_sec)
>          return 1;
>      else if (now.tv_sec == ts.tv_sec && now.tv_nsec >= ts.tv_nsec)
>          return 1;
>      else
>          return 0;
> }
>
>
> static bool
> wait_period(RtaiMain * inst) {
>
>      int rc;
>      bool done = false;
>      while (!done && inst - > doScan && runAll_) {
>          rc = clock_nanosleep(CLOCK_MONOTONIC,
>              TIMER_ABSTIME, & inst - > wakeupTime,
>              NULL);
>
>
>          if (rc == EFAULT) {
>              return false;
>          } else if (rc == EINTR) {
>              continue;
>          } else if (rc == EINVAL) {
>              return false;
>          } else {
>              done = 1;
>          }
>      }
>      TIMESPEC_ADD_NS(inst->wakeupTime,
> 	inst->cycleNs + dc_diff_ns );
>      return true;
>
> }
>
>
> static void
> cyclic_task(RtaiMain * inst) {
>
>      clock_gettime(CLOCK_MONOTONIC, & (inst - > wakeupTime));
>      /* start after one second */
>      inst - > wakeupTime.tv_sec++;
>      wait_period(inst);
>      while (runAll_ && inst - > doScan) {
>          //
>          // Trigger Fieldbus RX here.
>          //
>          //
>          ecrt_master_receive(master_);
>
>          // record the time we received the data so other parts of the program
>          // have an accurate time reading
>          globalTickTimeNs = ton_get_ns();
>
>          ecrt_domain_process(lrwDomainMgr_.domain);
>          ecrt_domain_process(noLrwWriteDomainMgr_.domain);
>          ecrt_domain_process(noLrwReadDomainMgr_.domain);
>
>          if (counter_) {
>
>              counter_—;
>          } else {
>              counter_ = 4000;
>
>              // check for master state
>              check_master_state();
>          }
>
>
>>          tick sub systems
>
>
>          //
>          // Trigger Fieldbus TX. This should be the last step
>          //
>          //
>          ecrt_domain_queue(lrwDomainMgr_.domain);
>          ecrt_domain_queue(noLrwWriteDomainMgr_.domain);
>          ecrt_domain_queue(noLrwReadDomainMgr_.domain);
>          clock_gettime(CLOCK_REALTIME, & dcTime_);
>          ecrt_master_application_time(
>              master_,
>              TIMESPEC2NSEPOCH2000(dcTime_));
>
>
>          if (TON_ISDONE(clockSyncTon_)) {
>              ecrt_master_sync_reference_clock(master_);
>              clockSyncTon_ = TON_ENDTIME(10); // milliseconds
>          }
>          ecrt_master_sync_slave_clocks(master_);
>
>          // send EtherCAT data
>          ecrt_master_send(master_);
>
> 	calculateClockDrift();
>
>
>          if (!wait_period(inst)) {
>              PRINT("%s Error with waiting! Stopping cyclic_task.\n",
>                  __FUNCTION__);
>              inst - > doScan = false;
>          }
>      }
>
> }
>



More information about the Etherlab-users mailing list