Re: [etherlab-users] DC questions

2016-06-12 Thread Graeme Foot
Hi,

1) Distributed clocks can work in a couple of ways, but all ways require a 
slave DC master which should be the first DC slave in the network.  Note: some 
slaves can act as a DC time master even though they are not fully DC capable:

a) EtherCAT master is the master clock:
  - The computer is used as the DC master for the entire system.  
ecrt_master_application_time() must be called every cycle to tell the 
EtherLab master what the current PC time is.
  - Call ecrt_master_sync_reference_clock() to tell the slave DC master to sync 
to the EtherLab masters time.
  - Call ecrt_master_sync_slave_clocks() to tell all other DC slaves to sync to 
the slave DC master

b) Slave DC master is the master clock. What I do is:
  - Get the slave DC masters time using ecrt_master_reference_clock_time() and 
sync the EtherLab masters cycle and time to it
  - Call ecrt_master_sync_slave_clocks() to tell all other DC slaves to sync to 
the slave DC master
  - Call ecrt_master_application_time() with the next cycles master time

Note: With option b you need to adjust your masters PC's time by the drift time 
from the slave DC master time and adjust your realtime cycle to suit.  I do 
this by having a wrapper around the time calls to rt_get_time() and use 
rt_sleep_until() (I use RTAI) rather than using a fixed periodic cycle.

Option b is the best, because option a has way too much jitter and the slaves 
find it very hard to synchronise.  Note: option b is the default option used 
via TwinCAT.


2) Yes, call ecrt_master_sync_slave_clocks() every cycle (and 
ecrt_master_application_time() and ecrt_master_reference_clock_time()).  Just 
before the ecrt_master_send() call to reduce jitter.


3) No, only call ecrt_slave_config_dc() on slaves that support DC and are going 
to be used with DC.


Regards,
Graeme.


-Original Message-
From: etherlab-users [mailto:etherlab-users-boun...@etherlab.org] On Behalf Of 
Tommaso
Sent: Friday, 10 June 2016 7:14 p.m.
To: etherlab-users@etherlab.org
Subject: [etherlab-users] DC questions

Good morning,

In the master documentation is reported, in DC section, that the reference 
clock is the one of the first slave that supports this functionality. This 
reference can be synchronized with the master clock.
My questions, based on the 'dc_user' example, are the following:
1 - calling cyclically the function 'ecrt_master_sync_reference_clock()' 
I have that the reference clock is the one of the master? Only for this case is 
useful to call the function 'ecrt_master_application_time()' or I have to call 
it every time I want to use the DC?
2 - the function 'ecrt_master_sync_slave_clocks()' is used for the 
synchronization of all the slave clocks for every reference clock? If I want to 
exploit the DC functionality I have always to call it cyclically?
3 - it makes sense to call 'ecrt_slave_config_dc()' even for slaves which do 
not support the DC functionality, like the EL2004?

Thank you for your help.

Best regards,

Tommaso
___
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users
___
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users


Re: [etherlab-users] DC questions

2016-06-12 Thread Gavin Lambert
Just to try to clarify a little: "DC" is actually two separate but related
features.

The first is distributed time synchronisation, which ensures that the whole
network has an approximately synchronised clock.  This works in one of the
two ways that Graeme indicates in #1 below.  Most "infrastructure" slaves
(bus couplers etc) and "smart" slaves (those with CoE) have a DC clock and
support this kind of synchronisation, even if they don't support the next
one.

The second feature is action synced to that clock -- typically a slave can
be set to capture inputs and/or generate outputs or just do its own internal
processing synched to a specific timestamp (and then repeated cyclicly).
This reduces jitter relative to the EtherCAT communications cycle.  Only a
smaller number of devices support this (typically those that require
precisely timed outputs or that provide input timestamps), but this is what
the ecrt_slave_config_dc() function is for -- all the other functions are
for the first feature instead.

The second feature requires the first, but the first can operate without the
second.

(And of Graeme's examples below, 1a is the method used by the dc_user
sample.  There's some sample code for 1b floating around the newsgroup
archive somewhere.)

> -Original Message-
> From: etherlab-users [mailto:etherlab-users-boun...@etherlab.org] On
Behalf
> Of Graeme Foot
> Sent: Monday, 13 June 2016 10:28
> To: Tommaso ; etherlab-users@etherlab.org
> Subject: Re: [etherlab-users] DC questions
> 
> Hi,
> 
> 1) Distributed clocks can work in a couple of ways, but all ways require a
slave
> DC master which should be the first DC slave in the network.  Note: some
> slaves can act as a DC time master even though they are not fully DC
capable:
> 
> a) EtherCAT master is the master clock:
>   - The computer is used as the DC master for the entire system.
> ecrt_master_application_time() must be called every cycle to tell the
> EtherLab master what the current PC time is.
>   - Call ecrt_master_sync_reference_clock() to tell the slave DC master to
sync
> to the EtherLab masters time.
>   - Call ecrt_master_sync_slave_clocks() to tell all other DC slaves to
sync to the
> slave DC master
> 
> b) Slave DC master is the master clock. What I do is:
>   - Get the slave DC masters time using ecrt_master_reference_clock_time()
> and sync the EtherLab masters cycle and time to it
>   - Call ecrt_master_sync_slave_clocks() to tell all other DC slaves to
sync to the
> slave DC master
>   - Call ecrt_master_application_time() with the next cycles master time
> 
> Note: With option b you need to adjust your masters PC's time by the drift
time
> from the slave DC master time and adjust your realtime cycle to suit.  I
do this
> by having a wrapper around the time calls to rt_get_time() and use
> rt_sleep_until() (I use RTAI) rather than using a fixed periodic cycle.
> 
> Option b is the best, because option a has way too much jitter and the
slaves
> find it very hard to synchronise.  Note: option b is the default option
used via
> TwinCAT.
> 
> 
> 2) Yes, call ecrt_master_sync_slave_clocks() every cycle (and
> ecrt_master_application_time() and ecrt_master_reference_clock_time()).
> Just before the ecrt_master_send() call to reduce jitter.
> 
> 
> 3) No, only call ecrt_slave_config_dc() on slaves that support DC and are
going
> to be used with DC.
> 
> 
> Regards,
> Graeme.
> 
> 
> -Original Message-
> From: etherlab-users [mailto:etherlab-users-boun...@etherlab.org] On
Behalf
> Of Tommaso
> Sent: Friday, 10 June 2016 7:14 p.m.
> To: etherlab-users@etherlab.org
> Subject: [etherlab-users] DC questions
> 
> Good morning,
> 
> In the master documentation is reported, in DC section, that the reference
> clock is the one of the first slave that supports this functionality. This
reference
> can be synchronized with the master clock.
> My questions, based on the 'dc_user' example, are the following:
> 1 - calling cyclically the function 'ecrt_master_sync_reference_clock()'
> I have that the reference clock is the one of the master? Only for this
case is
> useful to call the function 'ecrt_master_application_time()' or I have to
call it
> every time I want to use the DC?
> 2 - the function 'ecrt_master_sync_slave_clocks()' is used for the
> synchronization of all the slave clocks for every reference clock? If I
want to
> exploit the DC functionality I have always to call it cyclically?
> 3 - it makes sense to call 'ecrt_slave_config_dc()' even for slaves which
do not
> support the DC functionality, like the EL2004?
> 
> Thank you for your help.
> 
> Best regards,
> 
> Tommaso

___
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users


Re: [etherlab-users] DC questions

2016-06-20 Thread Graeme Foot
Hi,

Try having a look at:
https://www.mail-archive.com/etherlab-users@etherlab.org/msg02641.html

The post above shows the general flow of my program.


I use RTAI.  Below are the structures and functions I currently use to sync the 
master to the slave reference master.  I think there's also some other versions 
out there in past forum posts.

Some of the structures used:

struct _etherCATModule_s
{
  ...
  ec_master_t*master;   /**< the ethercat master 
reference once attached */
  ecDevice_s *m_dcRefSlave; /**< is there a configured ref 
slave? */
  uint64_tm_dcTimeStart;/**< distributed clock first 
now time */
  uint64_tm_dcTime; /**< distributed clock now time 
*/
  int32_t m_dcDiff; /**< distributed clock master 
to ref slave diff time */
  bool_t  m_getDCDiff;  /**< we are ready to get the 
distributed clock diff time */
  ...
};

/** the global application data structure
*/
typedef struct _app_s
{
  ...
  uint64_t  scanTimeNS;  /**< the amount of time per 
scan in nanoseconds */
  uint64_t  scanTimeMS;  /**< the amount of time per 
scan in milliseconds */
  doublescanTimeSec; /**< the amount of time per 
scan in seconds */

  int32_t   rtTimeDiff;  /**< master time source time 
diff (ns) */
  int32_t   rtTimeDelta; /**< master time source time 
diff delta (ns) */
  uint64_t  rtTimeStart; /**< master time source time 
base start (ns) */
  uint64_t  rtTimeCurr;  /**< master time source time 
base current (ns) */
  int64_t   rtAdjBy; /**< master time source cycle 
adjustment value (ns) */

  uint64_t  nextWakeTime;/**< next cycle wake time time 
(ns) */
  uint64_t  actualWakeTime;  /**< actual cycle wake time 
(ns) */
  uint64_t  overruns;/**< the number of overruns 
that have occured */
  ...
} app_s;


When preparing to run:

  intecRes;
  ec_slave_config_t *refSlaveConfig = NULL;

  // set up distributed clocks
  ecMod->m_dcTimeStart = app_getTimeNS();
  ecMod->m_dcTime  = ecMod->m_dcTimeStart;

  if (ecMod->m_dcRefSlave)
  {
refSlaveConfig = ecMod->m_dcRefSlave->slaveConfig;
  }

  // set initial app time (time must be in phase with realtime cycle)
  ecrt_master_application_time(ecMod->master, ecMod->m_dcTimeStart);

  // select the slave device to be the reference clock
  ecRes = ecrt_master_select_reference_clock(ecMod->master, refSlaveConfig);
  if (ecRes < 0) return E_EC_ACTIVATE_ERROR;

  // activate the master
  ecRes = ecrt_master_activate(ecMod->master);
  if (ecRes < 0) return E_EC_ACTIVATE_ERROR;


The "sync distributed clock" function is something like:

int32_t ecMod_syncDistClock(
void *this/**< pointer to module etherCATModule_s */
)
{
  etherCATModule_s *ecMod = this;
  uint32_t  masterTime;

  // cache lower 32 bits of prev master time and get now
  masterTime  = (uint32_t)ecMod->m_dcTime;
  ecMod->m_dcTime = app_getTimeNS();


  // use the dc ref slave to adjust the masters time base

  // get lower 32 bit of clock time from reference slave (after first scan)
  if (ecMod->m_getDCDiff)
  {
int  res;
uint32_t slaveTime;
res = ecrt_master_reference_clock_time(ecMod->master, &slaveTime);

switch (res)
{
  case 0 :
  {
// calc time diff
ecMod->m_dcDiff = masterTime - slaveTime;
  } break;

  default :
  {
// no ref clock found or datagram failure
ecMod->m_dcDiff = 0;
  }
}
  }
  else
  {
ecMod->m_dcDiff= 0;
ecMod->m_getDCDiff = true;
  }

  // call to sync slaves to ref slave
  // (which is used for ecrt_master_reference_clock_time)
  ecrt_master_sync_slave_clocks(ecMod->master);

  // update the master time for the next cycle (in nano-seconds)
  // (this is required for the master to figure out the modules initial
  //  dc time)
  ecrt_master_application_time(ecMod->master, ecMod->m_dcTime + 
g_app.scanTimeNS);


  return 0;
}



The "calc slave to master time drift and adjust master clock and cycle period to
match" function is:

#define DC_FILTER_CNT 1024

static bool_t   u_dcStarted = false;
static int32_t  u_dcLastDiff = 0;
static int64_t  u_dcDiffTot = 0LL;
static int64_t  u_dcDeltaTot = 0LL;
static int  u_dcIdx = 0;

/** update the master time based on ref slaves time diff
*
 * called after the ethercat frame is sent to avoid time jitter in
* ecMod_syncDistClock()
*/
int32_t ecMod_updateMasterClock(
void *this/**< pointer to module module_s */
)
{
  etherCATModule_s *ecMod = this;

  assert(ecMod->master);


  if (u_dcStarted)
  {
// calc drift (via un-normalised time diff)