FMMU的全称是Fieldbus Memory Management Unit, 负责将从站本地物理存储地址映射到网段内逻辑地址。
本地物理存储地址可以是ESC的寄存器区域,最典型的应用是邮箱通信中,将SM1的状态位(0x80D.3)映射到逻辑地址,主站周期性地读这一位的状态来判断邮箱的状态。
本地物理存储地址也可以是SM所管理的过程数据所在的地址空间,本文将简述IGH Etherlab在何时,以及如何配置从站过程数据对应的FMMU。
1、 FMMU寄存器
每个FMMU通道使用16个字节的配置寄存器,从0x0600开始。
2、执行配置
当应用程序调用ecrt_master_activate(master)激活master以后,Etherlab状态机将配置从站的FMMU寄存器。
//Fsm_slave_config.c
void ec_fsm_slave_config_enter_fmmu(
ec_fsm_slave_config_t *fsm /**< slave state machine */
)
{
......
// configure FMMUs
ec_datagram_fpwr(datagram, slave->station_address,
0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
ec_datagram_zero(datagram);
for (i = 0; i < slave->config->used_fmmus; i++) {
fmmu = &slave->config->fmmu_configs[i];
if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) { //寻找对应的SM
slave->error_flag = 1;
fsm->state = ec_fsm_slave_config_state_error;
EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
" for FMMU!\n");
return;
}
ec_fmmu_config_page(fmmu, sync, //填充FMMU各寄存器
datagram->data + EC_FMMU_PAGE_SIZE * i);
}
fsm->retries = EC_FSM_RETRIES;
fsm->state = ec_fsm_slave_config_state_fmmu;
}
//Fmmu_config.c
void ec_fmmu_config_page(
const ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
const ec_sync_t *sync, /**< Sync manager. */
uint8_t *data /**> Configuration page memory. */
)
{
EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, Size %3u,"
" PhysAddr 0x%04X, SM%u, Dir %s\n",
fmmu->logical_start_address, fmmu->data_size,
sync->physical_start_address, fmmu->sync_index,
fmmu->dir == EC_DIR_INPUT ? "in" : "out");
EC_WRITE_U32(data, fmmu->logical_start_address);
EC_WRITE_U16(data + 4, fmmu->data_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, sync->physical_start_address);
EC_WRITE_U8 (data + 10, 0x00); // physical start bit
EC_WRITE_U8 (data + 11, fmmu->dir == EC_DIR_INPUT ? 0x01 : 0x02);
EC_WRITE_U16(data + 12, 0x0001); // enable
EC_WRITE_U16(data + 14, 0x0000); // reserved
}
3、逻辑地址和数据长度
在ec_fmmu_config_page()函数中,FMMU配置寄存器中最重要的两个值fmmu->logical_start_address和fmmu->data_size是如何确定的呢?
在应用程序注册PDO对象时,IGH Etherlab将分配相应的FMMU,并与domain关联起来。
int ecrt_slave_config_reg_pdo_entry()
{
......
//根据index和subindex查找PDO所在的SM通道
for (sync_index = 0; sync_index < EC_MAX_SYNC_MANAGERS; sync_index++) {
sync_config = &sc->sync_configs[sync_index];
bit_offset = 0;
list_for_each_entry(pdo, &sync_config->pdos.list, list) {
list_for_each_entry(entry, &pdo->entries, list) {
if (entry->index != index || entry->subindex != subindex) {
bit_offset += entry->bit_length;
} else {
bit_pos = bit_offset % 8;
if (bit_position) {
*bit_position = bit_pos;
} else if (bit_pos) {
EC_CONFIG_ERR(sc, "PDO entry 0x%04X:%02X does"
" not byte-align.\n", index, subindex);
return -EFAULT;
}
sync_offset = ec_slave_config_prepare_fmmu( //分配FMMU
sc, domain, sync_index, sync_config->dir);
if (sync_offset < 0)
return sync_offset;
return sync_offset + bit_offset / 8;
}
}
}
}
EC_CONFIG_ERR(sc, "PDO entry 0x%04X:%02X is not mapped.\n",
index, subindex);
return -ENOENT;
}
而ec_slave_config_prepare_fmmu()将调用ec_fmmu_config_init(),为logical_start_address和data_size赋值:
//Fmmu_config.c
void ec_fmmu_config_init(
ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
ec_slave_config_t *sc, /**< EtherCAT slave configuration. */
ec_domain_t *domain, /**< EtherCAT domain. */
uint8_t sync_index, /**< Sync manager index to use. */
ec_direction_t dir /**< PDO direction. */
)
{
INIT_LIST_HEAD(&fmmu->list);
fmmu->sc = sc;
fmmu->sync_index = sync_index;
fmmu->dir = dir;
fmmu->logical_start_address = domain->data_size;//domain中的偏移地址
fmmu->data_size = ec_pdo_list_total_size( //SM中已映射的PDO总长度
&sc->sync_configs[sync_index].pdos);
ec_domain_add_fmmu_config(domain, fmmu); //将fmmu与domain关联起来
}