Variable-sized data fields, BK1120.
This commit is contained in:
parent
b01cc85944
commit
85bd5d131d
|
|
@ -57,14 +57,14 @@ spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
|||
|
||||
// data fields
|
||||
//void *r_ssi_input, *r_ssi_status, *r_4102[3];
|
||||
void *r_kbus_in;
|
||||
|
||||
// channels
|
||||
uint32_t k_pos;
|
||||
uint8_t k_stat;
|
||||
|
||||
ec_field_init_t domain1_fields[] = {
|
||||
{NULL, "3", "Beckhoff", "EL5001", "InputValue", 0},
|
||||
{NULL, "2", "Beckhoff", "EL4132", "OutputValue", 0},
|
||||
{&r_kbus_in, "0", "Beckhoff", "BK1120", "Inputs", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -133,6 +133,8 @@ void release_lock(void *data)
|
|||
|
||||
int __init init_mini_module(void)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
|
||||
printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
|
||||
|
||||
if ((master = ecrt_request_master(0)) == NULL) {
|
||||
|
|
@ -155,6 +157,15 @@ int __init init_mini_module(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
#if 1
|
||||
printk(KERN_INFO "Setting variable data field sizes...\n");
|
||||
if (!(slave = ecrt_master_get_slave(master, "0"))) {
|
||||
printk(KERN_ERR "Failed to get slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_slave_field_size(slave, "Inputs", 0, 1);
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "Activating master...\n");
|
||||
if (ecrt_master_activate(master)) {
|
||||
printk(KERN_ERR "Failed to activate master!\n");
|
||||
|
|
@ -191,14 +202,6 @@ int __init init_mini_module(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printk(KERN_INFO "Writing alias...\n");
|
||||
if (ecrt_slave_sdo_write_exp16(slave, 0xBEEF)) {
|
||||
printk(KERN_ERR "Failed to write alias!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASYNC
|
||||
// send once and wait...
|
||||
ecrt_master_prepare_async_io(master);
|
||||
|
|
|
|||
|
|
@ -160,7 +160,10 @@ int ecrt_slave_sdo_write_exp32(ec_slave_t *slave, uint16_t sdo_index,
|
|||
int ecrt_slave_sdo_read(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint8_t *data, size_t *size);
|
||||
|
||||
int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias);
|
||||
int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias); // deprecated!
|
||||
|
||||
int ecrt_slave_field_size(ec_slave_t *slave, const char *field_name,
|
||||
unsigned int field_index, size_t size);
|
||||
|
||||
/******************************************************************************
|
||||
* Bitwise read/write macros
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ int ec_domain_add_command(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
*/
|
||||
|
||||
int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
||||
uint32_t base_address /**< Logische Basisadresse */
|
||||
uint32_t base_address /**< logical base address */
|
||||
)
|
||||
{
|
||||
ec_field_reg_t *field_reg;
|
||||
|
|
@ -234,12 +234,12 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
unsigned int i, j, cmd_count;
|
||||
uint32_t field_off, field_off_cmd;
|
||||
uint32_t cmd_offset;
|
||||
size_t cmd_data_size;
|
||||
size_t cmd_data_size, sync_size;
|
||||
ec_command_t *command;
|
||||
|
||||
domain->base_address = base_address;
|
||||
|
||||
// Größe der Prozessdaten berechnen und Kommandos allozieren
|
||||
// calculate size of process data and allocate memory
|
||||
domain->data_size = 0;
|
||||
cmd_offset = base_address;
|
||||
cmd_data_size = 0;
|
||||
|
|
@ -249,20 +249,21 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
fmmu = &slave->fmmus[j];
|
||||
if (fmmu->domain == domain) {
|
||||
fmmu->logical_start_address = base_address + domain->data_size;
|
||||
domain->data_size += fmmu->sync->size;
|
||||
if (cmd_data_size + fmmu->sync->size > EC_MAX_DATA_SIZE) {
|
||||
sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
|
||||
domain->data_size += sync_size;
|
||||
if (cmd_data_size + sync_size > EC_MAX_DATA_SIZE) {
|
||||
if (ec_domain_add_command(domain, cmd_offset,
|
||||
cmd_data_size)) return -1;
|
||||
cmd_offset += cmd_data_size;
|
||||
cmd_data_size = 0;
|
||||
cmd_count++;
|
||||
}
|
||||
cmd_data_size += fmmu->sync->size;
|
||||
cmd_data_size += sync_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Letztes Kommando allozieren
|
||||
// allocate last command
|
||||
if (cmd_data_size) {
|
||||
if (ec_domain_add_command(domain, cmd_offset, cmd_data_size))
|
||||
return -1;
|
||||
|
|
@ -275,14 +276,14 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Alle Prozessdatenzeiger setzen
|
||||
// set all process data pointers
|
||||
list_for_each_entry(field_reg, &domain->field_regs, list) {
|
||||
for (i = 0; i < field_reg->slave->fmmu_count; i++) {
|
||||
fmmu = &field_reg->slave->fmmus[i];
|
||||
if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
|
||||
field_off = fmmu->logical_start_address +
|
||||
field_reg->field_offset;
|
||||
// Kommando suchen
|
||||
// search command
|
||||
list_for_each_entry(command, &domain->commands, list) {
|
||||
field_off_cmd = field_off - command->address.logical;
|
||||
if (field_off >= command->address.logical &&
|
||||
|
|
|
|||
|
|
@ -1128,7 +1128,7 @@ void ec_fsm_slave_sync(ec_fsm_t *fsm /**< finite state machine */)
|
|||
if (slave->type) {
|
||||
for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) {
|
||||
sync = slave->type->sync_managers[j];
|
||||
ec_sync_config(sync, command->data + EC_SYNC_SIZE * j);
|
||||
ec_sync_config(sync, slave, command->data + EC_SYNC_SIZE * j);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1247,7 +1247,8 @@ void ec_fsm_slave_fmmu(ec_fsm_t *fsm /**< finite state machine */)
|
|||
0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
for (j = 0; j < slave->fmmu_count; j++) {
|
||||
ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j);
|
||||
ec_fmmu_config(&slave->fmmus[j], slave,
|
||||
command->data + EC_FMMU_SIZE * j);
|
||||
}
|
||||
|
||||
ec_master_queue_command(master, command);
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ int ec_master_simple_io(ec_master_t *master, /**< EtherCAT master */
|
|||
{
|
||||
unsigned int response_tries_left;
|
||||
|
||||
response_tries_left = 10;
|
||||
response_tries_left = 10000;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
|
@ -748,11 +748,16 @@ void ec_master_freerun(void *data /**< master pointer */)
|
|||
*/
|
||||
|
||||
void ec_sync_config(const ec_sync_t *sync, /**< sync manager */
|
||||
const ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint8_t *data /**> configuration memory */
|
||||
)
|
||||
{
|
||||
size_t sync_size;
|
||||
|
||||
sync_size = ec_slave_calc_sync_size(slave, sync);
|
||||
|
||||
EC_WRITE_U16(data, sync->physical_start_address);
|
||||
EC_WRITE_U16(data + 2, sync->size);
|
||||
EC_WRITE_U16(data + 2, sync_size);
|
||||
EC_WRITE_U8 (data + 4, sync->control_byte);
|
||||
EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
|
||||
EC_WRITE_U16(data + 6, 0x0001); // enable
|
||||
|
|
@ -784,11 +789,16 @@ void ec_eeprom_sync_config(const ec_eeprom_sync_t *sync, /**< sync manager */
|
|||
*/
|
||||
|
||||
void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< FMMU */
|
||||
const ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint8_t *data /**> configuration memory */
|
||||
)
|
||||
{
|
||||
size_t sync_size;
|
||||
|
||||
sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
|
||||
|
||||
EC_WRITE_U32(data, fmmu->logical_start_address);
|
||||
EC_WRITE_U16(data + 4, fmmu->sync->size);
|
||||
EC_WRITE_U16(data + 4, sync_size); // size of fmmu
|
||||
EC_WRITE_U8 (data + 6, 0x00); // logical start bit
|
||||
EC_WRITE_U8 (data + 7, 0x07); // logical end bit
|
||||
EC_WRITE_U16(data + 8, fmmu->sync->physical_start_address);
|
||||
|
|
@ -1133,7 +1143,8 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
|||
if (ec_command_npwr(command, slave->station_address,
|
||||
0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE))
|
||||
return -1;
|
||||
ec_sync_config(sync, command->data);
|
||||
ec_sync_config(sync, slave, command->data);
|
||||
EC_INFO("configuring sync.\n");
|
||||
if (unlikely(ec_master_simple_io(master, command))) {
|
||||
EC_ERR("Setting sync manager %i failed on slave %i!\n",
|
||||
j, slave->ring_position);
|
||||
|
|
@ -1211,7 +1222,8 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
|||
if (ec_command_npwr(command, slave->station_address,
|
||||
0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE))
|
||||
return -1;
|
||||
ec_fmmu_config(fmmu, command->data);
|
||||
ec_fmmu_config(fmmu, slave, command->data);
|
||||
EC_INFO("configuring fmmu.\n");
|
||||
if (unlikely(ec_master_simple_io(master, command))) {
|
||||
EC_ERR("Setting FMMU %i failed on slave %i!\n",
|
||||
j, slave->ring_position);
|
||||
|
|
|
|||
|
|
@ -151,9 +151,9 @@ int ec_master_bus_scan(ec_master_t *);
|
|||
|
||||
// misc.
|
||||
void ec_master_clear_slaves(ec_master_t *);
|
||||
void ec_sync_config(const ec_sync_t *, uint8_t *);
|
||||
void ec_sync_config(const ec_sync_t *, const ec_slave_t *, uint8_t *);
|
||||
void ec_eeprom_sync_config(const ec_eeprom_sync_t *, uint8_t *);
|
||||
void ec_fmmu_config(const ec_fmmu_t *, uint8_t *);
|
||||
void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
|
||||
void ec_master_output_stats(ec_master_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
111
master/slave.c
111
master/slave.c
|
|
@ -166,6 +166,7 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */
|
|||
INIT_LIST_HEAD(&slave->eeprom_syncs);
|
||||
INIT_LIST_HEAD(&slave->eeprom_pdos);
|
||||
INIT_LIST_HEAD(&slave->sdo_dictionary);
|
||||
INIT_LIST_HEAD(&slave->varsize_fields);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
slave->dl_link[i] = 0;
|
||||
|
|
@ -192,6 +193,7 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
|
|||
ec_eeprom_pdo_entry_t *entry, *next_ent;
|
||||
ec_sdo_t *sdo, *next_sdo;
|
||||
ec_sdo_entry_t *en, *next_en;
|
||||
ec_varsize_t *var, *next_var;
|
||||
|
||||
slave = container_of(kobj, ec_slave_t, kobj);
|
||||
|
||||
|
|
@ -240,6 +242,12 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
|
|||
kfree(sdo);
|
||||
}
|
||||
|
||||
// free information about variable sized data fields
|
||||
list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) {
|
||||
list_del(&var->list);
|
||||
kfree(var);
|
||||
}
|
||||
|
||||
if (slave->eeprom_data) kfree(slave->eeprom_data);
|
||||
if (slave->new_eeprom_data) kfree(slave->new_eeprom_data);
|
||||
|
||||
|
|
@ -1447,6 +1455,43 @@ ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
\return size of sync manager contents
|
||||
*/
|
||||
|
||||
size_t ec_slave_calc_sync_size(const ec_slave_t *slave, /**< EtherCAT slave */
|
||||
const ec_sync_t *sync /**< sync manager */
|
||||
)
|
||||
{
|
||||
unsigned int i, found;
|
||||
const ec_field_t *field;
|
||||
const ec_varsize_t *var;
|
||||
size_t size;
|
||||
|
||||
// if size is specified, return size
|
||||
if (sync->size) return sync->size;
|
||||
|
||||
// sync manager has variable size (size == 0).
|
||||
|
||||
size = 0;
|
||||
for (i = 0; (field = sync->fields[i]); i++) {
|
||||
found = 0;
|
||||
list_for_each_entry(var, &slave->varsize_fields, list) {
|
||||
if (var->field != field) continue;
|
||||
size += var->size;
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
EC_WARN("Variable data field \"%s\" of slave %i has no size"
|
||||
" information!\n", field->name, slave->ring_position);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Realtime interface
|
||||
*****************************************************************************/
|
||||
|
|
@ -1466,9 +1511,75 @@ int ecrt_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_field_size(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
const char *field_name, /**< data field name */
|
||||
unsigned int field_index, /**< data field index */
|
||||
size_t size /**< new data field size */
|
||||
)
|
||||
{
|
||||
unsigned int i, j, field_counter;
|
||||
const ec_sync_t *sync;
|
||||
const ec_field_t *field;
|
||||
ec_varsize_t *var;
|
||||
|
||||
if (!slave->type) {
|
||||
EC_ERR("Slave %i has no type information!\n", slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
|
||||
field_counter = 0;
|
||||
for (i = 0; (sync = slave->type->sync_managers[i]); i++) {
|
||||
for (j = 0; (field = sync->fields[j]); j++) {
|
||||
if (!strcmp(field->name, field_name)) {
|
||||
if (field_counter++ == field_index) {
|
||||
// is the size of this field variable?
|
||||
if (field->size) {
|
||||
EC_ERR("Field \"%s\"[%i] of slave %i has no variable"
|
||||
" size!\n", field->name, field_index,
|
||||
slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
// does a size specification already exist?
|
||||
list_for_each_entry(var, &slave->varsize_fields, list) {
|
||||
if (var->field == field) {
|
||||
EC_WARN("Resizing field \"%s\"[%i] of slave %i.\n",
|
||||
field->name, field_index,
|
||||
slave->ring_position);
|
||||
var->size = size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// create a new size specification...
|
||||
if (!(var = kmalloc(sizeof(ec_varsize_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for varsize_t!\n");
|
||||
return -1;
|
||||
}
|
||||
var->field = field;
|
||||
var->size = size;
|
||||
list_add_tail(&var->list, &slave->varsize_fields);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EC_ERR("Slave %i (\"%s %s\") has no field \"%s\"[%i]!\n",
|
||||
slave->ring_position, slave->type->vendor_name,
|
||||
slave->type->product_name, field_name, field_index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**< \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_slave_write_alias);
|
||||
EXPORT_SYMBOL(ecrt_slave_field_size);
|
||||
|
||||
/**< \endcond */
|
||||
|
||||
|
|
|
|||
|
|
@ -213,6 +213,20 @@ ec_sdo_entry_t;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Variable-sized field information.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
const ec_field_t *field; /**< data field */
|
||||
size_t size; /**< field size */
|
||||
}
|
||||
ec_varsize_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
EtherCAT slave.
|
||||
*/
|
||||
|
|
@ -282,6 +296,9 @@ struct ec_slave
|
|||
ec_slave_state_t current_state; /**< current slave state */
|
||||
unsigned int state_error; /**< a state error has happened */
|
||||
unsigned int online; /**< non-zero, if the slave responds. */
|
||||
|
||||
struct list_head varsize_fields; /**< size information for variable-sized
|
||||
data fields. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -310,6 +327,7 @@ int ec_slave_fetch_pdo(ec_slave_t *, const uint8_t *, size_t, ec_pdo_type_t);
|
|||
int ec_slave_locate_string(ec_slave_t *, unsigned int, char **);
|
||||
|
||||
// misc.
|
||||
size_t ec_slave_calc_sync_size(const ec_slave_t *, const ec_sync_t *);
|
||||
void ec_slave_print(const ec_slave_t *, unsigned int);
|
||||
int ec_slave_check_crc(ec_slave_t *);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,9 +67,24 @@ const ec_slave_type_t Beckhoff_EK1110 = {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t bk1120_in = {"Inputs", 0}; // variable size
|
||||
|
||||
const ec_sync_t bk1120_sm0 = {0x1C00, 264, 0x26, {NULL}};
|
||||
const ec_sync_t bk1120_sm1 = {0x1E00, 264, 0x22, {NULL}};
|
||||
|
||||
const ec_sync_t bk1120_sm2 = { // outputs
|
||||
0x1000, 0, 0x24, // variable size
|
||||
{NULL}
|
||||
};
|
||||
|
||||
const ec_sync_t bk1120_sm3 = { // inputs
|
||||
0x1600, 0, 0x00, // variable size
|
||||
{&bk1120_in, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_BK1120 = {
|
||||
"Beckhoff", "BK1120", "KBUS Coupler", EC_TYPE_NORMAL,
|
||||
{NULL} // no sync managers
|
||||
{&bk1120_sm0, &bk1120_sm1, &bk1120_sm2, &bk1120_sm3, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -186,8 +201,7 @@ const ec_sync_t el5101_sm3 = {
|
|||
{&el5101_st, &el5101_ip, &el5101_la, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL5101 =
|
||||
{
|
||||
const ec_slave_type_t Beckhoff_EL5101 = {
|
||||
"Beckhoff", "EL5101", "Incremental Encoder Interface", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el5101_sm2, &el5101_sm3, NULL}
|
||||
};
|
||||
|
|
@ -233,7 +247,7 @@ ec_slave_ident_t slave_idents[] = {
|
|||
{0x00000002, 0x03F63052, &Beckhoff_EL1014},
|
||||
{0x00000002, 0x044C2C52, &Beckhoff_EK1100},
|
||||
{0x00000002, 0x04562C52, &Beckhoff_EK1110},
|
||||
//{0x00000002, 0x04602C22, &Beckhoff_BK1120},
|
||||
{0x00000002, 0x04602C22, &Beckhoff_BK1120},
|
||||
{0x00000002, 0x07D43052, &Beckhoff_EL2004},
|
||||
{0x00000002, 0x07F03052, &Beckhoff_EL2032},
|
||||
{0x00000002, 0x0C1E3052, &Beckhoff_EL3102},
|
||||
|
|
|
|||
Loading…
Reference in New Issue