[etherlab-users] Distributed Clocks

Thomas Bitsky Jr tbj at automateddesign.com
Thu Mar 3 17:08:31 CET 2016


[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