Added interface to select the reference clock and to sync to it.

Added rtai_rtdm_dc example, thanks to Graeme Foot.
This commit is contained in:
Florian Pose
2012-11-20 14:35:53 +01:00
parent c720cf8e10
commit becf05dbd6
11 changed files with 914 additions and 65 deletions

View File

@@ -102,6 +102,8 @@ examples/rtai/Makefile
examples/rtai/Makefile.in
examples/rtai_rtdm/.libs
examples/rtai_rtdm/ec_rtai_rtdm_example
examples/rtai_rtdm_dc/.libs
examples/rtai_rtdm_dc/ec_rtai_rtdm_dc_example
examples/user/.deps
examples/user/.libs
examples/user/Makefile

View File

@@ -804,6 +804,7 @@ AC_CONFIG_FILES([
examples/rtai/Kbuild
examples/rtai/Makefile
examples/rtai_rtdm/Makefile
examples/rtai_rtdm_dc/Makefile
examples/tty/Kbuild
examples/tty/Makefile
examples/user/Makefile

View File

@@ -49,7 +49,8 @@ endif
if ENABLE_RTAI
SUBDIRS += \
rtai_rtdm
rtai_rtdm \
rtai_rtdm_dc
endif
endif
@@ -59,6 +60,7 @@ DIST_SUBDIRS = \
mini \
rtai \
rtai_rtdm \
rtai_rtdm_dc \
tty \
user \
xenomai \

View File

@@ -0,0 +1,43 @@
#------------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# the IgH EtherCAT Master; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
#------------------------------------------------------------------------------
noinst_PROGRAMS = ec_rtai_rtdm_dc_example
ec_rtai_rtdm_dc_example_SOURCES = main.c
ec_rtai_rtdm_dc_example_CFLAGS = \
-Wall \
-I$(top_srcdir)/include \
$(RTAI_LXRT_CFLAGS)
ec_rtai_rtdm_dc_example_LDFLAGS = \
$(RTAI_LXRT_LDFLAGS) -llxrt -lrtdm \
-L$(top_builddir)/lib/.libs -lethercat_rtdm
#------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -57,6 +57,13 @@
* ecrt_reg_request_data(), ecrt_reg_request_state(),
* ecrt_reg_request_write(), ecrt_reg_request_read() and the feature flag
* EC_HAVE_REG_ACCESS.
* - Added method to select the reference clock,
* ecrt_master_select_reference_clock() and the feature flag
* EC_HAVE_SELECT_REF_CLOCK to check, if the method is available.
* - Added method to get the reference clock time,
* ecrt_master_reference_clock_time() and the feature flag
* EC_HAVE_REF_CLOCK_TIME to have the possibility to synchronize the master
* clock to the reference clock.
*
* Changes in version 1.5:
*
@@ -163,6 +170,14 @@
*/
#define EC_HAVE_REG_ACCESS
/* Defined if the method ecrt_master_select_reference_clock() is available.
*/
#define EC_HAVE_SELECT_REF_CLOCK
/* Defined if the method ecrt_master_reference_clock_time() is available.
*/
#define EC_HAVE_REF_CLOCK_TIME
/*****************************************************************************/
/** End of list marker.
@@ -664,6 +679,20 @@ ec_slave_config_t *ecrt_master_slave_config(
uint32_t product_code /**< Expected product code. */
);
/** Selects the reference clock for distributed clocks.
*
* If this method is not called for a certain master, or if the slave
* configuration pointer is NULL, then the first slave with DC functionality
* will provide the reference clock.
*
* \return 0 on success, otherwise negative error code.
*/
int ecrt_master_select_reference_clock(
ec_master_t *master, /**< EtherCAT master. */
ec_slave_config_t *sc /**< Slave config of the slave to use as the
* reference slave (or NULL). */
);
/** Obtains master information.
*
* No memory is allocated on the heap in
@@ -989,6 +1018,27 @@ void ecrt_master_sync_slave_clocks(
ec_master_t *master /**< EtherCAT master. */
);
/** Get the lower 32 bit of the reference clock system time.
*
* This method can be used to synchronize the master to the reference clock.
*
* The reference clock system time is queried via the
* ecrt_master_sync_slave_clocks() method, that reads the system time of the
* reference clock and writes it to the slave clocks (so be sure to call it
* cyclically to get valid data).
*
* \attention The returned time is the system time of the reference clock
* minus the transmission delay of the reference clock.
*
* \retval 0 success, system time was written into \a time.
* \retval -ENXIO No reference clock found.
* \retval -EIO Slave synchronization datagram was not received.
*/
int ecrt_master_reference_clock_time(
ec_master_t *master, /**< EtherCAT master. */
uint32_t *time /**< Pointer to store the queried system time. */
);
/** Queues the DC synchrony monitoring datagram for sending.
*
* The datagram broadcast-reads all "System time difference" registers (\a

View File

@@ -200,6 +200,31 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
return sc;
}
/*****************************************************************************/
int ecrt_master_select_reference_clock(ec_master_t *master,
ec_slave_config_t *sc)
{
uint32_t config_index;
int ret;
if (sc) {
config_index = sc->index;
}
else {
config_index = 0xFFFFFFFF;
}
ret = ioctl(master->fd, EC_IOCTL_SELECT_REF_CLOCK, config_index);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to select reference clock: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
return -EC_IOCTL_ERRNO(ret);
}
return 0;
}
/****************************************************************************/
int ecrt_master(ec_master_t *master, ec_master_info_t *master_info)
@@ -681,6 +706,21 @@ void ecrt_master_sync_slave_clocks(ec_master_t *master)
}
}
/*****************************************************************************/
int ecrt_master_reference_clock_time(ec_master_t *master, uint32_t *time)
{
int ret;
ret = ioctl(master->fd, EC_IOCTL_REF_CLOCK_TIME, time);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to get reference clock time: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
}
return ret;
}
/****************************************************************************/
void ecrt_master_sync_monitor_queue(ec_master_t *master)

View File

@@ -1562,6 +1562,45 @@ static int ec_ioctl_create_slave_config(
/*****************************************************************************/
/** Select the DC reference clock.
*/
static int ec_ioctl_select_ref_clock(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
uint32_t config_index = (uint32_t) arg;
ec_slave_config_t *sc = NULL;
int ret = 0;
if (unlikely(!ctx->requested)) {
ret = -EPERM;
goto out_return;
}
if (down_interruptible(&master->master_sem)) {
ret = -EINTR;
goto out_return;
}
if (config_index != 0xFFFFFFFF) {
if (!(sc = ec_master_get_config(master, config_index))) {
ret = -ENOENT;
goto out_up;
}
}
ecrt_master_select_reference_clock(master, sc);
out_up:
up(&master->master_sem);
out_return:
return ret;
}
/*****************************************************************************/
/** Activates the master.
*/
static int ec_ioctl_activate(
@@ -1842,6 +1881,35 @@ static int ec_ioctl_sync_slaves(
/*****************************************************************************/
/** Get the system time of the reference clock.
*/
static int ec_ioctl_ref_clock_time(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
uint32_t time;
int ret;
if (unlikely(!ctx->requested)) {
return -EPERM;
}
ret = ecrt_master_reference_clock_time(master, &time);
if (ret) {
return ret;
}
if (copy_to_user((void __user *) arg, &time, sizeof(time))) {
return -EFAULT;
}
return 0;
}
/*****************************************************************************/
/** Queue the sync monitoring datagram.
*/
static int ec_ioctl_sync_mon_queue(
@@ -3923,6 +3991,13 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
}
ret = ec_ioctl_create_slave_config(master, arg, ctx);
break;
case EC_IOCTL_SELECT_REF_CLOCK:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_select_ref_clock(master, arg, ctx);
break;
case EC_IOCTL_ACTIVATE:
if (!ctx->writable) {
ret = -EPERM;
@@ -3978,6 +4053,13 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
}
ret = ec_ioctl_sync_slaves(master, arg, ctx);
break;
case EC_IOCTL_REF_CLOCK_TIME:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_ref_clock_time(master, arg, ctx);
break;
case EC_IOCTL_SYNC_MON_QUEUE:
if (!ctx->writable) {
ret = -EPERM;

View File

@@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 22
#define EC_IOCTL_VERSION_MAGIC 23
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -96,58 +96,60 @@
#define EC_IOCTL_REQUEST EC_IO(0x1e)
#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1f)
#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x20, ec_ioctl_config_t)
#define EC_IOCTL_ACTIVATE EC_IOR(0x21, ec_ioctl_master_activate_t)
#define EC_IOCTL_DEACTIVATE EC_IO(0x22)
#define EC_IOCTL_SEND EC_IO(0x23)
#define EC_IOCTL_RECEIVE EC_IO(0x24)
#define EC_IOCTL_MASTER_STATE EC_IOR(0x25, ec_master_state_t)
#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x26, ec_ioctl_link_state_t)
#define EC_IOCTL_APP_TIME EC_IOW(0x27, ec_ioctl_app_time_t)
#define EC_IOCTL_SYNC_REF EC_IO(0x28)
#define EC_IOCTL_SYNC_SLAVES EC_IO(0x29)
#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2a)
#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2b, uint32_t)
#define EC_IOCTL_RESET EC_IO(0x2c)
#define EC_IOCTL_SC_SYNC EC_IOW(0x2d, ec_ioctl_config_t)
#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x2e, ec_ioctl_config_t)
#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x2f, ec_ioctl_config_pdo_t)
#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x30, ec_ioctl_config_pdo_t)
#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x31, ec_ioctl_add_pdo_entry_t)
#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x32, ec_ioctl_config_pdo_t)
#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x33, ec_ioctl_reg_pdo_entry_t)
#define EC_IOCTL_SC_DC EC_IOW(0x34, ec_ioctl_config_t)
#define EC_IOCTL_SC_SDO EC_IOW(0x35, ec_ioctl_sc_sdo_t)
#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x36, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x37, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x38, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3b, ec_ioctl_reg_request_t)
#define EC_IOCTL_SC_VOE EC_IOWR(0x3c, ec_ioctl_voe_t)
#define EC_IOCTL_SC_STATE EC_IOWR(0x3d, ec_ioctl_sc_state_t)
#define EC_IOCTL_SC_IDN EC_IOW(0x3e, ec_ioctl_sc_idn_t)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3f)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x40)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x41)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x42, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x43, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x44, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x45, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x46, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x47, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x48, ec_ioctl_sdo_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x49, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4a, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4b, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x4c, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x4d, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x4e, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x4f, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x50, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x51, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x52, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x53, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x54, size_t)
#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x21, uint32_t)
#define EC_IOCTL_ACTIVATE EC_IOR(0x22, ec_ioctl_master_activate_t)
#define EC_IOCTL_DEACTIVATE EC_IO(0x23)
#define EC_IOCTL_SEND EC_IO(0x24)
#define EC_IOCTL_RECEIVE EC_IO(0x25)
#define EC_IOCTL_MASTER_STATE EC_IOR(0x26, ec_master_state_t)
#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x27, ec_ioctl_link_state_t)
#define EC_IOCTL_APP_TIME EC_IOW(0x28, ec_ioctl_app_time_t)
#define EC_IOCTL_SYNC_REF EC_IO(0x29)
#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2a)
#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2b, uint32_t)
#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2c)
#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2d, uint32_t)
#define EC_IOCTL_RESET EC_IO(0x2e)
#define EC_IOCTL_SC_SYNC EC_IOW(0x2f, ec_ioctl_config_t)
#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x30, ec_ioctl_config_t)
#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x31, ec_ioctl_config_pdo_t)
#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x32, ec_ioctl_config_pdo_t)
#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x33, ec_ioctl_add_pdo_entry_t)
#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x34, ec_ioctl_config_pdo_t)
#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x35, ec_ioctl_reg_pdo_entry_t)
#define EC_IOCTL_SC_DC EC_IOW(0x36, ec_ioctl_config_t)
#define EC_IOCTL_SC_SDO EC_IOW(0x37, ec_ioctl_sc_sdo_t)
#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x38, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3a, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3b, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3c, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3d, ec_ioctl_reg_request_t)
#define EC_IOCTL_SC_VOE EC_IOWR(0x3e, ec_ioctl_voe_t)
#define EC_IOCTL_SC_STATE EC_IOWR(0x3f, ec_ioctl_sc_state_t)
#define EC_IOCTL_SC_IDN EC_IOW(0x40, ec_ioctl_sc_idn_t)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x41)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x42)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x43)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x44, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x45, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x46, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x47, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x48, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x49, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4b, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4c, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4d, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x4e, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x4f, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x50, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x51, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x52, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x53, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x54, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x55, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x56, size_t)
/*****************************************************************************/
@@ -748,12 +750,12 @@ typedef struct {
} ec_ioctl_context_t;
long ec_ioctl(ec_master_t *, ec_ioctl_context_t *, unsigned int,
void __user *);
void __user *);
#ifdef EC_RTDM
long ec_ioctl_rtdm(ec_master_t *, ec_ioctl_context_t *, unsigned int,
void __user *);
void __user *);
int ec_rtdm_mmap(ec_ioctl_context_t *, void **);
#endif

View File

@@ -234,7 +234,7 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
ec_datagram_init(&master->ref_sync_datagram);
snprintf(master->ref_sync_datagram.name, EC_DATAGRAM_NAME_SIZE,
"refsync");
ret = ec_datagram_apwr(&master->ref_sync_datagram, 0, 0x0910, 8);
ret = ec_datagram_prealloc(&master->ref_sync_datagram, 4);
if (ret < 0) {
ec_datagram_clear(&master->ref_sync_datagram);
EC_MASTER_ERR(master, "Failed to allocate reference"
@@ -265,7 +265,8 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
goto out_clear_sync;
}
ec_master_find_dc_ref_clock(master);
master->dc_ref_config = NULL;
master->dc_ref_clock = NULL;
// init character device
ret = ec_cdev_init(&master->cdev, master, device_number);
@@ -395,6 +396,8 @@ void ec_master_clear_slave_configs(ec_master_t *master)
{
ec_slave_config_t *sc, *next;
master->dc_ref_config = NULL;
list_for_each_entry_safe(sc, next, &master->configs, list) {
list_del(&sc->list);
ec_slave_config_clear(sc);
@@ -1872,18 +1875,52 @@ void ec_master_find_dc_ref_clock(
{
ec_slave_t *slave, *ref = NULL;
for (slave = master->slaves;
slave < master->slaves + master->slave_count;
slave++) {
if (slave->base_dc_supported && slave->has_dc_system_time) {
ref = slave;
break;
if (master->dc_ref_config) {
// Use application-selected reference clock
slave = master->dc_ref_config->slave;
if (slave) {
if (slave->base_dc_supported && slave->has_dc_system_time) {
ref = slave;
}
else {
EC_MASTER_WARN(master, "Slave %u can not act as a"
" DC reference clock!", slave->ring_position);
}
}
else {
EC_MASTER_WARN(master, "DC reference clock config (%u-%u)"
" has no slave attached!\n", master->dc_ref_config->alias,
master->dc_ref_config->position);
}
}
else {
// Use first slave with DC support as reference clock
for (slave = master->slaves;
slave < master->slaves + master->slave_count;
slave++) {
if (slave->base_dc_supported && slave->has_dc_system_time) {
ref = slave;
break;
}
}
}
master->dc_ref_clock = ref;
// This call always succeeds, because the datagram has been pre-allocated.
if (ref) {
EC_MASTER_INFO(master, "Using slave %u as DC reference clock.\n",
ref->ring_position);
}
else {
EC_MASTER_INFO(master, "No DC reference clock found.\n");
}
// These calls always succeed, because the
// datagrams have been pre-allocated.
ec_datagram_fpwr(&master->ref_sync_datagram,
ref ? ref->station_address : 0xffff, 0x0910, 4);
ec_datagram_frmw(&master->sync_datagram,
ref ? ref->station_address : 0xffff, 0x0910, 4);
}
@@ -2392,6 +2429,26 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
/*****************************************************************************/
int ecrt_master_select_reference_clock(ec_master_t *master,
ec_slave_config_t *sc)
{
if (sc) {
ec_slave_t *slave = sc->slave;
// output an early warning
if (slave &&
(!slave->base_dc_supported || !slave->has_dc_system_time)) {
EC_MASTER_WARN(master, "Slave %u can not act as"
" a reference clock!", slave->ring_position);
}
}
master->dc_ref_config = sc;
return 0;
}
/*****************************************************************************/
int ecrt_master(ec_master_t *master, ec_master_info_t *master_info)
{
EC_MASTER_DBG(master, 1, "ecrt_master(master = 0x%p,"
@@ -2525,6 +2582,25 @@ void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
/*****************************************************************************/
int ecrt_master_reference_clock_time(ec_master_t *master, uint32_t *time)
{
if (!master->dc_ref_clock) {
return -ENXIO;
}
if (master->sync_datagram.state != EC_DATAGRAM_RECEIVED) {
return -EIO;
}
// Get returned datagram time, transmission delay removed.
*time = EC_READ_U32(master->sync_datagram.data) -
master->dc_ref_clock->transmission_delay;
return 0;
}
/*****************************************************************************/
void ecrt_master_sync_reference_clock(ec_master_t *master)
{
EC_WRITE_U32(master->ref_sync_datagram.data, master->app_time);
@@ -2985,11 +3061,13 @@ EXPORT_SYMBOL(ecrt_master_callbacks);
EXPORT_SYMBOL(ecrt_master);
EXPORT_SYMBOL(ecrt_master_get_slave);
EXPORT_SYMBOL(ecrt_master_slave_config);
EXPORT_SYMBOL(ecrt_master_select_reference_clock);
EXPORT_SYMBOL(ecrt_master_state);
EXPORT_SYMBOL(ecrt_master_link_state);
EXPORT_SYMBOL(ecrt_master_application_time);
EXPORT_SYMBOL(ecrt_master_sync_reference_clock);
EXPORT_SYMBOL(ecrt_master_sync_slave_clocks);
EXPORT_SYMBOL(ecrt_master_reference_clock_time);
EXPORT_SYMBOL(ecrt_master_sync_monitor_queue);
EXPORT_SYMBOL(ecrt_master_sync_monitor_process);
EXPORT_SYMBOL(ecrt_master_sdo_download);

View File

@@ -224,6 +224,8 @@ struct ec_master {
compensation. */
ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation
monitoring. */
ec_slave_config_t *dc_ref_config; /**< Application-selected DC reference
clock slave config. */
ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */
unsigned int scan_busy; /**< Current scan state. */