ethercatdc.c
Go to the documentation of this file.
1 /*
2  * Licensed under the GNU General Public License version 2 with exceptions. See
3  * LICENSE file in the project root for full license information
4  */
5 
11 #include "oshw.h"
12 #include "osal.h"
13 #include "ethercattype.h"
14 #include "ethercatbase.h"
15 #include "ethercatmain.h"
16 #include "ethercatdc.h"
17 
18 #define PORTM0 0x01
19 #define PORTM1 0x02
20 #define PORTM2 0x04
21 #define PORTM3 0x08
22 
24 #define SyncDelay ((int32)100000000)
25 
35 void ecx_dcsync0(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, int32 CyclShift)
36 {
37  uint8 h, RA;
38  uint16 slaveh;
39  int64 t, t1;
40  int32 tc;
41 
42  slaveh = context->slavelist[slave].configadr;
43  RA = 0;
44 
45  /* stop cyclic operation, ready for next trigger */
46  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET);
47  if (act)
48  {
49  RA = 1 + 2; /* act cyclic operation and sync0, sync1 deactivated */
50  }
51  h = 0;
52  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCUC, sizeof(h), &h, EC_TIMEOUTRET); /* write access to ethercat */
53  t1 = 0;
54  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSYSTIME, sizeof(t1), &t1, EC_TIMEOUTRET); /* read local time of slave */
55  t1 = etohll(t1);
56 
57  /* Calculate first trigger time, always a whole multiple of CyclTime rounded up
58  plus the shifttime (can be negative)
59  This insures best synchronization between slaves, slaves with the same CyclTime
60  will sync at the same moment (you can use CyclShift to shift the sync) */
61  if (CyclTime > 0)
62  {
63  t = ((t1 + SyncDelay) / CyclTime) * CyclTime + CyclTime + CyclShift;
64  }
65  else
66  {
67  t = t1 + SyncDelay + CyclShift;
68  /* first trigger at T1 + CyclTime + SyncDelay + CyclShift in ns */
69  }
70  t = htoell(t);
71  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSTART0, sizeof(t), &t, EC_TIMEOUTRET); /* SYNC0 start time */
72  tc = htoel(CyclTime);
73  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCYCLE0, sizeof(tc), &tc, EC_TIMEOUTRET); /* SYNC0 cycle time */
74  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET); /* activate cyclic operation */
75 
76  // update ec_slave state
77  context->slavelist[slave].DCactive = (uint8)act;
78  context->slavelist[slave].DCshift = CyclShift;
79  context->slavelist[slave].DCcycle = CyclTime;
80 }
81 
94 void ecx_dcsync01(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, int32 CyclShift)
95 {
96  uint8 h, RA;
97  uint16 slaveh;
98  int64 t, t1;
99  int32 tc;
100  uint32 TrueCyclTime;
101 
102  /* Sync1 can be used as a multiple of Sync0, use true cycle time */
103  TrueCyclTime = ((CyclTime1 / CyclTime0) + 1) * CyclTime0;
104 
105  slaveh = context->slavelist[slave].configadr;
106  RA = 0;
107 
108  /* stop cyclic operation, ready for next trigger */
109  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET);
110  if (act)
111  {
112  RA = 1 + 2 + 4; /* act cyclic operation and sync0 + sync1 */
113  }
114  h = 0;
115  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCUC, sizeof(h), &h, EC_TIMEOUTRET); /* write access to ethercat */
116  t1 = 0;
117  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSYSTIME, sizeof(t1), &t1, EC_TIMEOUTRET); /* read local time of slave */
118  t1 = etohll(t1);
119 
120  /* Calculate first trigger time, always a whole multiple of TrueCyclTime rounded up
121  plus the shifttime (can be negative)
122  This insures best synchronization between slaves, slaves with the same CyclTime
123  will sync at the same moment (you can use CyclShift to shift the sync) */
124  if (CyclTime0 > 0)
125  {
126  t = ((t1 + SyncDelay) / TrueCyclTime) * TrueCyclTime + TrueCyclTime + CyclShift;
127  }
128  else
129  {
130  t = t1 + SyncDelay + CyclShift;
131  /* first trigger at T1 + CyclTime + SyncDelay + CyclShift in ns */
132  }
133  t = htoell(t);
134  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSTART0, sizeof(t), &t, EC_TIMEOUTRET); /* SYNC0 start time */
135  tc = htoel(CyclTime0);
136  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCYCLE0, sizeof(tc), &tc, EC_TIMEOUTRET); /* SYNC0 cycle time */
137  tc = htoel(CyclTime1);
138  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCYCLE1, sizeof(tc), &tc, EC_TIMEOUTRET); /* SYNC1 cycle time */
139  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET); /* activate cyclic operation */
140 
141  // update ec_slave state
142  context->slavelist[slave].DCactive = (uint8)act;
143  context->slavelist[slave].DCshift = CyclShift;
144  context->slavelist[slave].DCcycle = CyclTime0;
145 }
146 
147 /* latched port time of slave */
149 {
150  int32 ts;
151  switch (port)
152  {
153  case 0:
154  ts = context->slavelist[slave].DCrtA;
155  break;
156  case 1:
157  ts = context->slavelist[slave].DCrtB;
158  break;
159  case 2:
160  ts = context->slavelist[slave].DCrtC;
161  break;
162  case 3:
163  ts = context->slavelist[slave].DCrtD;
164  break;
165  default:
166  ts = 0;
167  break;
168  }
169  return ts;
170 }
171 
172 /* calculate previous active port of a slave */
174 {
175  uint8 pport = port;
176  uint8 aport = context->slavelist[slave].activeports;
177  switch(port)
178  {
179  case 0:
180  if(aport & PORTM2)
181  pport = 2;
182  else if (aport & PORTM1)
183  pport = 1;
184  else if (aport & PORTM3)
185  pport = 3;
186  break;
187  case 1:
188  if(aport & PORTM3)
189  pport = 3;
190  else if (aport & PORTM0)
191  pport = 0;
192  else if (aport & PORTM2)
193  pport = 2;
194  break;
195  case 2:
196  if(aport & PORTM1)
197  pport = 1;
198  else if (aport & PORTM3)
199  pport = 3;
200  else if (aport & PORTM0)
201  pport = 0;
202  break;
203  case 3:
204  if(aport & PORTM0)
205  pport = 0;
206  else if (aport & PORTM2)
207  pport = 2;
208  else if (aport & PORTM1)
209  pport = 1;
210  break;
211  }
212  return pport;
213 }
214 
215 /* search unconsumed ports in parent, consume and return first open port */
216 static uint8 ecx_parentport(ecx_contextt *context, uint16 parent)
217 {
218  uint8 parentport = 0;
219  uint8 b;
220  /* search order is important, here 3 - 1 - 2 - 0 */
221  b = context->slavelist[parent].consumedports;
222  if (b & PORTM3)
223  {
224  parentport = 3;
225  b &= (uint8)~PORTM3;
226  }
227  else if (b & PORTM1)
228  {
229  parentport = 1;
230  b &= (uint8)~PORTM1;
231  }
232  else if (b & PORTM2)
233  {
234  parentport = 2;
235  b &= (uint8)~PORTM2;
236  }
237  else if (b & PORTM0)
238  {
239  parentport = 0;
240  b &= (uint8)~PORTM0;
241  }
242  context->slavelist[parent].consumedports = b;
243  return parentport;
244 }
245 
252 boolean ecx_configdc(ecx_contextt *context)
253 {
254  uint16 i, slaveh, parent, child;
255  uint16 parenthold = 0;
256  uint16 prevDCslave = 0;
257  int32 ht, dt1, dt2, dt3;
258  int64 hrt;
259  uint8 entryport;
260  int8 nlist;
261  int8 plist[4];
262  int32 tlist[4];
263  ec_timet mastertime;
264  uint64 mastertime64;
265 
266  context->slavelist[0].hasdc = FALSE;
267  context->grouplist[0].hasdc = FALSE;
268  ht = 0;
269 
270  ecx_BWR(context->port, 0, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET); /* latch DCrecvTimeA of all slaves */
271  mastertime = osal_current_time();
272  mastertime.sec -= 946684800UL; /* EtherCAT uses 2000-01-01 as epoch start instead of 1970-01-01 */
273  mastertime64 = (((uint64)mastertime.sec * 1000000) + (uint64)mastertime.usec) * 1000;
274  for (i = 1; i <= *(context->slavecount); i++)
275  {
276  context->slavelist[i].consumedports = context->slavelist[i].activeports;
277  if (context->slavelist[i].hasdc)
278  {
279  if (!context->slavelist[0].hasdc)
280  {
281  context->slavelist[0].hasdc = TRUE;
282  context->slavelist[0].DCnext = i;
283  context->slavelist[i].DCprevious = 0;
284  context->grouplist[context->slavelist[i].group].hasdc = TRUE;
285  context->grouplist[context->slavelist[i].group].DCnext = i;
286  }
287  else
288  {
289  context->slavelist[prevDCslave].DCnext = i;
290  context->slavelist[i].DCprevious = prevDCslave;
291  }
292  /* this branch has DC slave so remove parenthold */
293  parenthold = 0;
294  prevDCslave = i;
295  slaveh = context->slavelist[i].configadr;
296  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET);
297  context->slavelist[i].DCrtA = etohl(ht);
298  /* 64bit latched DCrecvTimeA of each specific slave */
299  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSOF, sizeof(hrt), &hrt, EC_TIMEOUTRET);
300  /* use it as offset in order to set local time around 0 + mastertime */
301  hrt = htoell(-etohll(hrt) + mastertime64);
302  /* save it in the offset register */
303  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSOFFSET, sizeof(hrt), &hrt, EC_TIMEOUTRET);
304  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME1, sizeof(ht), &ht, EC_TIMEOUTRET);
305  context->slavelist[i].DCrtB = etohl(ht);
306  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME2, sizeof(ht), &ht, EC_TIMEOUTRET);
307  context->slavelist[i].DCrtC = etohl(ht);
308  (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME3, sizeof(ht), &ht, EC_TIMEOUTRET);
309  context->slavelist[i].DCrtD = etohl(ht);
310 
311  /* make list of active ports and their time stamps */
312  nlist = 0;
313  if (context->slavelist[i].activeports & PORTM0)
314  {
315  plist[nlist] = 0;
316  tlist[nlist] = context->slavelist[i].DCrtA;
317  nlist++;
318  }
319  if (context->slavelist[i].activeports & PORTM3)
320  {
321  plist[nlist] = 3;
322  tlist[nlist] = context->slavelist[i].DCrtD;
323  nlist++;
324  }
325  if (context->slavelist[i].activeports & PORTM1)
326  {
327  plist[nlist] = 1;
328  tlist[nlist] = context->slavelist[i].DCrtB;
329  nlist++;
330  }
331  if (context->slavelist[i].activeports & PORTM2)
332  {
333  plist[nlist] = 2;
334  tlist[nlist] = context->slavelist[i].DCrtC;
335  nlist++;
336  }
337  /* entryport is port with the lowest timestamp */
338  entryport = 0;
339  if((nlist > 1) && (tlist[1] < tlist[entryport]))
340  {
341  entryport = 1;
342  }
343  if((nlist > 2) && (tlist[2] < tlist[entryport]))
344  {
345  entryport = 2;
346  }
347  if((nlist > 3) && (tlist[3] < tlist[entryport]))
348  {
349  entryport = 3;
350  }
351  entryport = plist[entryport];
352  context->slavelist[i].entryport = entryport;
353  /* consume entryport from activeports */
354  context->slavelist[i].consumedports &= (uint8)~(1 << entryport);
355 
356  /* finding DC parent of current */
357  parent = i;
358  do
359  {
360  child = parent;
361  parent = context->slavelist[parent].parent;
362  }
363  while (!((parent == 0) || (context->slavelist[parent].hasdc)));
364  /* only calculate propagation delay if slave is not the first */
365  if (parent > 0)
366  {
367  /* find port on parent this slave is connected to */
368  context->slavelist[i].parentport = ecx_parentport(context, parent);
369  if (context->slavelist[parent].topology == 1)
370  {
371  context->slavelist[i].parentport = context->slavelist[parent].entryport;
372  }
373 
374  dt1 = 0;
375  dt2 = 0;
376  /* delta time of (parentport - 1) - parentport */
377  /* note: order of ports is 0 - 3 - 1 -2 */
378  /* non active ports are skipped */
379  dt3 = ecx_porttime(context, parent, context->slavelist[i].parentport) -
380  ecx_porttime(context, parent,
381  ecx_prevport(context, parent, context->slavelist[i].parentport));
382  /* current slave has children */
383  /* those children's delays need to be subtracted */
384  if (context->slavelist[i].topology > 1)
385  {
386  dt1 = ecx_porttime(context, i,
387  ecx_prevport(context, i, context->slavelist[i].entryport)) -
388  ecx_porttime(context, i, context->slavelist[i].entryport);
389  }
390  /* we are only interested in positive difference */
391  if (dt1 > dt3) dt1 = -dt1;
392  /* current slave is not the first child of parent */
393  /* previous child's delays need to be added */
394  if ((child - parent) > 1)
395  {
396  dt2 = ecx_porttime(context, parent,
397  ecx_prevport(context, parent, context->slavelist[i].parentport)) -
398  ecx_porttime(context, parent, context->slavelist[parent].entryport);
399  }
400  if (dt2 < 0) dt2 = -dt2;
401 
402  /* calculate current slave delay from delta times */
403  /* assumption : forward delay equals return delay */
404  context->slavelist[i].pdelay = ((dt3 - dt1) / 2) + dt2 +
405  context->slavelist[parent].pdelay;
406  ht = htoel(context->slavelist[i].pdelay);
407  /* write propagation delay*/
408  (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSDELAY, sizeof(ht), &ht, EC_TIMEOUTRET);
409  }
410  }
411  else
412  {
413  context->slavelist[i].DCrtA = 0;
414  context->slavelist[i].DCrtB = 0;
415  context->slavelist[i].DCrtC = 0;
416  context->slavelist[i].DCrtD = 0;
417  parent = context->slavelist[i].parent;
418  /* if non DC slave found on first position on branch hold root parent */
419  if ( (parent > 0) && (context->slavelist[parent].topology > 2))
420  parenthold = parent;
421  /* if branch has no DC slaves consume port on root parent */
422  if ( parenthold && (context->slavelist[i].topology == 1))
423  {
424  ecx_parentport(context, parenthold);
425  parenthold = 0;
426  }
427  }
428  }
429 
430  return context->slavelist[0].hasdc;
431 }
432 
433 #ifdef EC_VER1
434 void ec_dcsync0(uint16 slave, boolean act, uint32 CyclTime, int32 CyclShift)
435 {
436  ecx_dcsync0(&ecx_context, slave, act, CyclTime, CyclShift);
437 }
438 
439 void ec_dcsync01(uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, int32 CyclShift)
440 {
441  ecx_dcsync01(&ecx_context, slave, act, CyclTime0, CyclTime1, CyclShift);
442 }
443 
444 boolean ec_configdc(void)
445 {
446  return ecx_configdc(&ecx_context);
447 }
448 #endif
static int32 ecx_porttime(ecx_contextt *context, uint16 slave, uint8 port)
Definition: ethercatdc.c:148
int32 DCrtC
Definition: ethercatmain.h:189
Headerfile for ethercatdc.c.
uint8 entryport
Definition: ethercatmain.h:183
void ec_dcsync0(uint16 slave, boolean act, uint32 CyclTime, int32 CyclShift)
Definition: ethercatdc.c:434
uint8 DCactive
Definition: ethercatmain.h:203
uint8 topology
Definition: ethercatmain.h:173
#define htoel(A)
Definition: ethercattype.h:534
uint8 consumedports
Definition: ethercatmain.h:177
#define PORTM3
Definition: ethercatdc.c:21
uint8_t uint8
Definition: osal.h:28
uint32 usec
Definition: osal.h:39
void ecx_dcsync0(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, int32 CyclShift)
Definition: ethercatdc.c:35
int ecx_FPWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
Definition: ethercatbase.c:399
#define PORTM2
Definition: ethercatdc.c:20
int32 DCshift
Definition: ethercatmain.h:201
uint16_t uint16
Definition: osal.h:29
uint8 group
Definition: ethercatmain.h:225
int32 DCrtA
Definition: ethercatmain.h:185
General typedefs and defines for EtherCAT.
uint16 parent
Definition: ethercatmain.h:179
#define TRUE
Definition: osal.h:19
int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
Definition: ethercatbase.c:318
boolean hasdc
Definition: ethercatmain.h:252
int32 DCrtB
Definition: ethercatmain.h:187
void ecx_dcsync01(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, int32 CyclShift)
Definition: ethercatdc.c:94
ecx_portt * port
Definition: ethercatmain.h:387
ec_groupt * grouplist
Definition: ethercatmain.h:395
ec_timet osal_current_time(void)
Definition: erika/osal.c:37
Definition: osal.h:36
uint16 configadr
Definition: ethercatmain.h:113
int32 pdelay
Definition: ethercatmain.h:193
int slave
Definition: aliastool.c:44
int64_t int64
Definition: osal.h:31
#define FALSE
Definition: osal.h:22
uint8 parentport
Definition: ethercatmain.h:181
int32_t int32
Definition: osal.h:27
int ecx_BWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
Definition: ethercatbase.c:158
int8_t int8
Definition: osal.h:25
static uint8 ecx_parentport(ecx_contextt *context, uint16 parent)
Definition: ethercatdc.c:216
#define htoell(A)
Definition: ethercattype.h:535
#define PORTM1
Definition: ethercatdc.c:19
uint64_t uint64
Definition: osal.h:32
void ec_dcsync01(uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, int32 CyclShift)
Definition: ethercatdc.c:439
#define EC_TIMEOUTRET
Definition: ethercattype.h:64
static uint8 ecx_prevport(ecx_contextt *context, uint16 slave, uint8 port)
Definition: ethercatdc.c:173
boolean ecx_configdc(ecx_contextt *context)
Definition: ethercatdc.c:252
Headerfile for ethercatbase.c.
boolean ec_configdc(void)
Definition: ethercatdc.c:444
uint8 activeports
Definition: ethercatmain.h:175
#define etohl(A)
Definition: ethercattype.h:537
#define etohll(A)
Definition: ethercattype.h:538
Headerfile for ethercatmain.c.
uint32 sec
Definition: osal.h:38
uint32_t uint32
Definition: osal.h:30
boolean hasdc
Definition: ethercatmain.h:169
#define SyncDelay
Definition: ethercatdc.c:24
uint16 DCprevious
Definition: ethercatmain.h:197
uint16 DCnext
Definition: ethercatmain.h:254
uint16 DCnext
Definition: ethercatmain.h:195
ec_slavet * slavelist
Definition: ethercatmain.h:389
int32 DCcycle
Definition: ethercatmain.h:199
int32 DCrtD
Definition: ethercatmain.h:191
int * slavecount
Definition: ethercatmain.h:391
#define PORTM0
Definition: ethercatdc.c:18


soem
Author(s): Arthur Ketels and M.J.G. van den Molengraft
autogenerated on Sat Jun 27 2020 03:48:20