1. 程式人生 > >Etherlab原始碼解析----FMMU配置

Etherlab原始碼解析----FMMU配置

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關聯起來
}

4、配置例項

這裡寫圖片描述