<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
</head>
<body text="#000000" bgcolor="#FFFFFF">
Hi, <br>
<br>
I didn't check the codes. But is it OK to have the first device in
the bus a EK1100? <br>
I can't find it now, but a message in this list was telling me
EK1100 does not support DC fully.<br>
The fist node on the bus should be a drive or some other device
which can support DC fully.<br>
<br>
Best regards,<br>
Oguz.<br>
<br>
<div class="moz-cite-prefix">22.2.2016 11:52 tarihinde Richard
Hacker yazdı:<br>
</div>
<blockquote cite="mid:56CADA50.8070601@igh.de" type="cite">I do not
have the patience to look into your code in detail to find out
what you're doing wrong, but here is an excerpt of my code I use
in etherlab Simulink Coder (ecrt_support.c):
<br>
<br>
void
<br>
ecs_send()
<br>
{
<br>
//...
<br>
<br>
list_for_each(master, &ecat_data.master_list, list) {
<br>
list_for_each(domain, &master->domain_list, list) {
<br>
// ...
<br>
<br>
ecrt_domain_queue(domain->handle);
<br>
}
<br>
<br>
if (/* send frames */) {
<br>
struct timespec tp;
<br>
<br>
clock_gettime(CLOCK_MONOTONIC, &tp);
<br>
ecrt_master_application_time(master->handle,
<br>
EC_TIMESPEC2NANO(tp));
<br>
<br>
if (/* sync_clocks */)) {
<br>
ecrt_master_sync_reference_clock(master->handle);
<br>
//...
<br>
}
<br>
<br>
ecrt_master_sync_slave_clocks(master->handle);
<br>
ecrt_master_send(master->handle);
<br>
}
<br>
}
<br>
}
<br>
<br>
void
<br>
ecs_receive()
<br>
{
<br>
//...
<br>
<br>
list_for_each(master, &ecat_data.master_list, list) {
<br>
<br>
if (/* receive frames */) {
<br>
ecrt_master_receive(master->handle);
<br>
}
<br>
<br>
list_for_each(domain, &master->domain_list, list) {
<br>
<br>
ecrt_domain_process(domain->handle);
<br>
ecrt_domain_state(domain->handle,
&domain->state);
<br>
<br>
}
<br>
}
<br>
}
<br>
<br>
void
<br>
calculate()
<br>
{
<br>
while (forever) {
<br>
ecs_receive();
<br>
// do calculations
<br>
ecs_send();
<br>
sleep();
<br>
}
<br>
}
<br>
<br>
Some of this is pseudo code, but I trust in your programming
capabilities to be able to adapt this to your code ;)
<br>
<br>
It is very important to call clock_gettime() and
ecrt_master_application_time() as close to ecrt_master_send() as
possible.
<br>
<br>
As you can see, it is not necessary to call
ecrt_master_sync_reference_clock() with every ecrt_master_send().
In fact, ~100Hz of syncing should be enough, provided that your
call to clock_gettime() is accurate. On the other hand, if
clock_gettime() is inaccurate, you're in trouble when using DC
anyway!
<br>
<br>
- Richard
<br>
<br>
Am 2016-02-22 um 04:23 schrieb Thomas Bitsky Jr:
<br>
<blockquote type="cite">Ok, after following all your advice, plus
the clock adjustment from
<br>
Mattieu, I’m pretty close. I enable the DC on the drive, get
everything
<br>
into op, the domains all come up and it would appear that the
clocks are
<br>
syncing. Except for one thing:
<br>
<br>
[10248.633619] EtherCAT 0: Domain 0: Working counter changed to
1/17.
<br>
[10249.535776] EtherCAT WARNING 0: 3989 datagrams UNMATCHED!
<br>
[10249.539861] EtherCAT WARNING: Datagram f3bf2d0c
(domain0-0-main) was
<br>
SKIPPED 1 time.
<br>
[10249.539887] EtherCAT WARNING: Datagram f3bf2a8c
(domain2-120-main)
<br>
was SKIPPED 1 time.
<br>
[10249.539918] EtherCAT WARNING: Datagram f3bf2e8c
(domain1-114-main)
<br>
was SKIPPED 1 time.
<br>
[10249.635934] EtherCAT 0: Domain 0: 9 working counter changes -
now 17/17.
<br>
[10249.919163] EtherCAT 0: Domain 2: Working counter changed to
1/1.
<br>
[10250.018245] EtherCAT 0: Domain 1: Working counter changed to
1/1.
<br>
[10250.040259] EtherCAT 0: Slave states on main device: OP.
<br>
[10250.536654] EtherCAT WARNING 0: 4001 datagrams UNMATCHED!
<br>
[10251.537469] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
<br>
[10252.538282] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
<br>
[10252.538296] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
<br>
[10253.539097] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
<br>
[10254.539909] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
<br>
[10255.540723] EtherCAT WARNING 0: 4000 datagrams UNMATCHED!
<br>
[10256.541537] EtherCAT WARNING 0: 4000 datagrams
UNMATCHED!<— This
<br>
continues indefinitely
<br>
<br>
<br>
Everything else seems okay:
<br>
<br>
user@core:~/dist$ ethercat slaves
<br>
0 0:0 OP + EK1100 EtherCAT-Koppler (2A E-Bus)
<br>
1 0:1 OP + EL1104 4K. Dig. Eingang 24V, 3ms,
Sensorversorgung
<br>
2 0:2 OP + EL1104 4K. Dig. Eingang 24V, 3ms,
Sensorversorgung
<br>
3 0:3 OP + EL5101 1K. Inc. Encoder 5V
<br>
4 0:4 OP + EL7041 1K. Schrittmotor-Endstufe (50V, 5A)
<br>
5 0:5 OP + EL7041 1K. Schrittmotor-Endstufe (50V, 5A)
<br>
6 0:6 OP + EL2004 4K. Dig. Ausgang 24V, 0.5A
<br>
7 0:7 OP + EL2004 4K. Dig. Ausgang 24V, 0.5A
<br>
8 0:8 OP + EL4001 1K. Ana. Ausgang 0-10V, 12bit
<br>
9 1:0 OP + 0x00000539:0x02200001
<br>
user@core:~/dist$ ethercat master
<br>
Master0
<br>
Phase: Operation
<br>
Active: yes
<br>
Slaves: 10
<br>
Ethernet devices:
<br>
Main: 00:30:18:c8:d4:92 (attached)
<br>
Link: UP
<br>
Tx frames: 5204542
<br>
Tx bytes: 733318966
<br>
Rx frames: 5204539
<br>
Rx bytes: 733318636
<br>
Tx errors: 0
<br>
Tx frame rate [1/s]: 4000 3944 2090
<br>
Tx rate [KByte/s]: 823.7 811.9 412.9
<br>
Rx frame rate [1/s]: 4000 3944 2090
<br>
Rx rate [KByte/s]: 823.7 811.9 412.9
<br>
Common:
<br>
Tx frames: 5204542
<br>
Tx bytes: 733318966
<br>
Rx frames: 5204539
<br>
Rx bytes: 733318636
<br>
Lost frames: 3
<br>
Tx frame rate [1/s]: 4000 3944 2090
<br>
Tx rate [KByte/s]: 823.7 811.9 412.9
<br>
Rx frame rate [1/s]: 4000 3944 2090
<br>
Rx rate [KByte/s]: 823.7 811.9 412.9
<br>
Loss rate [1/s]: 0 0 0
<br>
Frame loss [%]: 0.0 0.0 0.0
<br>
Distributed clocks:
<br>
Reference clock: Slave 0
<br>
Application time: 509424243322706771
<br>
2016-02-22 02:44:03.322706771
<br>
<br>
<br>
<br>
<br>
<br>
<br>
I must have something out of sync. Is there something more I’m
supposed
<br>
to do to adjust the clock? I can make the number of dropped
packets
<br>
worse by simplifying the time adjustment, but I can’t seem to
get it any
<br>
better. I think I’m not understanding something about the clock
<br>
adjustment. Can you see what I’m doing wrong?
<br>
<br>
Thanks!
<br>
<br>
My cyclic task:
<br>
<br>
<br>
static void
<br>
sync_distributed_clocks(void)
<br>
{
<br>
uint32_t ref_time = 0;
<br>
uint64_t prev_app_time = dc_time_ns;
<br>
<br>
dc_time_ns = system_time_ns();
<br>
<br>
// set master time in nano-seconds
<br>
ecrt_master_application_time(master_, dc_time_ns);
<br>
<br>
// get reference clock time to synchronize master cycle
<br>
ecrt_master_reference_clock_time(master_, &ref_time);
<br>
dc_diff_ns = (uint32_t) prev_app_time - ref_time;
<br>
<br>
<br>
// call to sync slaves to ref slave
<br>
ecrt_master_sync_slave_clocks(master_);
<br>
}
<br>
<br>
static unsigned int cycle_ns = 1000000; // 1 millisecond
<br>
<br>
void update_master_clock(void)
<br>
{
<br>
// calc drift (via un-normalised time diff)
<br>
int32_t delta = dc_diff_ns - prev_dc_diff_ns;
<br>
prev_dc_diff_ns = dc_diff_ns;
<br>
<br>
// normalise the time diff
<br>
dc_diff_ns =
<br>
((dc_diff_ns + (cycle_ns / 2)) % cycle_ns) - (cycle_ns
/ 2);
<br>
<br>
// only update if primary master
<br>
if (dc_started)
<br>
{
<br>
<br>
// add to totals
<br>
dc_diff_total_ns += dc_diff_ns;
<br>
dc_delta_total_ns += delta;
<br>
dc_filter_idx++;
<br>
<br>
if (dc_filter_idx >= DC_FILTER_CNT)
<br>
{
<br>
// add rounded delta average
<br>
dc_adjust_ns +=
<br>
((dc_delta_total_ns + (DC_FILTER_CNT / 2)) /
<br>
DC_FILTER_CNT);
<br>
<br>
// and add adjustment for general diff (to pull in
drift)
<br>
dc_adjust_ns += sign(dc_diff_total_ns /
DC_FILTER_CNT);
<br>
<br>
// limit crazy numbers (0.1% of std cycle time)
<br>
if (dc_adjust_ns < -1000) {
<br>
dc_adjust_ns = -1000;
<br>
}
<br>
if (dc_adjust_ns > 1000) {
<br>
dc_adjust_ns = 1000;
<br>
}
<br>
<br>
// reset
<br>
dc_diff_total_ns = 0LL;
<br>
dc_delta_total_ns = 0LL;
<br>
dc_filter_idx = 0;
<br>
}
<br>
<br>
// add cycles adjustment to time base (including a spot
adjustment)
<br>
system_time_base += dc_adjust_ns + sign(dc_diff_ns);
<br>
}
<br>
else
<br>
{
<br>
dc_started = (dc_diff_ns != 0);
<br>
<br>
if (dc_started)
<br>
{
<br>
// output first diff
<br>
PRINT("First master diff: %d.\n", dc_diff_ns);
<br>
<br>
// record the time of this initial cycle
<br>
dc_start_time_ns = dc_time_ns;
<br>
}
<br>
}
<br>
<br>
}
<br>
<br>
<br>
int
<br>
<br>
ecatMain_process(void* lp)
<br>
<br>
{
<br>
<br>
<br>
sync_distributed_clocks();
<br>
<br>
update_master_clock();
<br>
<br>
<br>
ecrt_master_receive(master_);
<br>
<br>
ecrt_domain_process(lrwDomainMgr_.domain);
<br>
<br>
ecrt_domain_process(noLrwWriteDomainMgr_.domain);
<br>
<br>
ecrt_domain_process(noLrwReadDomainMgr_.domain);
<br>
<br>
… // handle my business
<br>
<br>
<br>
// send process data
<br>
<br>
ecrt_domain_queue(lrwDomainMgr_.domain);
<br>
<br>
ecrt_domain_queue(noLrwWriteDomainMgr_.domain);
<br>
<br>
ecrt_domain_queue(noLrwReadDomainMgr_.domain);
<br>
<br>
// send EtherCAT data
<br>
<br>
ecrt_master_send(master_);
<br>
<br>
return 1;
<br>
<br>
}
<br>
<br>
<br>
<br>
<br>
I made my sync0 time half of the can rate, as you prescribed:
<br>
<br>
void
<br>
ecatModule_registerDcClock( Slave* slave, uint16_t addr )
<br>
{
<br>
struct timespec cur_time;
<br>
clock_gettime(CLOCK_REALTIME, &cur_time);
<br>
uint16_t sync0time = (uint16_t)((globalScanRate_us * 1000) / 2);
<br>
ecrt_slave_config_dc(
<br>
slave->sc,
<br>
addr,
<br>
(globalScanRate_us * 1000),
<br>
sync0time,
<br>
0,
<br>
0);
<br>
}
<br>
<br>
<br>
<br>
<br>
<br>
From: Graeme Foot <<a class="moz-txt-link-abbreviated" href="mailto:Graeme.Foot@touchcut.com">Graeme.Foot@touchcut.com</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:Graeme.Foot@touchcut.com"><mailto:Graeme.Foot@touchcut.com></a>>
<br>
Date: Sunday, February 21, 2016 at 4:07 PM
<br>
To: Thomas Bitsky <<a class="moz-txt-link-abbreviated" href="mailto:tbj@automateddesign.com">tbj@automateddesign.com</a>
<a class="moz-txt-link-rfc2396E" href="mailto:tbj@automateddesign.com"><mailto:tbj@automateddesign.com></a>>
<br>
Cc: "<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>"
<br>
<<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>>
<br>
Subject: RE: Distributed Clocks
<br>
<br>
Hi,
<br>
<br>
I build and patch against revision 2526, so don’t know what
patches /
<br>
fixes have made it through to the latest release. However for
my
<br>
revision I need fixes for reference clock selections and dc
<br>
synchronization issues.
<br>
<br>
I’ve attached the dc related patches I use, but these are
applied after
<br>
some other patches so you may get some conflicts or offsetting.
<br>
<br>
*01 - Distributed Clock fixes and helpers.patch*
<br>
<br>
This sorts out some ref slave issues, allowing a user selected
ref
<br>
slave. It also adds some helper functions:
<br>
<br>
- ecrt_master_setup_domain_memory() : this allows me to set up
the
<br>
domain memory and do stuff with it before calling
ecrt_master_activate()
<br>
(for user space apps)
<br>
<br>
- ecrt_master_deactivate_slaves() : this lets me deactivate the
slaves
<br>
while still in realtime to avoid the slaves getting some
shutdown sync
<br>
errors
<br>
<br>
*02 - Distributed Clock fixes from Jun Yuan - dc sync
issues.patch*
<br>
<br>
This sorts out some timing issues to do with slave dc syncing.
Without
<br>
it they can start syncing from one cycle out causing a large
syncing
<br>
time overhead, one slave at a time.
<br>
<br>
Regards,
<br>
<br>
Graeme.
<br>
<br>
*From:*Thomas Bitsky Jr [<a class="moz-txt-link-freetext" href="mailto:tbj@automateddesign.com">mailto:tbj@automateddesign.com</a>]
<br>
*Sent:* Sunday, 21 February 2016 10:27 a.m.
<br>
*To:* Graeme Foot
<br>
*Cc:* <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>
<br>
*Subject:* Re: Distributed Clocks
<br>
<br>
Graeme,
<br>
<br>
Thank you so much for the detailed response. I'm away from my
computer
<br>
right now, so I can't try out your advice, but I noticed you
asked about
<br>
patches. I am not running any patches; which should I get?
<br>
<br>
Thanks!
<br>
Thomas Bitsky Jr
<br>
<br>
On Feb 20, 2016, at 3:04 PM, Graeme Foot
<<a class="moz-txt-link-abbreviated" href="mailto:Graeme.Foot@touchcut.com">Graeme.Foot@touchcut.com</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:Graeme.Foot@touchcut.com"><mailto:Graeme.Foot@touchcut.com></a>> wrote:
<br>
<br>
Hi,
<br>
<br>
The slave clocks get synced via the distributed clock system
using
<br>
the master methods: ecrt_master_reference_clock_time(),
<br>
ecrt_master_sync_slave_clocks(),
ecrt_master_application_time(),
<br>
ecrt_master_sync_reference_clock().
<br>
<br>
However each individual slave can choose (if it is capable
of it)
<br>
whether to synchronize its reading and writing of data to a
<br>
particular point in time within the dc cycle. If that slave
does
<br>
not choose to do so then the reading and writing of the data
occurs
<br>
at the time the EtherCAT frame goes past, resulting in a
progressive
<br>
update and application of data as the frame progresses
through all
<br>
of the slaves.
<br>
<br>
If a slave is registered to use the dc clock then it caches
the
<br>
frame data until the sync0 interrupt so in theory all dc
slaves
<br>
apply the data at the same time. It also means you don’t
have to
<br>
worry about jitter as to the time the frame is sent over the
wire.
<br>
The only thing is to choose a good sync0 time to ensure your
frames
<br>
are always sent out and have reached all of the slaves
before the
<br>
sync0 time occurs, and that the next frame is not sent out
before
<br>
the previous sync0 time occurs.
<br>
<br>
In my application my cycle time is 1000us. I choose a sync0
time of
<br>
500us. I also send my frame as close as possible to the
beginning
<br>
of the cycle. This gives the frame up to half the cycle time
to
<br>
reach all of the slaves and then the other half of the cycle
for the
<br>
frame to return in time for the master receive call. I
could choose
<br>
a sync0 time later than 500us but I want it processed as
soon as
<br>
possible after the frame is received while still allowing
for a bus
<br>
with a large number of terminals.
<br>
<br>
So below where you are calculating loop_shift based on the
current
<br>
time is wrong. Just choose a time within the dc cycle and
use that
<br>
value for all slaves. Note: the beginning of the dc cycle
is in
<br>
phase with the first call to ecrt_master_application_time(),
so all
<br>
of your realtime looping should also be in phase with that
initial time.
<br>
<br>
Note, when selecting a slave to be the DC reference slave
you should
<br>
generally choose the first slave on your bus, regardless of
whether
<br>
it will be (or can be) registered to use the dc
synchronization. At
<br>
the very least it must be before, or be the, first slave
that will
<br>
be registered as a dc slave.
<br>
<br>
Also note that some slaves clocks are not very stable and
shouldn’t
<br>
be used as the DC reference slave. My original testing was
on a
<br>
Beckhoff CX1020 with a CX1100-0004, this could not be used
as a
<br>
reference slave as its clock was not stable.
<br>
<br>
I see you are configuring the slaves via
ecrt_slave_config_*()then
<br>
calling ecrt_slave_config_pdos()at the end. If you call
<br>
ecrt_slave_config_pdos() at the beginning you don’t need all
the
<br>
other config calls. However I hear AKD drives and some other
slaves
<br>
prefer explicit slave config calls but most slaves are happy
with
<br>
just the ecrt_slave_config_reg_pdo_entry()methods.
<br>
<br>
This also leads to another issue. One of the configured PDO
items
<br>
is the “mode of operation” value (0x6060 0x00). You are
also
<br>
configuring this with: ecrt_slave_config_sdo8( sc, 0x6060,
0, 8 ).
<br>
This value should be instead be set via the PDO value. Use
<br>
ecrt_slave_config_reg_pdo_entry()to get the offset to the
value and
<br>
set the value there.
<br>
<br>
Sorry if that was a bit long but DC’s is not an easy topic
to get
<br>
your head around. Here’s a bit of a summary:
<br>
<br>
- You can choose which slaves get registered with
<br>
ecrt_slave_config_dc(). But each slave you want synced must
get its
<br>
own call to ecrt_slave_config_dc().
<br>
<br>
- If your yaskawa drives get to OP without
<br>
ecrt_slave_config_dc()then they should get to OP with
<br>
ecrt_slave_config_dc().
<br>
<br>
- The yaskawa drives require a very stable reference slave
time,
<br>
which is why we sync the EtherCAT master to the reference
slave
<br>
rather than the other way around.
<br>
<br>
And some other comments:
<br>
<br>
- Never use anEL9010 endcap module. These break the
distributed
<br>
clock calculations. I don’t think they are available
anymore though.
<br>
<br>
- There are some patches out there that fix various DC clock
issues,
<br>
are you using any of these?
<br>
<br>
Regards,
<br>
<br>
Graeme.
<br>
<br>
*From:*Thomas Bitsky Jr [<a class="moz-txt-link-freetext" href="mailto:tbj@automateddesign.com">mailto:tbj@automateddesign.com</a>]
<br>
*Sent:* Sunday, 21 February 2016 7:15 a.m.
<br>
*To:* Graeme Foot; <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>
<br>
*Subject:* Re: Distributed Clocks
<br>
<br>
[snip]
<br>
<br>
I’ve never been able to get the EL7041 stepper modules to
work in dc
<br>
mode.
<br>
<br>
[/snip]
<br>
<br>
Is it all or nothing? I need the servo drives, the LVDT and
the
<br>
EL3356 tied to a distributed clock. The EL7041 is optional
for me.
<br>
<br>
[snip]
<br>
<br>
I don’t see in your code calls to ecrt_slave_config_dc().
<br>
<br>
For the yaskawa drive, during the config stage, I use the
following
<br>
calls…
<br>
<br>
[/snip]
<br>
<br>
Forgot to put that part; my bad. This is what I had for the
<br>
Yaskawa/AKD, although I was only doing it to one of the
drives. I
<br>
thought I was supposed to set up one distributed clock, and
it
<br>
became the master and handled the rest. Am I supposed to do
this for
<br>
all the cards, or do I select?
<br>
<br>
Yaskawa(AKD drive code is pretty much the same):
<br>
<br>
if (!(sc = ecrt_master_slave_config(
<br>
<br>
master,
<br>
<br>
slavePosDomain,
<br>
<br>
slavePosIndex,
<br>
<br>
vendorId, productCode)))
<br>
<br>
{
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1C12, 0, 0 ); /* clear sm pdo
0x1c12 */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1C13, 0, 0 ); /* clear sm pdo
0x1c12 */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A00, 0, 0 ); /* clear TxPDO0
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A01, 0, 0 ); /* clear TxPDO1
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A02, 0, 0 ); /* clear TxPDO2
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A03, 0, 0 ); /* clear TxPDO3
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1600, 0, 0 ); /* number of var
in this
<br>
PDO */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1601, 0, 0 ); /* clear RxPdo
0x1601 */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1602, 0, 0 ); /* clear
RxPdo
<br>
0x1602 */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1603, 0, 0 ); /* clear
RxPdo
<br>
0x1603 */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A00, 0, 0 ); /* clear TxPDO0
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 1, 0x60410010 ); //
Status word
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 2,0x60640020 );//
Position
<br>
actual value, per encoder
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 3,0x60770010 );//
Torque,
<br>
actual value
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 4,0x60F40020 );//
Following
<br>
error, actual value
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 5,0x60610008 );// Modes
of
<br>
operation display
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 6,0x00000008 );// GAP
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 7,0x60B90010 );// Touch
probe
<br>
status
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A00, 8, 0x60BA0020 ); //
Touch probe
<br>
1 position
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A00, 0, 8 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A01, 0, 0 ); /* clear TxPDO1
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A01,1,0x60410010 ); //
Status word
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A01,2,0x60640020 );//
Position
<br>
actual value, per encoder
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A01, 0, 2 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A02, 0, 0 ); /* clear TxPDO2
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A02,1,0x60410010 ); //
Status word
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A02,2,0x60640020 );//
Position
<br>
actual value, per encoder
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A02, 0, 2 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A03, 0, 0 ); /* clear TxPDO2
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A03,1,0x60410010 ); //
Status word
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A03,2,0x60640020 );//
Position
<br>
actual value, per encoder
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1A03,3,0x60770010 );//
Torque, actual
<br>
value
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1A03, 0, 3 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1600, 0, 0 ); /* clear entries
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 1, 0x60400010 ); /*
control
<br>
word */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 2, 0x607A0020 ); /*
target
<br>
position */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 3, 0x60FF0020 ); /*
target
<br>
velocity */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 4, 0x60710010 ); /*
target
<br>
torque */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 5, 0x60720010 ); /*
max torque */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 6, 0x60600008 ); /*
modes of
<br>
operation */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 7, 0x00000008 ); /*
gap */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1600, 8, 0x60B80010 ); /*
touch
<br>
probe function */
<br>
<br>
ecrt_slave_config_sdo8(sc, 0x1600, 0, 8 ); /* pdo entries */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1601, 0, 0 ); /* clear entries
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1601, 1, 0x60400010 ); /*
control
<br>
word */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1601, 2, 0x607A0020 ); /*
target
<br>
position */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1601, 0, 2 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1602, 0, 0 ); /* clear entries
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1602, 1, 0x60400010 ); /*
control
<br>
word */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1602, 2, 0x60FF0020 ); /*
target
<br>
position */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1602, 0, 2 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1603, 0, 0 ); /* clear entries
*/
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1603, 1, 0x60400010 ); /*
control
<br>
word */
<br>
<br>
ecrt_slave_config_sdo32( sc, 0x1603, 2, 0x60710020 ); /*
target
<br>
position */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1603, 0, 2 ); /* pdo entries
*/
<br>
<br>
ecrt_slave_config_sdo16( sc, 0x1C12, 1, 0x1601 ); /*
download pdo
<br>
1C12 index */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1C12, 0, 1 ); /* set number of
RxPDO */
<br>
<br>
ecrt_slave_config_sdo16( sc, 0x1C13, 1, 0x1A01 ); /*
download pdo
<br>
1C13 index */
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x1C13, 0, 1 ); /* set number of
TxPDO */
<br>
<br>
// OPMODE
<br>
<br>
// Yaskawa recommends 8
<br>
<br>
ecrt_slave_config_sdo8( sc, 0x6060, 0, 8 );
<br>
<br>
unsigned char interpolationTime = 0xFF;
<br>
<br>
// 250
<br>
<br>
unsigned char cycleExponent = 0xFA;
<br>
<br>
// microseconds
<br>
<br>
// globalSCanRate_us equals either 250 or 125.
<br>
<br>
unsigned int us = globalScanRate_us;
<br>
<br>
size_t i;
<br>
<br>
for ( i=0;i<6, us > 0xFF;++i )
<br>
<br>
{
<br>
<br>
us /= 10;
<br>
<br>
cycleExponent += 1;
<br>
<br>
}
<br>
<br>
interpolationTime = us;
<br>
<br>
ecrt_slave_config_sdo8( akd->sc_akd, 0x60C2, 1,
interpolationTime );
<br>
/* Interpolation time */
<br>
<br>
ecrt_slave_config_sdo8( akd->sc_akd, 0x60C2, 2,
cycleExponent ); /*
<br>
Cycle exponent */
<br>
<br>
PRINT("Configuring PDOs...\n");
<br>
<br>
if (ecrt_slave_config_pdos(sc, EC_END, slave_syncs))
<br>
<br>
{
<br>
<br>
PRINT("Failed to configure Yaskawa Sigma PDOs.\n");
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
*struct timespec cur_time;*
<br>
<br>
*clock_gettime(CLOCK_REALTIME, &cur_time);*
<br>
<br>
*size_t loop_period = globalScanRate_us * 1000;*
<br>
<br>
*if ( loop_period == 0 ) loop_period = 1;*
<br>
<br>
*size_t loop_shift *
<br>
<br>
*= loop_period - (cur_time.tv_nsec % loop_period);*
<br>
<br>
*ecrt_slave_config_dc(*
<br>
<br>
*sc, *
<br>
<br>
*0x0300, *
<br>
<br>
*loop_period, *
<br>
<br>
*loop_shift, *
<br>
<br>
*0, *
<br>
<br>
*0);*
<br>
<br>
For the EL3356, would I then?
<br>
<br>
KL3356StrainGauge* sg =
(KL3356StrainGauge*)slave->instance;
<br>
<br>
printf( "Begin kl3356_ecConfigure...\n");
<br>
<br>
//
<br>
<br>
// Create the slave configuration
<br>
<br>
//
<br>
<br>
if (!(sg->sc = ecrt_master_slave_config(
<br>
<br>
master,
<br>
<br>
slavePosDomain, slavePosIndex, // Bus position
<br>
<br>
vendorId, productCode
<br>
<br>
// Slave type
<br>
<br>
)))
<br>
<br>
{
<br>
<br>
printf(
<br>
<br>
"kl3356_ecConfigure -- Failed to get slave
configuration.\n");
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
//
<br>
<br>
// Register startup configuration for the hardware
<br>
<br>
//
<br>
<br>
ecrt_slave_config_sdo8( sg->sc, 0x1C12, 0, 0 ); /* clear
sm pdo
<br>
0x1c12 */
<br>
<br>
ecrt_slave_config_sdo8( sg->sc, 0x1C13, 0, 0 ); /* clear
sm pdo
<br>
0x1c12 */
<br>
<br>
ecrt_slave_config_sdo16( sg->sc, 0x1C12, 1, 0x1600 ); /*
download
<br>
pdo 1C12 index */
<br>
<br>
ecrt_slave_config_sdo8( sg->sc, 0x1C12, 0, 1 ); /* set
number of
<br>
RxPDO */
<br>
<br>
ecrt_slave_config_sdo16( sg->sc, 0x1C13, 1, 0x1A00 ); /*
download
<br>
pdo 1C13 index */
<br>
<br>
ecrt_slave_config_sdo16( sg->sc, 0x1C13, 2, 0x1A02 ); /*
download
<br>
pdo 1C13 index */
<br>
<br>
ecrt_slave_config_sdo8( sg->sc, 0x1C13, 0, 2 ); /* set
number of
<br>
TxPDO */
<br>
<br>
//
<br>
<br>
// Configure the hardware's PDOs
<br>
<br>
//
<br>
<br>
if (ecrt_slave_config_pdos(sg->sc, EC_END, kl3356_syncs))
<br>
<br>
{
<br>
<br>
printf(
<br>
<br>
"kl3356_ecConfigure -- Failed to configure PDOs.\n");
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
*struct timespec cur_time;*
<br>
<br>
*clock_gettime(CLOCK_REALTIME, &cur_time);*
<br>
<br>
*size_t loop_period = globalScanRate_us * 1000;*
<br>
<br>
*if ( loop_period == 0 ) loop_period = 1;*
<br>
<br>
*size_t loop_shift *
<br>
<br>
*= loop_period - (cur_time.tv_nsec % loop_period);*
<br>
<br>
*ecrt_slave_config_dc(*
<br>
<br>
*s**g->sc, *
<br>
<br>
*0x0300, *
<br>
<br>
*loop_period, *
<br>
<br>
*loop_shift, *
<br>
<br>
*0, *
<br>
<br>
*0);*
<br>
<br>
Thanks!
<br>
<br>
Thomas C. Bitsky Jr. | Lead Developer
<br>
<br>
ADC | automateddesign.com
<a class="moz-txt-link-rfc2396E" href="http://automateddesign.com/"><http://automateddesign.com/></a>
<br>
<br>
P: 630-783-1150 F: 630-783-1159 M: 630-632-6679
<br>
<br>
Follow ADC news and media:
<br>
<br>
Facebook <a class="moz-txt-link-rfc2396E" href="https://facebook.com/automateddesigncorp"><https://facebook.com/automateddesigncorp></a> |
Twitter
<br>
<a class="moz-txt-link-rfc2396E" href="https://twitter.com/ADCSportsLogic"><https://twitter.com/ADCSportsLogic></a> | YouTube
<br>
<a class="moz-txt-link-rfc2396E" href="https://www.youtube.com/user/ADCSportsLogic"><https://www.youtube.com/user/ADCSportsLogic></a>
<br>
<br>
*From: *Graeme Foot <<a class="moz-txt-link-abbreviated" href="mailto:Graeme.Foot@touchcut.com">Graeme.Foot@touchcut.com</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:Graeme.Foot@touchcut.com"><mailto:Graeme.Foot@touchcut.com></a>>
<br>
*Date: *Friday, February 19, 2016 at 7:24 PM
<br>
*To: *Thomas Bitsky <<a class="moz-txt-link-abbreviated" href="mailto:tbj@automateddesign.com">tbj@automateddesign.com</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:tbj@automateddesign.com"><mailto:tbj@automateddesign.com></a>>,
"<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>"
<<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<br>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>>
<br>
*Subject: *RE: Distributed Clocks
<br>
<br>
Hi,
<br>
<br>
I don’t see in your code calls to ecrt_slave_config_dc().
<br>
<br>
For the yaskawa drive, during the config stage, I use the
following
<br>
calls:
<br>
<br>
// set interpolation time period (free run mode)
<br>
<br>
// where 0x60C2 is time in seconds = (0x60C2, 0x01) x
<br>
10^(0x60C2, 0x02)
<br>
<br>
// eg period of 1ms:
<br>
<br>
// (0x60C2, 0x01) = 1
<br>
<br>
// (0x60C2, 0x02) = -3
<br>
<br>
// => 1 x 10^(-3) = 0.001s
<br>
<br>
ecrt_slave_config_sdo8(dev->slaveConfig, 0x60C2,
0x01,
<br>
(uint8_t)g_app.scanTimeMS);
<br>
<br>
ecrt_slave_config_sdo8(dev->slaveConfig, 0x60C2,
0x02,
<br>
(int8_t)(-3));
<br>
<br>
// set up the distributed clock
<br>
<br>
// 0x0000 = free run, 0x0300 = dc
<br>
<br>
// (Supported DC cycle: 125us to 4ms (every 125us
cycle))
<br>
<br>
ecrt_slave_config_dc(dev->slaveConfig, 0x0300,
<br>
g_app.scanTimeNS, 500000, 0, 0);
<br>
<br>
0x60C2 shouldn’t be necessary for dc mode, but I used it
before I
<br>
had dc mode working and have never tried it without and it
doesn’t
<br>
harm anything having it in.
<br>
<br>
The second value that is being passed to the
<br>
ecrt_slave_config_dcmethod is a value that is written to the
ESC
<br>
register 0x980. The Yaskawa SGDV doco says this value should
be
<br>
0x0000 for free run mode and 0x0300 for dc mode. Other
ESC’s may
<br>
required different values.
<br>
<br>
I’ve never been able to get the EL7041 stepper modules to
work in dc
<br>
mode.
<br>
<br>
Graeme.
<br>
<br>
*From:*etherlab-users
[<a class="moz-txt-link-freetext" href="mailto:etherlab-users-bounces@etherlab.org">mailto:etherlab-users-bounces@etherlab.org</a>]
<br>
*On Behalf Of *Thomas Bitsky Jr
<br>
*Sent:* Saturday, 20 February 2016 1:09 p.m.
<br>
*To:* <a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<a class="moz-txt-link-rfc2396E" href="mailto:etherlab-users@etherlab.org"><mailto:etherlab-users@etherlab.org></a>
<br>
*Subject:* [etherlab-users] Distributed Clocks
<br>
<br>
Hello.
<br>
<br>
I’ve been using the EtherCAT master for years to great
success, but
<br>
I’m stuck on a problem I can’t figure out that I think
several
<br>
people here are doing successfully. I can’t implement
distributed
<br>
clocks in my application.
<br>
<br>
I am having the same problem on two systems I have up and
running:
<br>
<br>
SYSTEM ONE:
<br>
<br>
EtherLAB Master 1.52, E1000E Driver, Scan Rate 4Khz, Ubuntu
Server
<br>
14.04LTS, RT-PREEMPT 3.12.50-rt68
<br>
<br>
alias=0, position=0, device=EK1100
<br>
<br>
alias=0, position=1, device=EL1104
<br>
<br>
alias=0, position=2, device=EL2004
<br>
<br>
alias=0, position=3, device=EL9510
<br>
<br>
alias=0, position=4, device=EL3356
<br>
<br>
alias=0, position=5, device=Kollmorgen AKD
<br>
<br>
alias=0, position=6, device=MTS LVDT
<br>
<br>
SYSTEM TWO:
<br>
<br>
EtherLAB Master 1.52, E1000E Driver, Scan Rate 8Khz, Ubuntu
Server
<br>
14.04LTS, RT-PREEMPT 3.12.50-rt68
<br>
<br>
alias=0, position=0, device=EK1100
<br>
<br>
alias=0, position=1, device=EL3001
<br>
<br>
alias=0, position=2, device=EL1104
<br>
<br>
alias=0, position=3, device=EL1104
<br>
<br>
alias=0, position=4, device=EL1104
<br>
<br>
alias=0, position=5, device=EL2004
<br>
<br>
alias=0, position=6, device=EL2004
<br>
<br>
alias=0, position=7, device=EL9505
<br>
<br>
alias=0, position=8, device=EL7041
<br>
<br>
alias=0, position=9, device=EL7041
<br>
<br>
alias=0, position=10, device=EL7041
<br>
<br>
alias=0, position=11, device=EL7041
<br>
<br>
alias=0, position=12, device=EL7041
<br>
<br>
alias=0, position=13, device=EL7041
<br>
<br>
alias=0, position=14, device=EK1110
<br>
<br>
alias=1, position=0, device=SIGMA5-05
<br>
<br>
alias=2, position=0, device=Yaskawa SIGMA5-05
<br>
<br>
alias=3, position=0, device=Yaskawa SIGMA5-05
<br>
<br>
Both of the system are fully operational. However, for
various
<br>
reasons, I need to implement distributed clocks on these
systems.
<br>
I’ve never been able to get this to work.
<br>
<br>
What follows is the code I used for both systems to try
this. I read
<br>
through examples on the mailing list, plus the examples, but
I’m not
<br>
seeing what I’m doing wrong. The result is always the same:
all the
<br>
fieldbus cards go into operation, but the servo drives won’t
because
<br>
of “bad configuration.” Take out the distributed clock code,
and
<br>
they work fine. I’m getting away with it for now, but I do
need
<br>
better clock resolution.
<br>
<br>
The systems have an LRW domain, then a separate read domain
and
<br>
write domain for the servo drive(s) for a total of three
domains
<br>
(LRW, read, write). The yaskawa drives necessitate this. The
scan
<br>
rate is usually 4Khz, but I have tried it at both 1Khz and
8Khz and
<br>
gotten the same results. Everything about the implementation
is
<br>
fairly straight-forward. There’s just something fundamental
about
<br>
the DC configuration that I’m not understanding.
<br>
<br>
Almost all the code below is taken right from the examples
or the
<br>
message boards (thanks, everybody!). If anyone could tell me
what
<br>
I’m going wrong or offer any insights, it’s greatly
appreciated. For
<br>
brevity, I tried to narrow it down to relevant parts, but
please let
<br>
me know any additional information or code I can provide.
<br>
<br>
Thank you in advance,
<br>
<br>
Tom
<br>
<br>
**********************************************************
<br>
<br>
// EtherCAT distributed clock variables
<br>
<br>
#define DC_FILTER_CNT 1024
<br>
<br>
#define SYNC_MASTER_TO_REF 1
<br>
<br>
static uint64_t dc_start_time_ns = 0LL;
<br>
<br>
static uint64_t dc_time_ns = 0;
<br>
<br>
static uint8_t dc_started = 0;
<br>
<br>
static int32_t dc_diff_ns = 0;
<br>
<br>
static int32_t prev_dc_diff_ns = 0;
<br>
<br>
static int64_t dc_diff_total_ns = 0LL;
<br>
<br>
static int64_t dc_delta_total_ns = 0LL;
<br>
<br>
static int dc_filter_idx = 0;
<br>
<br>
static int64_t dc_adjust_ns;
<br>
<br>
static int64_t system_time_base = 0LL;
<br>
<br>
static uint64_t wakeup_time = 0LL;
<br>
<br>
static uint64_t overruns = 0LL;
<br>
<br>
/** Get the time in ns for the current cpu, adjusted by
<br>
system_time_base.
<br>
<br>
*
<br>
<br>
* \attention Rather than calling rt_get_time_ns()
directly, all
<br>
application
<br>
<br>
* time calls should use this method instead.
<br>
<br>
*
<br>
<br>
* \ret The time in ns.
<br>
<br>
*/
<br>
<br>
uint64_t system_time_ns(void)
<br>
<br>
{
<br>
<br>
struct timespec ts;
<br>
<br>
clock_gettime(GLOBAL_CLOCK_TO_USE, &ts);
<br>
<br>
return TIMESPEC2NS(ts);
<br>
<br>
}
<br>
<br>
static
<br>
<br>
void sync_distributed_clocks(void)
<br>
<br>
{
<br>
<br>
uint32_t ref_time = 0;
<br>
<br>
uint64_t prev_app_time = dc_time_ns;
<br>
<br>
dc_time_ns = system_time_ns();
<br>
<br>
// set master time in nano-seconds
<br>
<br>
ecrt_master_application_time(master_, dc_time_ns);
<br>
<br>
// get reference clock time to synchronize master cycle
<br>
<br>
ecrt_master_reference_clock_time(master_,
&ref_time);
<br>
<br>
dc_diff_ns = (uint32_t) prev_app_time - ref_time;
<br>
<br>
// call to sync slaves to ref slave
<br>
<br>
ecrt_master_sync_slave_clocks(master_);
<br>
<br>
}
<br>
<br>
/** Return the sign of a number
<br>
<br>
*
<br>
<br>
* ie -1 for -ve value, 0 for 0, +1 for +ve value
<br>
<br>
*
<br>
<br>
* \retval the sign of the value
<br>
<br>
*/
<br>
<br>
#define sign(val) \
<br>
<br>
({ typeof (val) _val = (val); \
<br>
<br>
((_val > 0) - (_val < 0)); })
<br>
<br>
/*****************************************************************************/<br>
<br>
/** Update the master time based on ref slaves time diff
<br>
<br>
*
<br>
<br>
* called after the ethercat frame is sent to avoid time
jitter in
<br>
<br>
* sync_distributed_clocks()
<br>
<br>
*/
<br>
<br>
static unsigned int cycle_ns = 1000000; // 1 millisecond
<br>
<br>
void update_master_clock(void)
<br>
<br>
{
<br>
<br>
// calc drift (via un-normalised time diff)
<br>
<br>
int32_t delta = dc_diff_ns - prev_dc_diff_ns;
<br>
<br>
prev_dc_diff_ns = dc_diff_ns;
<br>
<br>
// normalise the time diff
<br>
<br>
dc_diff_ns =
<br>
<br>
((dc_diff_ns + (cycle_ns / 2)) % cycle_ns) -
(cycle_ns / 2);
<br>
<br>
// only update if primary master
<br>
<br>
if (dc_started) {
<br>
<br>
// add to totals
<br>
<br>
dc_diff_total_ns += dc_diff_ns;
<br>
<br>
dc_delta_total_ns += delta;
<br>
<br>
dc_filter_idx++;
<br>
<br>
if (dc_filter_idx >= DC_FILTER_CNT) {
<br>
<br>
// add rounded delta average
<br>
<br>
dc_adjust_ns +=
<br>
<br>
((dc_delta_total_ns + (DC_FILTER_CNT / 2))
/
<br>
DC_FILTER_CNT);
<br>
<br>
// and add adjustment for general diff (to pull
in drift)
<br>
<br>
dc_adjust_ns += sign(dc_diff_total_ns /
DC_FILTER_CNT);
<br>
<br>
// limit crazy numbers (0.1% of std cycle time)
<br>
<br>
if (dc_adjust_ns < -1000) {
<br>
<br>
dc_adjust_ns = -1000;
<br>
<br>
}
<br>
<br>
if (dc_adjust_ns > 1000) {
<br>
<br>
dc_adjust_ns = 1000;
<br>
<br>
}
<br>
<br>
// reset
<br>
<br>
dc_diff_total_ns = 0LL;
<br>
<br>
dc_delta_total_ns = 0LL;
<br>
<br>
dc_filter_idx = 0;
<br>
<br>
}
<br>
<br>
// add cycles adjustment to time base (including a
spot
<br>
adjustment)
<br>
<br>
system_time_base += dc_adjust_ns +
sign(dc_diff_ns);
<br>
<br>
}
<br>
<br>
else {
<br>
<br>
dc_started = (dc_diff_ns != 0);
<br>
<br>
if (dc_started)
<br>
<br>
{
<br>
<br>
// record the time of this initial cycle
<br>
<br>
dc_start_time_ns = dc_time_ns;
<br>
<br>
}
<br>
<br>
}
<br>
<br>
}
<br>
<br>
struct timespec dcTime_;
<br>
<br>
int
<br>
<br>
ecatMain_process(void* lp)
<br>
<br>
{
<br>
<br>
ecrt_master_receive(master_);
<br>
<br>
clock_gettime(CLOCK_REALTIME, &dcTime_);
<br>
<br>
ecrt_master_application_time(master_, TIMESPEC2NS(dcTime_));
<br>
<br>
ecrt_master_sync_reference_clock(master_);
<br>
<br>
ecrt_master_sync_slave_clocks(master_);
<br>
<br>
ecrt_domain_process(lrwDomainMgr_.domain);
<br>
<br>
ecrt_domain_process(noLrwWriteDomainMgr_.domain);
<br>
<br>
ecrt_domain_process(noLrwReadDomainMgr_.domain);
<br>
<br>
… // handle my business
<br>
<br>
// write application time to master
<br>
<br>
clock_gettime(CLOCK_REALTIME, &dcTime_);
<br>
<br>
ecrt_master_application_time(master_, TIMESPEC2NS(dcTime_));
<br>
<br>
if (sync_ref_counter_)
<br>
<br>
{
<br>
<br>
sync_ref_counter_--;
<br>
<br>
}
<br>
<br>
else
<br>
<br>
{
<br>
<br>
sync_ref_counter_ = 1; // sync every cycle
<br>
<br>
ecrt_master_sync_reference_clock(master_);
<br>
<br>
}
<br>
<br>
// send process data
<br>
<br>
ecrt_domain_queue(lrwDomainMgr_.domain);
<br>
<br>
ecrt_domain_queue(noLrwWriteDomainMgr_.domain);
<br>
<br>
ecrt_domain_queue(noLrwReadDomainMgr_.domain);
<br>
<br>
// sync distributed clock just before master_send to set
<br>
<br>
// most accurate master clock time
<br>
<br>
sync_distributed_clocks();
<br>
<br>
// send EtherCAT data
<br>
<br>
ecrt_master_send(master_);
<br>
<br>
// update the master clock
<br>
<br>
// Note: called after ecrt_master_send() to reduce time
<br>
<br>
// jitter in the sync_distributed_clocks() call
<br>
<br>
update_master_clock();
<br>
<br>
return 1;
<br>
<br>
}
<br>
<br>
int
<br>
<br>
ecatMain_start(void* lp)
<br>
<br>
{
<br>
<br>
//
<br>
<br>
// domain regs must end in a null entry
<br>
<br>
//
<br>
<br>
lrwDomainMgr_.domainRegs = realloc(
<br>
<br>
lrwDomainMgr_.domainRegs,
<br>
<br>
sizeof(ec_pdo_entry_reg_t) * (lrwDomainMgr_.size + 1) );
<br>
<br>
memset(
<br>
<br>
&(lrwDomainMgr_.domainRegs[lrwDomainMgr_.size]),
<br>
<br>
0,
<br>
<br>
sizeof(ec_pdo_entry_reg_t) );
<br>
<br>
noLrwReadDomainMgr_.domainRegs = realloc(
<br>
<br>
noLrwReadDomainMgr_.domainRegs,
<br>
<br>
sizeof(ec_pdo_entry_reg_t) * (noLrwReadDomainMgr_.size + 1)
);
<br>
<br>
memset(
<br>
<br>
&(noLrwReadDomainMgr_.domainRegs[noLrwReadDomainMgr_.size]),
<br>
<br>
0,
<br>
<br>
sizeof(ec_pdo_entry_reg_t) );
<br>
<br>
noLrwWriteDomainMgr_.domainRegs = realloc(
<br>
<br>
noLrwWriteDomainMgr_.domainRegs,
<br>
<br>
sizeof(ec_pdo_entry_reg_t) * (noLrwWriteDomainMgr_.size +
1) );
<br>
<br>
memset(
<br>
<br>
&(noLrwWriteDomainMgr_.domainRegs[noLrwWriteDomainMgr_.size]),
<br>
<br>
0,
<br>
<br>
sizeof(ec_pdo_entry_reg_t) );
<br>
<br>
//
<br>
<br>
// NOTE: the Output Domain must be registered with
<br>
<br>
// ecrt_domain_reg_pdo_entry_list before the Input Domain
otherwise you
<br>
<br>
// will not have any data exchanged even though the drive
goes into OP
<br>
<br>
// mode.
<br>
<br>
//
<br>
<br>
PRINT("\nAttempting to register PDOs on WRITE ONLY
domain...\n");
<br>
<br>
if (ecrt_domain_reg_pdo_entry_list(
<br>
<br>
noLrwWriteDomainMgr_.domain,
noLrwWriteDomainMgr_.domainRegs))
<br>
<br>
{
<br>
<br>
PRINT("WRITE ONLY PDO entry registration failed!\n");
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
PRINT("\nAttempting to register PDOs on READ ONLY
domain...\n");
<br>
<br>
if (ecrt_domain_reg_pdo_entry_list(
<br>
<br>
noLrwReadDomainMgr_.domain, noLrwReadDomainMgr_.domainRegs))
<br>
<br>
{
<br>
<br>
PRINT("READ ONLY PDO entry registration failed!\n");
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
//
<br>
<br>
// And now we register the bi-directional domain.
<br>
<br>
//
<br>
<br>
PRINT("\nAttempting to register PDOs on LRW domain...\n");
<br>
<br>
if (ecrt_domain_reg_pdo_entry_list(
<br>
<br>
lrwDomainMgr_.domain, lrwDomainMgr_.domainRegs))
<br>
<br>
{
<br>
<br>
PRINT("LRW PDO entry registration failed!\n");
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
/*
<br>
<br>
* Finishes the configuration phase and prepares for cyclic
operation.
<br>
<br>
* This function tells the master that the configuration
phase
<br>
<br>
* is finished and the realtime operation will begin.
<br>
<br>
* The function allocates internal memory for the domains and
calculates
<br>
<br>
* the logical FMMU addresses for domain members.
<br>
<br>
* It tells the master state machine that the bus
configuration is
<br>
<br>
* now to be applied
<br>
<br>
*/
<br>
<br>
PRINT("\nAttempting to activate ECAT master...\n");
<br>
<br>
if (ecrt_master_activate(master_))
<br>
<br>
{
<br>
<br>
PRINT(
<br>
<br>
"%s Failed to activate master!\n",
<br>
<br>
__FUNCTION__ );
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
/*
<br>
<br>
* Returns the domain's process data.
<br>
<br>
*/
<br>
<br>
PRINT( "%s getting LRW process data from master.\n",
__FUNCTION__ );
<br>
<br>
if (!(lrwDomainMgr_.processData
<br>
<br>
= ecrt_domain_data(lrwDomainMgr_.domain)))
<br>
<br>
{
<br>
<br>
PRINT(
<br>
<br>
"%s set ecProcessData -- domain data is NULL!\n",
<br>
<br>
__FUNCTION__ );
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
if (!(noLrwReadDomainMgr_.processData
<br>
<br>
= ecrt_domain_data(noLrwReadDomainMgr_.domain)))
<br>
<br>
{
<br>
<br>
PRINT(
<br>
<br>
"%s set read ProcessData -- domain data is NULL!\n",
<br>
<br>
__FUNCTION__ );
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
if (!(noLrwWriteDomainMgr_.processData
<br>
<br>
= ecrt_domain_data(noLrwWriteDomainMgr_.domain)))
<br>
<br>
{
<br>
<br>
PRINT(
<br>
<br>
"%s set write ProcessData -- domain data is NULL!\n",
<br>
<br>
__FUNCTION__ );
<br>
<br>
return FALSE;
<br>
<br>
}
<br>
<br>
… // blah blah blah
<br>
<br>
doScan_ = TRUE;
<br>
<br>
PRINT( "%s completed successfully.\n", __FUNCTION__ );
<br>
<br>
return TRUE;
<br>
<br>
}
<br>
<br>
<br>
<br>
_______________________________________________
<br>
etherlab-users mailing list
<br>
<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<br>
<a class="moz-txt-link-freetext" href="http://lists.etherlab.org/mailman/listinfo/etherlab-users">http://lists.etherlab.org/mailman/listinfo/etherlab-users</a>
<br>
<br>
</blockquote>
_______________________________________________
<br>
etherlab-users mailing list
<br>
<a class="moz-txt-link-abbreviated" href="mailto:etherlab-users@etherlab.org">etherlab-users@etherlab.org</a>
<br>
<a class="moz-txt-link-freetext" href="http://lists.etherlab.org/mailman/listinfo/etherlab-users">http://lists.etherlab.org/mailman/listinfo/etherlab-users</a>
<br>
<br>
<br>
</blockquote>
<br>
<div class="moz-signature">-- <br>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title></title>
<br>
<pre class="moz-signature" cols="72">Oguz Dilmac
ARGE Bolumu
Bilko AS, R&D Department
====================================
Perpa Ticaret Merkezi B Blok Kat 13 Nr. 2568
TR-34384 Okmeydani Istanbul Turkey
Tel : +90 212 220 07 40 Fax : +90 212 210 47 01
e-mail : <a class="moz-txt-link-abbreviated" href="mailto:odilmac@bilko-automation.com">odilmac@bilko-automation.com</a>
web site : <a class="moz-txt-link-freetext" href="http://www.bilko-automation.com">http://www.bilko-automation.com</a>
</pre>
</div>
</body>
</html>