Added --enable-loop-control to make use of the loop control registers.

This commit is contained in:
Florian Pose 2015-02-20 16:06:23 +01:00
parent b4d4a98287
commit c81f24e68b
5 changed files with 349 additions and 30 deletions

View File

@ -1030,6 +1030,35 @@ else
AC_MSG_RESULT([no])
fi
#------------------------------------------------------------------------------
# use loop control registers to open slave ports
#------------------------------------------------------------------------------
AC_MSG_CHECKING([whether to use loop control registers])
AC_ARG_ENABLE([loop-control],
AS_HELP_STRING([--enable-loop-control],
[Use loop control registers (default: no)]),
[
case "${enableval}" in
yes) loopctl=1
;;
no) loopctl=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-loop-control])
;;
esac
],
[loopctl=0]
)
if test "x${loopctl}" = "x1"; then
AC_DEFINE([EC_LOOP_CONTROL], [1], [Use loop control registers])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
#------------------------------------------------------------------------------
AC_CONFIG_FILES([

View File

@ -54,10 +54,17 @@
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 *);
void ec_fsm_master_state_read_al_status(ec_fsm_master_t *);
#ifdef EC_LOOP_CONTROL
void ec_fsm_master_state_read_dl_status(ec_fsm_master_t *);
void ec_fsm_master_state_open_port(ec_fsm_master_t *);
#endif
void ec_fsm_master_state_acknowledge(ec_fsm_master_t *);
void ec_fsm_master_state_configure_slave(ec_fsm_master_t *);
void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *);
#ifdef EC_LOOP_CONTROL
void ec_fsm_master_state_loop_control(ec_fsm_master_t *);
#endif
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 *);
@ -415,7 +422,7 @@ void ec_fsm_master_state_broadcast(
ec_datagram_zero(datagram);
fsm->datagram->device_index = fsm->slave->device_index;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_read_state;
fsm->state = ec_fsm_master_state_read_al_status;
}
} else {
ec_fsm_master_restart(fsm);
@ -594,7 +601,7 @@ void ec_fsm_master_action_next_slave_state(
ec_datagram_zero(fsm->datagram);
fsm->datagram->device_index = fsm->slave->device_index;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_read_state;
fsm->state = ec_fsm_master_state_read_al_status;
return;
}
@ -604,6 +611,151 @@ void ec_fsm_master_action_next_slave_state(
/*****************************************************************************/
#ifdef EC_LOOP_CONTROL
/** Master action: Read DL status of current slave.
*/
void ec_fsm_master_action_read_dl_status(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0110, 2);
ec_datagram_zero(fsm->datagram);
fsm->datagram->device_index = fsm->slave->device_index;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_read_dl_status;
}
/*****************************************************************************/
/** Master action: Open slave port.
*/
void ec_fsm_master_action_open_port(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
EC_SLAVE_INFO(fsm->slave, "Opening ports.\n");
ec_datagram_fpwr(fsm->datagram, fsm->slave->station_address, 0x0101, 1);
EC_WRITE_U8(fsm->datagram->data, 0x54); // port 0 auto, 1-3 auto-close
fsm->datagram->device_index = fsm->slave->device_index;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_open_port;
}
/*****************************************************************************/
/** Master state: READ DL STATUS.
*
* Fetches the DL state of a slave.
*/
void ec_fsm_master_state_read_dl_status(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_slave_t *slave = fsm->slave;
ec_datagram_t *datagram = fsm->datagram;
unsigned int i;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
return;
}
if (datagram->state != EC_DATAGRAM_RECEIVED) {
EC_SLAVE_ERR(slave, "Failed to receive AL state datagram: ");
ec_datagram_print_state(datagram);
ec_fsm_master_restart(fsm);
return;
}
// did the slave not respond to its station address?
if (datagram->working_counter != 1) {
// try again next time
ec_fsm_master_action_next_slave_state(fsm);
return;
}
ec_slave_set_dl_status(slave, EC_READ_U16(datagram->data));
// process port state machines
for (i = 0; i < EC_MAX_PORTS; i++) {
ec_slave_port_t *port = &slave->ports[i];
switch (port->state) {
case EC_SLAVE_PORT_DOWN:
if (port->link.loop_closed) {
if (port->link.link_up) {
port->link_detection_jiffies = jiffies;
port->state = EC_SLAVE_PORT_WAIT;
}
}
else { // loop open
port->state = EC_SLAVE_PORT_UP;
}
break;
case EC_SLAVE_PORT_WAIT:
if (port->link.link_up) {
if (jiffies - port->link_detection_jiffies >
HZ * EC_PORT_WAIT_MS / 1000) {
port->state = EC_SLAVE_PORT_UP;
ec_fsm_master_action_open_port(fsm);
return;
}
}
else { // link down
port->state = EC_SLAVE_PORT_DOWN;
}
break;
default: // EC_SLAVE_PORT_UP
if (!port->link.link_up) {
port->state = EC_SLAVE_PORT_DOWN;
}
break;
}
}
// process next slave
ec_fsm_master_action_next_slave_state(fsm);
}
/*****************************************************************************/
/** Master state: OPEN_PORT.
*
* Opens slave ports.
*/
void ec_fsm_master_state_open_port(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_slave_t *slave = fsm->slave;
ec_datagram_t *datagram = fsm->datagram;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
return;
}
if (datagram->state != EC_DATAGRAM_RECEIVED) {
EC_SLAVE_ERR(slave, "Failed to receive port open datagram: ");
ec_datagram_print_state(datagram);
ec_fsm_master_restart(fsm);
return;
}
// did the slave not respond to its station address?
if (datagram->working_counter != 1) {
EC_SLAVE_ERR(slave, "Did not respond to port open command!\n");
return;
}
// process next slave
ec_fsm_master_action_next_slave_state(fsm);
}
#endif
/*****************************************************************************/
/** Master action: Configure.
*/
void ec_fsm_master_action_configure(
@ -654,17 +806,22 @@ void ec_fsm_master_action_configure(
return;
}
#ifdef EC_LOOP_CONTROL
// read DL status
ec_fsm_master_action_read_dl_status(fsm);
#else
// process next slave
ec_fsm_master_action_next_slave_state(fsm);
#endif
}
/*****************************************************************************/
/** Master state: READ STATE.
/** Master state: READ AL STATUS.
*
* Fetches the AL state of a slave.
*/
void ec_fsm_master_state_read_state(
void ec_fsm_master_state_read_al_status(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
@ -694,7 +851,7 @@ void ec_fsm_master_state_read_state(
}
// A single slave responded
ec_slave_set_state(slave, EC_READ_U8(datagram->data));
ec_slave_set_al_status(slave, EC_READ_U8(datagram->data));
if (!slave->error_flag) {
// Check, if new slave state has to be acknowledged
@ -711,8 +868,13 @@ void ec_fsm_master_state_read_state(
return;
}
// slave has error flag set; process next one
#ifdef EC_LOOP_CONTROL
// read DL status
ec_fsm_master_action_read_dl_status(fsm);
#else
// process next slave
ec_fsm_master_action_next_slave_state(fsm);
#endif
}
/*****************************************************************************/
@ -755,6 +917,73 @@ void ec_fsm_master_enter_clear_addresses(
/*****************************************************************************/
/** Start measuring DC delays.
*/
void ec_fsm_master_enter_dc_measure_delays(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
EC_MASTER_DBG(fsm->master, 1, "Sending broadcast-write"
" to measure transmission delays on %s link.\n",
ec_device_names[fsm->dev_idx != 0]);
ec_datagram_bwr(fsm->datagram, 0x0900, 1);
ec_datagram_zero(fsm->datagram);
fsm->datagram->device_index = fsm->dev_idx;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_dc_measure_delays;
}
/*****************************************************************************/
#ifdef EC_LOOP_CONTROL
/** Start writing loop control registers.
*/
void ec_fsm_master_enter_loop_control(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
EC_MASTER_DBG(fsm->master, 1, "Broadcast-writing"
" loop control registers on %s link.\n",
ec_device_names[fsm->dev_idx != 0]);
ec_datagram_bwr(fsm->datagram, 0x0101, 1);
EC_WRITE_U8(fsm->datagram->data, 0x54); // port 0 auto, 1-3 auto-close
fsm->datagram->device_index = fsm->dev_idx;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_loop_control;
}
/*****************************************************************************/
/** Master state: LOOP CONTROL.
*/
void ec_fsm_master_state_loop_control(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_master_t *master = fsm->master;
ec_datagram_t *datagram = fsm->datagram;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
return;
}
if (datagram->state != EC_DATAGRAM_RECEIVED) {
EC_MASTER_ERR(master, "Failed to receive loop control"
" datagram on %s link: ",
ec_device_names[fsm->dev_idx != 0]);
ec_datagram_print_state(datagram);
}
ec_fsm_master_enter_dc_measure_delays(fsm);
}
#endif
/*****************************************************************************/
/** Master state: CLEAR ADDRESSES.
*/
void ec_fsm_master_state_clear_addresses(
@ -786,15 +1015,11 @@ void ec_fsm_master_state_clear_addresses(
fsm->slaves_responding[fsm->dev_idx]);
}
EC_MASTER_DBG(master, 1, "Sending broadcast-write"
" to measure transmission delays on %s link.\n",
ec_device_names[fsm->dev_idx != 0]);
ec_datagram_bwr(datagram, 0x0900, 1);
ec_datagram_zero(datagram);
fsm->datagram->device_index = fsm->dev_idx;
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_master_state_dc_measure_delays;
#ifdef EC_LOOP_CONTROL
ec_fsm_master_enter_loop_control(fsm);
#else
ec_fsm_master_enter_dc_measure_delays(fsm);
#endif
}
/*****************************************************************************/
@ -947,7 +1172,14 @@ void ec_fsm_master_state_configure_slave(
}
fsm->idle = 1;
#ifdef EC_LOOP_CONTROL
// read DL status
ec_fsm_master_action_read_dl_status(fsm);
#else
// process next slave
ec_fsm_master_action_next_slave_state(fsm);
#endif
}
/*****************************************************************************/

View File

@ -493,8 +493,6 @@ void ec_fsm_slave_scan_state_datalink(
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
uint16_t dl_status;
unsigned int i;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
return;
@ -514,15 +512,7 @@ void ec_fsm_slave_scan_state_datalink(
return;
}
dl_status = EC_READ_U16(datagram->data);
for (i = 0; i < EC_MAX_PORTS; i++) {
slave->ports[i].link.link_up =
dl_status & (1 << (4 + i)) ? 1 : 0;
slave->ports[i].link.loop_closed =
dl_status & (1 << (8 + i * 2)) ? 1 : 0;
slave->ports[i].link.signal_detected =
dl_status & (1 << (9 + i * 2)) ? 1 : 0;
}
ec_slave_set_dl_status(slave, EC_READ_U16(datagram->data));
#ifdef EC_SII_ASSIGN
ec_fsm_slave_scan_enter_assign_sii(fsm);

View File

@ -95,7 +95,7 @@ void ec_slave_init(
slave->ports[i].desc = EC_PORT_NOT_IMPLEMENTED;
slave->ports[i].link.link_up = 0;
slave->ports[i].link.loop_closed = 0;
slave->ports[i].link.loop_closed = 1;
slave->ports[i].link.signal_detected = 0;
slave->sii.physical_layer[i] = 0xFF;
@ -103,6 +103,11 @@ void ec_slave_init(
slave->ports[i].next_slave = NULL;
slave->ports[i].delay_to_next_dc = 0U;
#ifdef EC_LOOP_CONTROL
slave->ports[i].state = EC_SLAVE_PORT_DOWN;
slave->ports[i].link_detection_jiffies = 0;
#endif
}
slave->base_fmmu_bit_operation = 0;
@ -277,11 +282,51 @@ void ec_slave_clear_sync_managers(ec_slave_t *slave /**< EtherCAT slave. */)
/*****************************************************************************/
/**
* Sets the data-link state of a slave.
*/
void ec_slave_set_dl_status(ec_slave_t *slave, /**< EtherCAT slave */
uint16_t new_state /**< content of registers 0x0110-0x0111. */
)
{
unsigned int i;
uint8_t state;
for (i = 0; i < EC_MAX_PORTS; i++) {
// link status
state = new_state & (1 << (4 + i)) ? 1 : 0;
if (slave->ports[i].link.link_up != state) {
EC_SLAVE_DBG(slave, 1, "Port %u link status changed to %s.\n",
i, state ? "up" : "down");
slave->ports[i].link.link_up = state;
}
// loop status
state = new_state & (1 << (8 + i * 2)) ? 1 : 0;
if (slave->ports[i].link.loop_closed != state) {
EC_SLAVE_DBG(slave, 1, "Port %u loop status changed to %s.\n",
i, state ? "closed" : "open");
slave->ports[i].link.loop_closed = state;
}
// signal detection
state = new_state & (1 << (9 + i * 2)) ? 1 : 0;
if (slave->ports[i].link.signal_detected != state) {
EC_SLAVE_DBG(slave, 1, "Port %u signal status changed to %s.\n",
i, state ? "yes" : "no");
slave->ports[i].link.signal_detected = state;
}
}
}
/*****************************************************************************/
/**
* Sets the application state of a slave.
*/
void ec_slave_set_state(ec_slave_t *slave, /**< EtherCAT slave */
void ec_slave_set_al_status(ec_slave_t *slave, /**< EtherCAT slave */
ec_slave_state_t new_state /**< new application state */
)
{

View File

@ -113,6 +113,24 @@
/*****************************************************************************/
#ifdef EC_LOOP_CONTROL
/** Slave port state.
*/
typedef enum {
EC_SLAVE_PORT_DOWN,
EC_SLAVE_PORT_WAIT,
EC_SLAVE_PORT_UP
} ec_slave_port_state_t;
/** Wait time in [ms] from detecting a link to opening a port.
*/
#define EC_PORT_WAIT_MS 2000
#endif
/*****************************************************************************/
/** Slave port.
*/
typedef struct {
@ -123,6 +141,10 @@ typedef struct {
measurement. */
uint32_t delay_to_next_dc; /**< Delay to next slave with DC support behind
this port [ns]. */
#ifdef EC_LOOP_CONTROL
ec_slave_port_state_t state; /**< Port state for loop control. */
unsigned long link_detection_jiffies; /**< Time of link detection. */
#endif
} ec_slave_port_t;
/*****************************************************************************/
@ -245,7 +267,8 @@ void ec_slave_clear(ec_slave_t *);
void ec_slave_clear_sync_managers(ec_slave_t *);
void ec_slave_request_state(ec_slave_t *, ec_slave_state_t);
void ec_slave_set_state(ec_slave_t *, ec_slave_state_t);
void ec_slave_set_dl_status(ec_slave_t *, uint16_t);
void ec_slave_set_al_status(ec_slave_t *, ec_slave_state_t);
// SII categories
int ec_slave_fetch_sii_strings(ec_slave_t *, const uint8_t *, size_t);