Richard, I put a lot of time into your suggestions the past few days, and here is where I’m at.
[snip]
we use CLOCK_MONOTONIC for ecrt_master_application_time(), in fact we
use it thoughout. Probably not the solution, but worth a try.
[/snip]
As I generally do; thanks for catching that error for me.
[snip]
Once your cyclic test is stable (~10us max jitter), you may start
looking for delays in your code.
[/snip]
Semaphore and mutex calls were waking up inconsistently (the rt tests reported
the same thing). I re-designed the API to eliminate the need for them in my
code. I also reduced the memory footprint. Send, recv and timespec functions
are the only system calls remaining.
This brought the rest of the program down to very little execution time. I went
through function by function, but couldn’t find the reason for the long
execution times in my cleaned up code.
However, I still have a surprisingly long execution time. The functions that
cause the problem are from the ethercat master library.
ecrt_master_receive(master_);
ecrt_domain_process(lrwDomainMgr_.domain);
ecrt_domain_process(noLrwWriteDomainMgr_.domain);
ecrt_domain_process(noLrwReadDomainMgr_.domain);
I have tried this on two pieces of hardware. They run the same operating system
and configuration, same EtherLAB master version, same Ethernet driver.
System 1 (Intel i3 NUC, 1 Intel e1000e Ethernet port): exec min 6789 .. max
50345 (nano seconds)
System 2 (Intel quad celeoron, 4 x e1000e Ethernet port): exec min 15588 … max
323376 (nano seconds)
(Both systems: Ubuntu Server 14.04LTS, Linux core 3.12.50-rt68 #1 SMP PREEMPT
RT)
On system 1, the unmatched packets never happen; for whatever reason, those
functions are returning much more rapidly. On the second system, the worst case
happens about once per minute, once every two minutes.
1. Am I unreasonable in thinking these times are excessive? I understand that
the system is communicating out to external hardware and there will be a delay,
but the difference between the two computers is surprising to me.
2. Is this a consequence of using the EtherCAT master from user space? I’ve
always used it from kernel space before. However, I’ve never done as extensive
of timing measurements before. The EtherLAB documentation mentioned that the
userspace library only added 1 microsecond of overhead, if I recall. Is this as
good as it gets from the user space?
3. Is there a way to address this problem, or is it completely dependent upon
the hardware?
Thanks for any insights to the problem, and for all the advice everyone has
submitted this far.
On 3/3/16, 1:59 PM, "Richard Hacker" <[email protected]> wrote:
>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;
>> }
>> }
>>
>> }
>>
<<< text/html; name="default[S7Ry].html": Unrecognized >>>
_______________________________________________ etherlab-users mailing list [email protected] http://lists.etherlab.org/mailman/listinfo/etherlab-users
