Write DC system time offsets right after slave scan / config change. Wait for DC clock discipline.
This commit is contained in:
parent
a05a56429a
commit
9c91630351
1
TODO
1
TODO
|
|
@ -41,6 +41,7 @@ Version 1.5.0:
|
|||
* Log SoE IDNs with real name ([SP]-x-yyyy).
|
||||
* Output SoE IDN configurations in 'ethercat config'.
|
||||
* Fix casting away constness during expected WC calculation.
|
||||
* Only set system time offset, if application time is present.
|
||||
* Read AL status code on spontaneous state change.
|
||||
|
||||
Future issues:
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Time difference [ns] to tolerate without setting a new system time offset.
|
||||
*/
|
||||
#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_fsm_master_state_start(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_broadcast(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_read_state(ec_fsm_master_t *);
|
||||
|
|
@ -54,11 +60,14 @@ void ec_fsm_master_state_configure_slave(ec_fsm_master_t *);
|
|||
void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_dc_measure_delays(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_scan_slave(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_dc_read_offset(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_dc_write_offset(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_write_sii(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_sdo_request(ec_fsm_master_t *);
|
||||
void ec_fsm_master_state_reg_request(ec_fsm_master_t *);
|
||||
|
||||
void ec_fsm_master_enter_write_system_times(ec_fsm_master_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -290,13 +299,25 @@ void ec_fsm_master_state_broadcast(
|
|||
}
|
||||
|
||||
if (master->slave_count) {
|
||||
// fetch state from first slave
|
||||
fsm->slave = master->slaves;
|
||||
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
|
||||
0x0130, 2);
|
||||
ec_datagram_zero(datagram);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_master_state_read_state;
|
||||
|
||||
// application applied configurations
|
||||
if (master->config_changed) {
|
||||
master->config_changed = 0;
|
||||
|
||||
EC_MASTER_DBG(master, 1, "Configuration changed.\n");
|
||||
|
||||
fsm->slave = master->slaves; // begin with first slave
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
|
||||
} else {
|
||||
// fetch state from first slave
|
||||
fsm->slave = master->slaves;
|
||||
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
|
||||
0x0130, 2);
|
||||
ec_datagram_zero(datagram);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_master_state_read_state;
|
||||
}
|
||||
} else {
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
|
|
@ -787,7 +808,12 @@ void ec_fsm_master_state_scan_slave(
|
|||
ec_master_eoe_start(master);
|
||||
#endif
|
||||
|
||||
ec_fsm_master_restart(fsm);
|
||||
if (master->slave_count) {
|
||||
fsm->slave = master->slaves; // begin with first slave
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
} else {
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -821,6 +847,208 @@ void ec_fsm_master_state_configure_slave(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Start writing DC system times.
|
||||
*/
|
||||
void ec_fsm_master_enter_write_system_times(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = fsm->master;
|
||||
|
||||
EC_MASTER_DBG(master, 1, "Writing system time offsets...\n");
|
||||
|
||||
if (master->has_app_time) {
|
||||
while (fsm->slave < master->slaves + master->slave_count) {
|
||||
if (!fsm->slave->base_dc_supported
|
||||
|| !fsm->slave->has_dc_system_time) {
|
||||
fsm->slave++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// read DC system time (0x0910, 64 bit)
|
||||
// gap (64 bit)
|
||||
// and time offset (0x0920, 64 bit)
|
||||
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
|
||||
0x0910, 24);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_master_state_dc_read_offset;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
EC_MASTER_DBG(master, 1, "No app_time received up to now.\n");
|
||||
}
|
||||
|
||||
ec_master_request_op(master);
|
||||
ec_fsm_master_restart(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure 32 bit time offset.
|
||||
*/
|
||||
u64 ec_fsm_master_dc_offset32(
|
||||
ec_fsm_master_t *fsm, /**< Master state machine. */
|
||||
u64 system_time, /**< System time register. */
|
||||
u64 old_offset, /**< Time offset register. */
|
||||
unsigned long jiffies_since_read /**< Jiffies for correction. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u32 correction, system_time32, old_offset32, new_offset;
|
||||
s32 time_diff;
|
||||
|
||||
system_time32 = (u32) system_time;
|
||||
old_offset32 = (u32) old_offset;
|
||||
|
||||
// correct read system time by elapsed time since read operation
|
||||
correction = jiffies_since_read * 1000 / HZ * 1000000;
|
||||
system_time32 += correction;
|
||||
time_diff = (u32) slave->master->app_time - system_time32;
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
|
||||
" system_time=%u (corrected with %u),"
|
||||
" app_time=%u, diff=%i\n",
|
||||
system_time32, correction,
|
||||
(u32) slave->master->app_time, time_diff);
|
||||
|
||||
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
|
||||
new_offset = time_diff + old_offset32;
|
||||
EC_SLAVE_DBG(slave, 1, "Setting time offset to %u (was %u)\n",
|
||||
new_offset, old_offset32);
|
||||
return (u64) new_offset;
|
||||
} else {
|
||||
EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
|
||||
return old_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure 64 bit time offset.
|
||||
*/
|
||||
u64 ec_fsm_master_dc_offset64(
|
||||
ec_fsm_master_t *fsm, /**< Master state machine. */
|
||||
u64 system_time, /**< System time register. */
|
||||
u64 old_offset, /**< Time offset register. */
|
||||
unsigned long jiffies_since_read /**< Jiffies for correction. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u64 new_offset, correction;
|
||||
s64 time_diff;
|
||||
|
||||
// correct read system time by elapsed time since read operation
|
||||
correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000;
|
||||
system_time += correction;
|
||||
time_diff = fsm->slave->master->app_time - system_time;
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
|
||||
" system_time=%llu (corrected with %llu),"
|
||||
" app_time=%llu, diff=%lli\n",
|
||||
system_time, correction,
|
||||
slave->master->app_time, time_diff);
|
||||
|
||||
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
|
||||
new_offset = time_diff + old_offset;
|
||||
EC_SLAVE_DBG(slave, 1, "Setting time offset to %llu (was %llu)\n",
|
||||
new_offset, old_offset);
|
||||
} else {
|
||||
new_offset = old_offset;
|
||||
EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
|
||||
}
|
||||
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state: DC READ OFFSET.
|
||||
*/
|
||||
void ec_fsm_master_state_dc_read_offset(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u64 system_time, old_offset, new_offset;
|
||||
unsigned long jiffies_since_read;
|
||||
|
||||
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
|
||||
return;
|
||||
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
EC_SLAVE_ERR(slave, "Failed to receive DC times datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
fsm->slave++;
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
EC_SLAVE_WARN(slave, "Failed to get DC times: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
fsm->slave++;
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
system_time = EC_READ_U64(datagram->data); // 0x0910
|
||||
old_offset = EC_READ_U64(datagram->data + 16); // 0x0920
|
||||
jiffies_since_read = jiffies - datagram->jiffies_sent;
|
||||
|
||||
if (slave->base_dc_range == EC_DC_32) {
|
||||
new_offset = ec_fsm_master_dc_offset32(fsm,
|
||||
system_time, old_offset, jiffies_since_read);
|
||||
} else {
|
||||
new_offset = ec_fsm_master_dc_offset64(fsm,
|
||||
system_time, old_offset, jiffies_since_read);
|
||||
}
|
||||
|
||||
// set DC system time offset and transmission delay
|
||||
ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12);
|
||||
EC_WRITE_U64(datagram->data, new_offset);
|
||||
EC_WRITE_U32(datagram->data + 8, slave->transmission_delay);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_master_state_dc_write_offset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state: DC WRITE OFFSET.
|
||||
*/
|
||||
void ec_fsm_master_state_dc_write_offset(
|
||||
ec_fsm_master_t *fsm /**< Master 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) {
|
||||
EC_SLAVE_ERR(slave,
|
||||
"Failed to receive DC system time offset datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
fsm->slave++;
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
EC_SLAVE_ERR(slave, "Failed to set DC system time offset: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
fsm->slave++;
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
fsm->slave++;
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state: WRITE SII.
|
||||
*/
|
||||
void ec_fsm_master_state_write_sii(
|
||||
|
|
|
|||
|
|
@ -44,9 +44,20 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Time difference [ns] to tolerate without setting a new system time offset.
|
||||
/** Maximum clock difference (in ns) before going to SAFEOP.
|
||||
*
|
||||
* Wait for DC time difference to drop under this absolute value before
|
||||
* requesting SAFEOP.
|
||||
*/
|
||||
#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000
|
||||
#define EC_DC_MAX_SYNC_DIFF_NS 5000
|
||||
|
||||
/** Maximum time (in ms) to wait for clock discipline.
|
||||
*/
|
||||
#define EC_DC_SYNC_WAIT_MS 5000
|
||||
|
||||
/** Time offset (in ns), that is added to cyclic start time.
|
||||
*/
|
||||
#define EC_DC_START_OFFSET 100000000ULL
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -55,8 +66,6 @@ void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *);
|
|||
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_dc_read_offset(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_dc_write_offset(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *);
|
||||
|
|
@ -67,6 +76,7 @@ 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_sync_check(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 *);
|
||||
|
|
@ -391,172 +401,6 @@ void ec_fsm_slave_config_state_dc_clear_assign(
|
|||
ec_datagram_print_wc_error(datagram);
|
||||
}
|
||||
|
||||
// read DC system time (0x0910, 64 bit)
|
||||
// gap (64 bit)
|
||||
// and time offset (0x0920, 64 bit)
|
||||
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0910, 24);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_config_state_dc_read_offset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure 32 bit time offset.
|
||||
*/
|
||||
u64 ec_fsm_slave_config_dc_offset32(
|
||||
ec_fsm_slave_config_t *fsm, /**< slave state machine */
|
||||
u64 system_time, /**< System time register. */
|
||||
u64 old_offset, /**< Time offset register. */
|
||||
unsigned long jiffies_since_read /**< Jiffies for correction. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u32 correction, system_time32, old_offset32, new_offset;
|
||||
s32 time_diff;
|
||||
|
||||
system_time32 = (u32) system_time;
|
||||
old_offset32 = (u32) old_offset;
|
||||
|
||||
// correct read system time by elapsed time since read operation
|
||||
correction = jiffies_since_read * 1000 / HZ * 1000000;
|
||||
system_time32 += correction;
|
||||
time_diff = (u32) slave->master->app_time - system_time32;
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "Calculating DC time offset (32 bit):"
|
||||
" system_time=%u (corrected with %u), app_time=%u, diff=%i\n",
|
||||
system_time32, correction,
|
||||
(u32) slave->master->app_time, time_diff);
|
||||
|
||||
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
|
||||
new_offset = time_diff + old_offset32;
|
||||
EC_SLAVE_DBG(slave, 1, "Setting time offset to %u (was %u)\n",
|
||||
new_offset, old_offset32);
|
||||
return (u64) new_offset;
|
||||
} else {
|
||||
EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
|
||||
return old_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure 64 bit time offset.
|
||||
*/
|
||||
u64 ec_fsm_slave_config_dc_offset64(
|
||||
ec_fsm_slave_config_t *fsm, /**< slave state machine */
|
||||
u64 system_time, /**< System time register. */
|
||||
u64 old_offset, /**< Time offset register. */
|
||||
unsigned long jiffies_since_read /**< Jiffies for correction. */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u64 new_offset, correction;
|
||||
s64 time_diff;
|
||||
|
||||
// correct read system time by elapsed time since read operation
|
||||
correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000;
|
||||
system_time += correction;
|
||||
time_diff = fsm->slave->master->app_time - system_time;
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "Calculating DC time offset (64 bit):"
|
||||
" system_time=%llu (corrected with %llu),"
|
||||
" app_time=%llu, diff=%lli\n",
|
||||
system_time, correction,
|
||||
slave->master->app_time, time_diff);
|
||||
|
||||
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
|
||||
new_offset = time_diff + old_offset;
|
||||
EC_SLAVE_DBG(slave, 1, "Setting time offset to %llu (was %llu)\n",
|
||||
new_offset, old_offset);
|
||||
} else {
|
||||
new_offset = old_offset;
|
||||
EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
|
||||
}
|
||||
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave configuration state: DC READ OFFSET.
|
||||
*/
|
||||
void ec_fsm_slave_config_state_dc_read_offset(
|
||||
ec_fsm_slave_config_t *fsm /**< slave state machine */
|
||||
)
|
||||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
u64 system_time, old_offset, new_offset;
|
||||
unsigned long jiffies_since_read;
|
||||
|
||||
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_SLAVE_ERR(slave, "Failed to receive DC times datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
slave->error_flag = 1;
|
||||
fsm->state = ec_fsm_slave_config_state_error;
|
||||
EC_SLAVE_ERR(slave, "Failed to get DC times: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
system_time = EC_READ_U64(datagram->data); // 0x0910
|
||||
old_offset = EC_READ_U64(datagram->data + 16); // 0x0920
|
||||
jiffies_since_read = jiffies - datagram->jiffies_sent;
|
||||
|
||||
if (slave->base_dc_range == EC_DC_32) {
|
||||
new_offset = ec_fsm_slave_config_dc_offset32(fsm,
|
||||
system_time, old_offset, jiffies_since_read);
|
||||
} else {
|
||||
new_offset = ec_fsm_slave_config_dc_offset64(fsm,
|
||||
system_time, old_offset, jiffies_since_read);
|
||||
}
|
||||
|
||||
// set DC system time offset and transmission delay
|
||||
ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12);
|
||||
EC_WRITE_U64(datagram->data, new_offset);
|
||||
EC_WRITE_U32(datagram->data + 8, slave->transmission_delay);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_config_state_dc_write_offset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave configuration state: DC WRITE OFFSET.
|
||||
*/
|
||||
void ec_fsm_slave_config_state_dc_write_offset(
|
||||
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_SLAVE_ERR(slave, "Failed to receive DC system time offset"
|
||||
" datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
slave->error_flag = 1;
|
||||
fsm->state = ec_fsm_slave_config_state_error;
|
||||
EC_SLAVE_ERR(slave, "Failed to set DC system time offset: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
ec_fsm_slave_config_enter_mbox_sync(fsm);
|
||||
}
|
||||
|
||||
|
|
@ -1319,10 +1163,7 @@ void ec_fsm_slave_config_state_dc_cycle(
|
|||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_master_t *master = slave->master;
|
||||
ec_slave_config_t *config = slave->config;
|
||||
ec_sync_signal_t *sync0 = &config->dc_sync[0];
|
||||
u64 start_time;
|
||||
|
||||
if (!config) { // config removed in the meantime
|
||||
ec_fsm_slave_config_reconfigure(fsm);
|
||||
|
|
@ -1347,13 +1188,83 @@ void ec_fsm_slave_config_state_dc_cycle(
|
|||
return;
|
||||
}
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
|
||||
|
||||
fsm->jiffies_start = jiffies;
|
||||
ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_config_state_dc_sync_check;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Slave configuration state: DC SYNC CHECK.
|
||||
*/
|
||||
void ec_fsm_slave_config_state_dc_sync_check(
|
||||
ec_fsm_slave_config_t *fsm /**< slave state machine */
|
||||
)
|
||||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_master_t *master = slave->master;
|
||||
ec_slave_config_t *config = slave->config;
|
||||
uint32_t abs_sync_diff;
|
||||
unsigned long diff_ms;
|
||||
ec_sync_signal_t *sync0 = &config->dc_sync[0];
|
||||
u64 start_time;
|
||||
|
||||
if (!config) { // config removed in the meantime
|
||||
ec_fsm_slave_config_reconfigure(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
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_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
|
||||
ec_datagram_print_state(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
slave->error_flag = 1;
|
||||
fsm->state = ec_fsm_slave_config_state_error;
|
||||
EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
|
||||
diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
|
||||
|
||||
if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
|
||||
|
||||
if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
|
||||
EC_SLAVE_WARN(slave, "Slave did not sync after %u ms.\n",
|
||||
(u32) diff_ms);
|
||||
} else {
|
||||
EC_SLAVE_DBG(slave, 1, "Sync after %4u ms: %10u ns\n",
|
||||
(u32) diff_ms, abs_sync_diff);
|
||||
|
||||
// check synchrony again
|
||||
ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
EC_SLAVE_DBG(slave, 1, "%u ns difference after %u ms.\n",
|
||||
abs_sync_diff, (u32) diff_ms);
|
||||
}
|
||||
|
||||
// set DC start time
|
||||
start_time = master->app_time + 100000000ULL; // now + X ns
|
||||
start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
|
||||
// FIXME use slave's local system time here?
|
||||
|
||||
if (sync0->cycle_time) {
|
||||
// find correct phase
|
||||
if (master->has_start_time) {
|
||||
if (master->has_app_time) {
|
||||
u64 diff, start;
|
||||
u32 remainder;
|
||||
|
||||
|
|
@ -1363,20 +1274,13 @@ void ec_fsm_slave_config_state_dc_cycle(
|
|||
start = start_time +
|
||||
sync0->cycle_time - remainder + sync0->shift_time;
|
||||
|
||||
if (master->debug_level) {
|
||||
EC_SLAVE_DBG(slave, 1, "app_start_time=%llu\n",
|
||||
master->app_start_time);
|
||||
EC_SLAVE_DBG(slave, 1, " start_time=%llu\n",
|
||||
start_time);
|
||||
EC_SLAVE_DBG(slave, 1, " cycle_time=%u\n",
|
||||
sync0->cycle_time);
|
||||
EC_SLAVE_DBG(slave, 1, " shift_time=%u\n",
|
||||
sync0->shift_time);
|
||||
EC_SLAVE_DBG(slave, 1, " remainder=%u\n",
|
||||
remainder);
|
||||
EC_SLAVE_DBG(slave, 1, " start=%llu\n",
|
||||
start);
|
||||
}
|
||||
EC_SLAVE_DBG(slave, 1, "app_start_time=%llu\n",
|
||||
master->app_start_time);
|
||||
EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
|
||||
EC_SLAVE_DBG(slave, 1, " cycle_time=%u\n", sync0->cycle_time);
|
||||
EC_SLAVE_DBG(slave, 1, " shift_time=%u\n", sync0->shift_time);
|
||||
EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
|
||||
EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
|
||||
start_time = start;
|
||||
} else {
|
||||
EC_SLAVE_WARN(slave, "No application time supplied."
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
master->phase = EC_ORPHANED;
|
||||
master->active = 0;
|
||||
master->config_changed = 0;
|
||||
master->injection_seq_fsm = 0;
|
||||
master->injection_seq_rt = 0;
|
||||
|
||||
|
|
@ -149,7 +150,7 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
master->app_time = 0ULL;
|
||||
master->app_start_time = 0ULL;
|
||||
master->has_start_time = 0;
|
||||
master->has_app_time = 0;
|
||||
|
||||
master->scan_busy = 0;
|
||||
master->allow_scan = 1;
|
||||
|
|
@ -1824,6 +1825,37 @@ void ec_master_calc_dc(
|
|||
ec_master_calc_transmission_delays(master);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Request OP state for configured slaves.
|
||||
*/
|
||||
void ec_master_request_op(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
)
|
||||
{
|
||||
unsigned int i;
|
||||
ec_slave_t *slave;
|
||||
|
||||
if (!master->active)
|
||||
return;
|
||||
|
||||
EC_MASTER_DBG(master, 1, "Requesting OP...\n");
|
||||
|
||||
// request OP for all configured slaves
|
||||
for (i = 0; i < master->slave_count; i++) {
|
||||
slave = master->slaves + i;
|
||||
if (slave->config) {
|
||||
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
|
||||
}
|
||||
}
|
||||
|
||||
// always set DC reference clock to OP
|
||||
if (master->dc_ref_clock) {
|
||||
ec_slave_request_state(master->dc_ref_clock,
|
||||
EC_SLAVE_STATE_OP);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Application interface
|
||||
*****************************************************************************/
|
||||
|
|
@ -1906,11 +1938,6 @@ int ecrt_master_activate(ec_master_t *master)
|
|||
domain_offset += domain->data_size;
|
||||
}
|
||||
|
||||
// always set DC reference clock to OP
|
||||
if (master->dc_ref_clock) {
|
||||
ec_slave_request_state(master->dc_ref_clock, EC_SLAVE_STATE_OP);
|
||||
}
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
// restart EoE process and master thread with new locking
|
||||
|
|
@ -1945,6 +1972,10 @@ int ecrt_master_activate(ec_master_t *master)
|
|||
master->allow_config = 1; // request the current configuration
|
||||
master->allow_scan = 1; // allow re-scanning on topology change
|
||||
master->active = 1;
|
||||
|
||||
// notify state machine, that the configuration shall now be applied
|
||||
master->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2004,7 +2035,7 @@ void ecrt_master_deactivate(ec_master_t *master)
|
|||
|
||||
master->app_time = 0ULL;
|
||||
master->app_start_time = 0ULL;
|
||||
master->has_start_time = 0;
|
||||
master->has_app_time = 0;
|
||||
|
||||
#ifdef EC_EOE
|
||||
if (eoe_was_running) {
|
||||
|
|
@ -2258,9 +2289,9 @@ void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
|
|||
{
|
||||
master->app_time = app_time;
|
||||
|
||||
if (unlikely(!master->has_start_time)) {
|
||||
if (unlikely(!master->has_app_time)) {
|
||||
master->app_start_time = app_time;
|
||||
master->has_start_time = 1;
|
||||
master->has_app_time = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ struct ec_master {
|
|||
ec_datagram_t fsm_datagram; /**< Datagram used for state machines. */
|
||||
ec_master_phase_t phase; /**< Master phase. */
|
||||
unsigned int active; /**< Master has been activated. */
|
||||
unsigned int config_changed; /**< The configuration changed. */
|
||||
unsigned int injection_seq_fsm; /**< Datagram injection sequence number
|
||||
for the FSM side. */
|
||||
unsigned int injection_seq_rt; /**< Datagram injection sequence number
|
||||
|
|
@ -177,7 +178,7 @@ struct ec_master {
|
|||
|
||||
u64 app_time; /**< Time of the last ecrt_master_sync() call. */
|
||||
u64 app_start_time; /**< Application start time. */
|
||||
u8 has_start_time; /**< Start time already taken. */
|
||||
u8 has_app_time; /**< Application time is valid. */
|
||||
ec_datagram_t ref_sync_datagram; /**< Datagram used for synchronizing the
|
||||
reference clock to the master clock. */
|
||||
ec_datagram_t sync_datagram; /**< Datagram used for DC drift
|
||||
|
|
@ -306,6 +307,7 @@ ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *, uint16_t,
|
|||
uint16_t, uint32_t, uint32_t);
|
||||
|
||||
void ec_master_calc_dc(ec_master_t *);
|
||||
void ec_master_request_op(ec_master_t *);
|
||||
|
||||
void ec_master_internal_send_cb(void *);
|
||||
void ec_master_internal_receive_cb(void *);
|
||||
|
|
|
|||
Loading…
Reference in New Issue