在进行过程数据通信之前,EtherCAT主站需要配置从站的同步管理器,通常为SM2和SM3,本文介绍IGH Etherlab配置从站SM2和SM3的过程。
当应用程序调用ecrt_master_activate(master)激活master以后,Etherlab状态机就会执行Fsm_slave_config.c中的
ec_fsm_slave_config_enter_pdo_sync()函数,完成SM2/SM3各寄存器的配置。
/** Check for PDO sync managers to be configured.
*/
void ec_fsm_slave_config_enter_pdo_sync(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
......
// configure sync managers for process data
ec_datagram_fpwr(datagram, slave->station_address,
0x0800 + EC_SYNC_PAGE_SIZE * offset, //准备报文
EC_SYNC_PAGE_SIZE * num_pdo_syncs);
ec_datagram_zero(datagram);
for (i = 0; i < num_pdo_syncs; i++) {
const ec_sync_config_t *sync_config;
uint8_t pdo_xfer = 0;
sync_index = i + offset;
sync = &slave->sii.syncs[sync_index];
if (slave->config) {
const ec_slave_config_t *sc = slave->config;
sync_config = &sc->sync_configs[sync_index];
size = ec_pdo_list_total_size(&sync_config->pdos); //计算已映射的PDO对象的总长度
......
} else {
sync_config = NULL;
size = sync->default_length;
}
ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer, //将SM寄存器写入报文对应位置
datagram->data + EC_SYNC_PAGE_SIZE * i);
}
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_slave_config_state_pdo_sync;
}
在ec_sync_page()中将SM寄存器的值填入报文对应位置:
void ec_sync_page(
const ec_sync_t *sync, /**< Sync manager. */
uint8_t sync_index, /**< Index of the sync manager. */
uint16_t data_size, /**< Data size. */
const ec_sync_config_t *sync_config, /**< Configuration. */
uint8_t pdo_xfer, /**< Non-zero, if PDOs will be transferred via this
sync manager. */
uint8_t *data /**> Configuration memory. */
)
{
......
EC_WRITE_U16(data, sync->physical_start_address);
EC_WRITE_U16(data + 2, data_size);
EC_WRITE_U8 (data + 4, control);
EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
EC_WRITE_U16(data + 6, enable);
}
SM寄存器的物理起始地址和控制字,来源于从站的EEPROM,Etherlab在扫描从站时获取对应的值。
//Fsm_slave_scan.c
ec_fsm_slave_scan_state_sii_data()
{
......
case 0x0029:
if (ec_slave_fetch_sii_syncs(slave, (uint8_t *) cat_word,cat_size * 2))
goto end;
break;
......
}
//slave.c
int ec_slave_fetch_sii_syncs(
ec_slave_t *slave, /**< EtherCAT slave. */
const uint8_t *data, /**< Category data. */
size_t data_size /**< Number of bytes. */
)
{
......
{
// initialize new sync managers
for (i = 0; i < count; i++, data += 8) {
index = i + slave->sii.sync_count;
sync = &syncs[index];
ec_sync_init(sync, slave);
sync->physical_start_address = EC_READ_U16(data); //物理起始地址
sync->default_length = EC_READ_U16(data + 2); //默认长度,命令行ethercat pdos打印的defaultsize
sync->control_register = EC_READ_U8(data + 4);//控制字
sync->enable = EC_READ_U8(data + 6);//使能
}
if (slave->sii.syncs)
kfree(slave->sii.syncs);
slave->sii.syncs = syncs;
slave->sii.sync_count = total_count;
}
return 0;
}
SM2寄存器的数据长度等于主站发送到从站的过程数据的长度,SM3寄存器的长度等于从站发送到主站的过程数据的长度。
SM数据长度为已映射的PDO对象的总长度,在ec_pdo_list_total_size()中计算。
uint16_t ec_pdo_list_total_size(
const ec_pdo_list_t *pl /**< PDO list. */
)
{
unsigned int bit_size;
const ec_pdo_t *pdo;
const ec_pdo_entry_t *pdo_entry;
uint16_t byte_size;
bit_size = 0;
list_for_each_entry(pdo, &pl->list, list) {
list_for_each_entry(pdo_entry, &pdo->entries, list) {
bit_size += pdo_entry->bit_length;
}
}
if (bit_size % 8) // round up to full bytes
byte_size = bit_size / 8 + 1;
else
byte_size = bit_size / 8;
return byte_size;
}