DC cyclic operation and slave configuration. TBC...

This commit is contained in:
Florian Pose 2009-04-09 09:17:41 +00:00
parent 07ab460d36
commit e3b1d8e573
6 changed files with 220 additions and 6 deletions

1
NEWS
View File

@ -10,6 +10,7 @@ Changes since 1.4.0:
* Added a userspace library for accessing the application interface. This
library is licensed under LGPLv2.
* Added distributed clocks support.
* Added VoE mailbox protocol support.
* Separated datagram initialization from filling the payload with zeros.
Introduced new method ec_datagram_zero() for that.

6
TODO
View File

@ -10,6 +10,10 @@ vim: spelllang=en spell
Version 1.5.0:
* Distributed clocks:
- Delay calculation.
- Synchronize the reference clock to the master clock.
* Read alias from register 0x0012 instead of SII.
* Output link state in 'ethercat master'.
* Finish library implementation.
* Re-work EoE code.
@ -22,12 +26,10 @@ Version 1.5.0:
* Check force_config flag before error.
* Remove allow_scanning flag.
* Test File access over EtherCAT (FoE) reading.
* Distributed clocks.
* Implement ecrt_master_slave() in kernel space.
* Check for ioctl() interface version.
* Improve application-triggered SDO transfers by moving the statemachine into
the SDO handlers.
* FoE in application interface?
* Apply watchdog patches from J. Mohre.
Future issues:

View File

@ -41,6 +41,10 @@
*
* Changes in version 1.5:
*
* - Added the distributed clocks feature and the respective methods
* ecrt_slave_config_dc_assign_activate() and
* ecrt_slave_config_dc_sync_cycle_times() to configure a slave for cyclic
* operation.
* - Changed the meaning of the negative return values of
* ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
* - Imlemented the Vendor-specific over EtherCAT mailbox protocol. See
@ -671,6 +675,25 @@ int ecrt_slave_config_reg_pdo_entry(
is desired */
);
/** Sets the AssignActivate word necessary for DC operation.
*
* The AssignActivate word is vendor-specific and can be taken from the XML
* device description file (Device -> Dc -> AssignActivate). Set this to zero,
* if the slave shall be not operated without distributed clocks (default).
*/
void ecrt_slave_config_dc_assign_activate(
ec_slave_config_t *sc, /**< Slave configuration. */
uint16_t assign_activate /**< AssignActivate word. */
);
/** Sets the cylce times for the SYNC0 and SYNC1 signals.
*/
void ecrt_slave_config_dc_sync_cycle_times(
ec_slave_config_t *sc, /**< Slave configuration. */
uint32_t sync0_cycle_time, /**< SYNC0 cycle time [ns]. */
uint32_t sync1_cycle_time /**< SYNC1 cycle time [ns]. */
);
/** Add an SDO configuration.
*
* An SDO configuration is stored in the slave configuration object and is

View File

@ -52,6 +52,9 @@ void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *);
@ -63,6 +66,8 @@ void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_dc_assign(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *);
@ -602,6 +607,7 @@ void ec_fsm_slave_config_enter_sdo_conf(
ec_slave_t *slave = fsm->slave;
// No CoE configuration to be applied?
// FIXME check for config
if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
ec_fsm_slave_config_enter_pdo_conf(fsm);
return;
@ -805,7 +811,7 @@ void ec_fsm_slave_config_enter_fmmu(
}
if (!slave->base_fmmu_count) { // skip FMMU configuration
ec_fsm_slave_config_enter_safeop(fsm);
ec_fsm_slave_config_enter_dc_cycle(fsm);
return;
}
@ -861,6 +867,161 @@ void ec_fsm_slave_config_state_fmmu(
return;
}
ec_fsm_slave_config_enter_dc_cycle(fsm);
}
/*****************************************************************************/
/** Check for DCs to be configured.
*/
void ec_fsm_slave_config_enter_dc_cycle(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
ec_slave_config_t *config = slave->config;
if (config->dc_assign_activate) {
if (!slave->base_dc_supported) {
EC_WARN("Attempt to enable synchronized mode for slave %u,"
" that seems not to support distributed clocks!\n",
slave->ring_position);
}
// set DC cycle times
ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
EC_WRITE_U32(datagram->data, config->dc_sync_cycle_times[0]);
EC_WRITE_U32(datagram->data + 4, config->dc_sync_cycle_times[1]);
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_slave_config_state_dc_cycle;
} else {
ec_fsm_slave_config_enter_dc_assign(fsm);
}
}
/*****************************************************************************/
/** Slave configuration state: DC CYCLE.
*/
void ec_fsm_slave_config_state_dc_cycle(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
fsm->state = ec_fsm_slave_config_state_error;
EC_ERR("Failed to receive DC cycle times datagram for slave %u"
" (datagram state %u).\n",
slave->ring_position, datagram->state);
return;
}
if (datagram->working_counter != 1) {
slave->error_flag = 1;
fsm->state = ec_fsm_slave_config_state_error;
EC_ERR("Failed to set DC cycle times of slave %u: ",
slave->ring_position);
ec_datagram_print_wc_error(datagram);
return;
}
// set DC start time
ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
EC_WRITE_U64(datagram->data, 0x37E11D600ULL); // 15 s, FIXME
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_slave_config_state_dc_start;
}
/*****************************************************************************/
/** Slave configuration state: DC START.
*/
void ec_fsm_slave_config_state_dc_start(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
fsm->state = ec_fsm_slave_config_state_error;
EC_ERR("Failed to receive DC start time datagram for slave %u"
" (datagram state %u).\n",
slave->ring_position, datagram->state);
return;
}
if (datagram->working_counter != 1) {
slave->error_flag = 1;
fsm->state = ec_fsm_slave_config_state_error;
EC_ERR("Failed to set DC start time of slave %u: ",
slave->ring_position);
ec_datagram_print_wc_error(datagram);
return;
}
ec_fsm_slave_config_enter_dc_assign(fsm);
}
/*****************************************************************************/
/** Set the DC AssignActivate word.
*/
void ec_fsm_slave_config_enter_dc_assign(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
ec_slave_config_t *config = slave->config;
// assign sync unit to EtherCAT or PDI
ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
EC_WRITE_U16(datagram->data, config->dc_assign_activate);
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_slave_config_state_dc_assign;
}
/*****************************************************************************/
/** Slave configuration state: DC ASSIGN.
*/
void ec_fsm_slave_config_state_dc_assign(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
return;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
fsm->state = ec_fsm_slave_config_state_error;
EC_ERR("Failed to receive DC activation datagram for slave %u"
" (datagram state %u).\n",
slave->ring_position, datagram->state);
return;
}
if (datagram->working_counter != 1) {
slave->error_flag = 1;
fsm->state = ec_fsm_slave_config_state_error;
EC_ERR("Failed to set DC cyclia operation state of slave %u: ",
slave->ring_position);
ec_datagram_print_wc_error(datagram);
return;
}
ec_fsm_slave_config_enter_safeop(fsm);
}

View File

@ -61,20 +61,26 @@ void ec_slave_config_init(
unsigned int i;
sc->master = master;
sc->alias = alias;
sc->position = position;
sc->vendor_id = vendor_id;
sc->product_code = product_code;
sc->slave = NULL;
for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++)
ec_sync_config_init(&sc->sync_configs[i]);
sc->used_fmmus = 0;
sc->dc_assign_activate = 0x0000;
sc->dc_sync_cycle_times[0] = 0x00000000;
sc->dc_sync_cycle_times[1] = 0x00000000;
INIT_LIST_HEAD(&sc->sdo_configs);
INIT_LIST_HEAD(&sc->sdo_requests);
INIT_LIST_HEAD(&sc->voe_handlers);
sc->used_fmmus = 0;
}
/*****************************************************************************/
@ -399,7 +405,7 @@ ec_voe_handler_t *ec_slave_config_find_voe_handler(
}
/******************************************************************************
* Realtime interface
* Application interface
*****************************************************************************/
int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index,
@ -665,6 +671,22 @@ int ecrt_slave_config_reg_pdo_entry(
return -ENOENT;
}
/*****************************************************************************/
void ecrt_slave_config_dc_assign_activate(ec_slave_config_t *sc,
uint16_t assign_activate)
{
sc->dc_assign_activate = assign_activate;
}
/*****************************************************************************/
void ecrt_slave_config_dc_sync_cycle_times(ec_slave_config_t *sc,
uint32_t sync0_cycle_time, uint32_t sync1_cycle_time)
{
sc->dc_sync_cycle_times[0] = sync0_cycle_time;
sc->dc_sync_cycle_times[1] = sync1_cycle_time;
}
/*****************************************************************************/
@ -880,6 +902,8 @@ EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_add);
EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_clear);
EXPORT_SYMBOL(ecrt_slave_config_pdos);
EXPORT_SYMBOL(ecrt_slave_config_reg_pdo_entry);
EXPORT_SYMBOL(ecrt_slave_config_dc_assign_activate);
EXPORT_SYMBOL(ecrt_slave_config_dc_sync_cycle_times);
EXPORT_SYMBOL(ecrt_slave_config_sdo);
EXPORT_SYMBOL(ecrt_slave_config_sdo8);
EXPORT_SYMBOL(ecrt_slave_config_sdo16);

View File

@ -66,6 +66,9 @@ struct ec_slave_config {
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
uint8_t used_fmmus; /**< Number of FMMUs used. */
uint16_t dc_assign_activate; /**< Vendor-specific AssignActivate word. */
uint32_t dc_sync_cycle_times[2]; /**< SYNC[0,1] cycle times. */
struct list_head sdo_configs; /**< List of SDO configurations. */
struct list_head sdo_requests; /**< List of SDO requests. */
struct list_head voe_handlers; /**< List of VoE handlers. */