<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;
mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:#0563C1;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:#954F72;
text-decoration:underline;}
p.MsoPlainText, li.MsoPlainText, div.MsoPlainText
{mso-style-priority:99;
mso-style-link:"Plain Text Char";
margin:0cm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;
mso-fareast-language:EN-US;}
span.PlainTextChar
{mso-style-name:"Plain Text Char";
mso-style-priority:99;
mso-style-link:"Plain Text";
font-family:"Calibri",sans-serif;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri",sans-serif;
mso-fareast-language:EN-US;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-NZ" link="#0563C1" vlink="#954F72">
<div class="WordSection1">
<p class="MsoPlainText">Hi,<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Firstly, there is no way of checking if the frame transfer is complete.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">One comment, to reduce the jitter and offset of the master application time, place the clock_gettime(), ecrt_master_application_time(), ecrt_master_sync_reference_clock(), ecrt_master_sync_slave_clocks() calls after ecrt_domain_queue()
(and before ecrt_master_send()).<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">It doesn't matter how long "do a lot of stuff" takes as long as the application time is set just before the send and your cycle start time is in sync with the initial call to ecrt_master_application_time().<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Traditional cycle:<o:p></o:p></p>
<p class="MsoPlainText">- master receive<o:p></o:p></p>
<p class="MsoPlainText">- domain process<o:p></o:p></p>
<p class="MsoPlainText">- perform application calcs<o:p></o:p></p>
<p class="MsoPlainText">- domain queue<o:p></o:p></p>
<p class="MsoPlainText">- dc sync<o:p></o:p></p>
<p class="MsoPlainText">- master send<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">-> as long as the time to master send and the time on the wire is shorter than sync0 offset then you are all good.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Alternate option:<o:p></o:p></p>
<p class="MsoPlainText">- cycle time 0, wakeup<o:p></o:p></p>
<p class="MsoPlainText">- domain queue<o:p></o:p></p>
<p class="MsoPlainText">- dc sync<o:p></o:p></p>
<p class="MsoPlainText">- master send<o:p></o:p></p>
<p class="MsoPlainText">- sleep for data over wire time<o:p></o:p></p>
<p class="MsoPlainText">- wakeup<o:p></o:p></p>
<p class="MsoPlainText">- master receive<o:p></o:p></p>
<p class="MsoPlainText">- domain process<o:p></o:p></p>
<p class="MsoPlainText">- perform application calcs<o:p></o:p></p>
<p class="MsoPlainText">- sleep<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">-> you need to determine the appropriate sleep time between the master send and receive to allow for software overhead and time on the wire.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Note: You can guess a time on the wire by using the "ethercat slaves -v" command. Look up the "DC system time transmission delay" on your last slave and double it.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">I do something a little different. My cycle:<o:p></o:p></p>
<p class="MsoPlainText">- master receive<o:p></o:p></p>
<p class="MsoPlainText">- domain process<o:p></o:p></p>
<p class="MsoPlainText">- <b>write cached PDO values</b><o:p></o:p></p>
<p class="MsoPlainText">- domain queue<o:p></o:p></p>
<p class="MsoPlainText">- dc sync<o:p></o:p></p>
<p class="MsoPlainText">- master send<o:p></o:p></p>
<p class="MsoPlainText">- <b>perform application calcs (writes to PDO data is cached)</b><o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">This has the advantage of a very short turnaround with minimal jitter between the receive and send. It allows nearly a whole cycle for the data to be on the wire. It also allows for up to the remainder of that cycle to be used for
application calculations, in parallel to the data being on the wire. The drawbacks are:<o:p></o:p></p>
<p class="MsoPlainText">- The domain process step will overwrite any PDO data changes you have made while performing your application calcs, so you need to cache your changes somewhere else then apply them after the domain process step<o:p></o:p></p>
<p class="MsoPlainText">- You add 1 extra cycle delay for the PDO data being read.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">However, your cycle time can generally also be reduced by an amount since the "app calc time" and "data on the wire time" are now in parallel.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">The traditional cycle takes around three cycles between writing data and receiving its results (3 * 1ms = 3ms turnaround)<o:p></o:p></p>
<p class="MsoPlainText">My cycle can often be reduced to at least ½ of the traditional cycle. Even though it has the extra cycle overhead it still has a better turnaround (4 * 0.5ms = 2ms turnaround)<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">I personally don't reduce my cycle time (I keep it at 1ms) as I'm happy at the extra cycle delay and some of our controllers can have quite a large calculation overhead.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Just some info on timing from one of our controllers (around 55 slaves)<o:p></o:p></p>
<p class="MsoPlainText">- 30us to perform master receive through to master send<o:p></o:p></p>
<p class="MsoPlainText">- 150us to perform application calcs<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">One last comment. Assuming a linear topology, the EtherCAT frames are sent out through all of the slaves and once it reaches the last slave it returns through all of the slaves. It should take a similar time between outgoing and returning.
Only the outgoing data needs to arrive before the Sync0 event. So with my method you can allow nearly the whole cycle for the data to be on the wire as long as your Sync0 events are configured to be after the cycle half time. If it's not a linear topology,
this does not apply.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Regards,<o:p></o:p></p>
<p class="MsoPlainText">Graeme.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">-----Original Message-----<o:p></o:p></p>
<p class="MsoPlainText">From: etherlab-users [mailto:etherlab-users-bounces@etherlab.org] On Behalf Of Michael Ruder<o:p></o:p></p>
<p class="MsoPlainText">Sent: Wednesday, 16 May 2018 4:34 AM<o:p></o:p></p>
<p class="MsoPlainText">To: etherlab-users@etherlab.org<o:p></o:p></p>
<p class="MsoPlainText">Subject: [etherlab-users] How to perform DC time synchronisation the right way?<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Hello,<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">I am progressing quite well with EtherLab and am currently working on synchronizing outputs/movement with the Master time. We are using the Master 1.5.2 from the 1.5.2 branch, ec_generic driver with PREEMPT RT (kernel 4.14.28).<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">In our application, we need to be synchronized to the real time (UTC). We use a GPS receiver and Chrony to synchronize our PC clock to within a few microseconds.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Now I want to have the slaves also synchronized to this time frame and have the following dilemma:<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">- normally, I would like to call<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// cycle begins<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">ecrt_master_receive(master);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_domain_process(domain1);<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// do a lot of stuff<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">clock_gettime(CLOCK_REALTIME, &time);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_master_application_time(master, ((time.tv_sec - 946684800ULL) * 1000000000ULL + time.tv_nsec));<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">ecrt_master_sync_reference_clock(master);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_master_sync_slave_clocks(master);<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">ecrt_domain_queue(domain1);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_master_send(master);<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// cycle ends, wait for next cycle<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">However, as the "lot of stuff" takes different amounts of time, this seems to be not good, as this means a few hundred microseconds jitter as to when the application time is set in our (1 ms long) cycle.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">- therefore, I could call it that way:<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// cycle begins<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">clock_gettime(CLOCK_REALTIME, &time);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_master_application_time(master, ((time.tv_sec - 946684800ULL) * 1000000000ULL + time.tv_nsec));<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">ecrt_master_sync_reference_clock(master);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_master_sync_slave_clocks(master);<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">ecrt_domain_queue(domain1);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_master_send(master);<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// wait for frame transfer to complete<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">ecrt_master_receive(master);<o:p></o:p></p>
<p class="MsoPlainText">ecrt_domain_process(domain1);<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// do a lot of stuff<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">// cycle ends, wait for next cycle<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">This removes the jitter and I could also cope with the updated domain data being sent at the begin of the next cycle somehow. However, the problematic part is the "wait for frame transfer to complete". There seems to be no way to actually
know when this has happened. Also, I experienced stable operation with a low as 50 us, while sometimes 200 us is needed to avoid "datagram UNMATCHED" messages and a short drop out of OP (working counter going to 0 for a moment).<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">From what I read, there seems to be not a single good solution to this, or am I overlooking something?<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Is there any way of actually checking if the frame transfer is complete?
<o:p></o:p></p>
<p class="MsoPlainText">As I am in a realtime cycle, I could then busywait instead of using a fixed (probably rather large) delay.<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Or can I still use the first solution? I am a bit afraid of it, as it is mentioned that the SYNC0 timing will be in phase with the first call to this function.
<o:p></o:p></p>
<p class="MsoPlainText"><o:p> </o:p></p>
<p class="MsoPlainText">Thanks for your help!<o:p></o:p></p>
<p class="MsoPlainText">-- <o:p></o:p></p>
<p class="MsoPlainText">. -Michael<o:p></o:p></p>
<p class="MsoPlainText">_______________________________________________<o:p></o:p></p>
<p class="MsoPlainText">etherlab-users mailing list<o:p></o:p></p>
<p class="MsoPlainText">etherlab-users@etherlab.org<o:p></o:p></p>
<p class="MsoPlainText">http://lists.etherlab.org/mailman/listinfo/etherlab-users<o:p></o:p></p>
</div>
</body>
</html>