<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:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
p.msonormal0, li.msonormal0, div.msonormal0
{mso-style-name:msonormal;
mso-margin-top-alt:auto;
margin-right:0cm;
mso-margin-bottom-alt:auto;
margin-left:0cm;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.EmailStyle18
{mso-style-type:personal;
font-family:"Calibri",sans-serif;
color:windowtext;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:70.85pt 70.85pt 2.0cm 70.85pt;}
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=blue vlink=purple><div class=WordSection1><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'>Actually you typically shouldn’t have Sync0 simultaneous with your communication cycle; that causes problems. The goal is to get it into a locked phase arrangement.<o:p></o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'><o:p> </o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'>Sync0 is typically when the slave’s actions trigger – it asserts outputs and captures inputs ideally both at that precise instant (though there might be some delay if it needs to do one before the other). However there is generally some setup time before Sync0 required (so you have to provide the next cycle’s outputs at least this amount of time before Sync0) and some transfer time after Sync0 required (so you have to wait that long after Sync0 before you can read the inputs). The slave’s documentation should tell you how long each of these times are, and you need to allow a little bit of extra time to cope with jitter on the master’s end and the comms delay of the network itself. If you have no clue, aiming for somewhere in the middle of your sync cycle is usually a fairly safe bet.<o:p></o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'><o:p> </o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'>The most important aspect of the EtherCAT comms cycle is when you call ecrt_master_send. This is what actually sends (and receives back) the datagrams and transfers all data to and from the slaves. Your goal is always to make <b>this</b> call happen consistently with as little latency and jitter as possible. <b>None</b> of the other calls matter in terms of timing.<o:p></o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_reference_clock_time retrieves the 32-bit time of the reference slave as of when you called ecrt_master_send, provided that you called ecrt_master_sync_slave_clocks at some previous point (each cycle).<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_64bit_reference_clock_time retrieves the 64-bit time of the reference slave as of when you called ecrt_master_send, provided that you called ecrt_master_64bit_reference_clock_time_queue at some previous point (each cycle).<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>(In principle doing both ecrt_master_64bit_reference_clock_time_queue and ecrt_master_sync_slave_clocks on every cycle is a bit wasteful. It would be better if you could just do a 64-bit sync, but this is not supported at present. If you’re worried about bandwidth then you should call ecrt_master_sync_slave_clocks on every cycle and ecrt_master_64bit_reference_clock_time_queue only occasionally. You cannot omit calling ecrt_master_sync_slave_clocks.)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>For maximum consistency, you should call ecrt_master_application_time immediately prior to ecrt_master_send. You should also call it on each cycle, although in practice it matters most when it’s doing the slave DC configuration, which will span several cycles across the slaves shortly after activating the master. Also rather than using a monotonically increasing value as it appears you’re using at the moment, I think it’s more typical to use the actual PC clock time, corrected for the offset between the master clock and the reference clock. I’m not sure which is “better” though.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>(Also note that most things work best when you always use the first DC-capable slave as the reference clock, which is the default. If you’re explicitly designating a clock elsewhere on the network then there might be complications.)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>If you are trying to synchronise the reference clock to the master (which you are not; it tends to be less accurate), you also have to call ecrt_master_sync_reference_clock between ecrt_master_application_time and ecrt_master_send. It doesn’t matter when you call ecrt_master_sync_slave_clocks as long as you do it periodically (typically recommended once per cycle, unless you have a really fast cycle time). If you’re using ecrt_master_reference_clock_time then you have to sync slave clocks at least as often as you ask for the time.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_receive can be called at any time after the packets arrive back, which will be shortly after ecrt_master_send (exactly how long depends on your network size) – but it’s most common to use this time to do a proper idle sleep and process it at the start of the next cycle rather than the end of the previous one. That can cause higher jitter if your processing times aren’t consistent, however (unless you have two smaller sleeps rather than one large one), so the way you’re doing it isn’t a bad one. You do have to call it before anything else that uses the results of the datagrams, such as the time calls above.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>If you can hook a scope up to a slave’s SYNC0 and SOF pins (if accessible), that will give you the best idea of how your timing cycle looks.<o:p></o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-NZ'> </span><o:p></o:p></p><div style='border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt'><div><div style='border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal><b><span lang=EN-US style='mso-fareast-language:EN-NZ'>From:</span></b><span lang=EN-US style='mso-fareast-language:EN-NZ'> Matthias Bartsch<br><b>Sent:</b> Friday, 2 February 2018 05:12<br><b>To:</b> etherlab-users@etherlab.org<br><b>Subject:</b> [etherlab-users] Synchronizing the EtherCAT application time to the DC reference clock<o:p></o:p></span></p></div></div><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal style='margin-bottom:12.0pt'><span lang=DE style='font-size:12.0pt'>Hello everybody!<o:p></o:p></span></p><p class=MsoNormal style='margin-bottom:12.0pt'><span lang=EN-GB style='font-size:12.0pt'>I‘m using the unofficial patch set from <a href="https://github.com/ribalda/ethercat">https://github.com/ribalda/ethercat</a> (2017-11-08).<br>My RTAI communication cycle is synchronized to the DC slave reference clock (average jitter < 1µs). I need to extrapolate the position of servo drives to the beginning of my cycle.<br><br>I’m not sure about the right use of the functions for reading the reference clock.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>I want to start my cycle at the time of the “Sync0” interrupt.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>My questions are: When is the time sampled that I get by calling <br> ecrt_master_64bit_reference_clock_time(m_poMaster, &ui64RefClockTime)); ?<br><br>How I have to initialize my application time (first call of “ecrt_master_application_time(…)”)?<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>My synchronisation seems to work but I’m not sure about the phase shift between the Sync0 event and the start of my communication cycle.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>My code looks something like this:<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>In the first real time cycle I call:<br>ecrt_master_application_time(m_poMaster, m_ui64AppTime_ns); // with m_ui64AppTime_ns=0<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_sync_slave_clocks(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_domain_queue(m_po_domainInput);<o:p></o:p></span></p><p class=MsoNormal style='margin-bottom:12.0pt'><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_send(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>// busy wait 25µs for getting the answer<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_receive(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_domain_process(m_po_domainInput);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>//<o:p></o:p></span></p><p class=MsoNormal style='margin-bottom:12.0pt'><span lang=EN-GB style='font-size:12.0pt'>// …. Later sending the output data<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>In the next cycles I do this:<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_receive(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_domain_process(m_po_domainOutput);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_64bit_reference_clock_time_queue(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_domain_queue(m_po_domainInput);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_send(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>// busy wait 25µs for getting the answer<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_receive(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_domain_process(m_po_domainInput);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>uint64_t ui64RefClockTime;<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_64bit_reference_clock_time(m_poMaster, &ui64RefClockTime));<o:p></o:p></span></p><p class=MsoNormal style='margin-bottom:12.0pt'><span lang=EN-GB style='font-size:12.0pt'>m_ui64AppTime_ns += static_cast<uint64_t>((m_io__dNominalCycleTime) * 1e9);<br>ecrt_master_application_time(m_poMaster, m_ui64AppTime_ns);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>m_out_iDcSysTimeDifferenceMaster = m_ui64AppTime_ns - ui64RefClockTime; // Time drift value<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'>ecrt_master_sync_slave_clocks(m_poMaster);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-GB style='font-size:12.0pt;mso-fareast-language:DE'>With kind regards<o:p></o:p></span></p><p class=MsoNormal style='text-autospace:none'><span lang=EN-GB style='font-size:12.0pt;mso-fareast-language:DE'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US style='font-size:12.0pt;mso-fareast-language:DE'>Matthias Bartsch<o:p></o:p></span></p><p class=MsoNormal style='margin-bottom:12.0pt;text-autospace:none'><b><span lang=EN-GB style='mso-fareast-language:DE'>ARADEX AG</span></b><span lang=EN-GB style='mso-fareast-language:DE'> </span><span lang=EN-US style='font-family:"Arial",sans-serif;mso-fareast-language:DE'><o:p></o:p></span></p><p class=MsoNormal><span lang=EN-GB><o:p> </o:p></span></p></div></div></body></html>