EtherCAT使用與解析-主站狀態機(idle->preop)

當加載完畢ec_master主站模塊和一個網絡驅動模塊後(如ec_generic),整個系統就創建一個線程用於指向空閒階段函數(./master/master.c/ec_master_idle_thread()),在該函數中有一個過程就是執行主站狀態機,也就是ec_fsm_master_exec()函數,具體實現模式就與主站中的ec_fsm_master_t類型結構有關,該類型的數據如下:

struct ec_fsm_master 
{
    ec_master_t *master; /**< master the FSM runs on 狀態機的主站 */
    ec_datagram_t *datagram; /**< datagram used in the state machine 狀態機用到的數據 */

	/* 數據報超時重發次數,一般設置爲EC_FSM_RETRIES(3次) */
    unsigned int retries; /**< retries on datagram timeout. */

	/* 主站狀態機執行函數,通過指定在不同狀態下該指針指向不同函數實現,從而實現不同狀態下的不同執行函數:空閒階段: 先指向ec_fsm_master_state_start()函數實現對狀態機的數據幀進行初始化,標誌主機進入空閒階段;然後再指向ec_fsm_master_state_broadcast()廣播函數。*/
    void (*state)(ec_fsm_master_t *); /**< master state function */
    ec_device_index_t dev_idx; /**< Current device index (for scanning etc.). */

	/* idle表示主站狀態機處於空閒階段,該量在本文件的c文件中ec_fsm_master_reset()初始化過程中初始化爲0在加載完畢ec_generic網絡驅動模塊之後,網絡設備驅動模塊創建一個內核線程執行了主站的空閒階段函數;在空閒階段函數中調用了ec_fsm_master_state_start()函數,該函數中設置了該量爲1,標誌進入空閒階段;ec_fsm_master_state_broadcast函數中,當狀態機進行重新掃描的時候,會將該idle置0,對從站配置完成後又會將該位賦值爲1 */
    int idle; /**< state machine is in idle phase */

	/* 當從站個數即拓撲結構被檢測到發生變化的時候,會將該rescan_required量置1,在開始主站狀態機開始進行就重新掃描的時候,會將該變量賦值爲當前的jiffies */
	unsigned long scan_jiffies; /**< beginning of slave scanning */

	/* 用於存儲上一週期的網絡設備連接狀態,從而可以和本週期網絡連接狀態進行組合判斷網絡連接的斷開時刻和接上的哪一刻 */
    uint8_t link_state[EC_MAX_NUM_DEVICES]; /**< Last link state for every device. */

	/* 每個網絡設備接收到從站響應個數,該數值在空閒階段是通過發送EC_DATAGRAM_BRD子報文,然後接收到的子報文獲取其WKC得到 */
    unsigned int slaves_responding[EC_MAX_NUM_DEVICES]; /**< Number of responding slaves for every device. */

	/* 當從站個數即拓撲結構被檢測到發生變化的時候,會將該rescan_required量置1,在開始主站狀態機開始進行就重新掃描的時候,會將該位置於0 */
	unsigned int rescan_required; /**< A bus rescan is required. */

	/* 每個設備響應從站的AL狀態(AL狀態寄存器) */
    ec_slave_state_t slave_states[EC_MAX_NUM_DEVICES]; /**< AL states of responding slaves for every device. */
	
    ec_slave_t *slave; /**< current slave */
    ec_sii_write_request_t *sii_request; /**< SII write request */
    off_t sii_index; /**< index to SII write request data */
    ec_sdo_request_t *sdo_request; /**< SDO request to process. */

	/* 各個不同的狀態機,每個狀態機都有對應的不同的源碼文件,如fsm_coe對應源碼實現爲/master/fsm_coe.h和/master/fsm_coe.c文件中 */
    ec_fsm_coe_t fsm_coe; /**< CoE state machine */
    ec_fsm_soe_t fsm_soe; /**< SoE state machine */
    ec_fsm_pdo_t fsm_pdo; /**< PDO configuration state machine. */
    ec_fsm_change_t fsm_change; /**< State change state machine */
    ec_fsm_slave_config_t fsm_slave_config; /**< slave state machine */

	/* 從站掃描狀態機,主站狀態機中的子狀態機 */
    ec_fsm_slave_scan_t fsm_slave_scan; /**< slave state machine */
    ec_fsm_sii_t fsm_sii; /**< SII state machine */
};

查看完畢該結構體可以看到主站狀態機中還存在一些子狀態機,如fsm_coe,fsm_soe,fsm_pdo,fsm_change,fsm_slave_config,基本的模式就是主站狀態機在需要執行子狀態機的時候,會一直等待子狀態機完成相應工作,然後再執行之後的程序轉入下一狀態。

那麼繼續看主站狀態機,主站狀態機的狀態函數會在初始化的時候初始化到./master/fsm_master.c/ec_fsm_master_state_start()函數,該函數中會對狀態機子報文進行填充,進行本週期的子報文數據發送,在此使用了BRD類型子報文(關於BRD子報文的作用可以查看這部分內容https://welsey.blog.csdn.net/article/details/105288222)進行數據發送,通過BRD類型子報文獲取從站個數,然後進入下一個狀態函數,也就是./master/fsm_master.c/ec_fsm_master_state_broadcast()中進行解析。由於使用的是BRD,對應的返回的子報文的WKC(WKC計算公式參考https://welsey.blog.csdn.net/article/details/105289253)也就是主站連接的從站的個數,這樣通過判斷與之前存儲的從站個數時候一致就可以判斷主站連接的從站有無變化,如果判斷髮生變化,那麼就需要進行主站對從站的重新掃描過程。

1.首先調用ec_master_clear_slaves()函數清除主站連接的從站鏈表,而後以剛掃描完畢得到的從站個數進行從站空間申請,並將主站的從站鏈表指向該位置。之後做的工作就是爲新申請的從站鏈表空間進行內容初始化,以及對從站寄存器的一些初始化。

2.從站的配置地址存儲在0x0010~0x0011,先進行對從站配置地址的清除(就是直接使用BWR報文直接寫入0x0000到該寄存器);之後的配置地址寫入在之後的從站掃描子狀態機中進行。然後就是寫入0x0900寄存器,寫入該寄存器會鎖存寫入時候的本地時間,該時間用來使用在DC過程。

3.執行從站掃描狀態機,該狀態機是主站狀態機中的子狀態機,主站會在ec_fsm_master_state_scan_slave()函數中等待該子狀態機執行完畢,至於執行是否完畢的標準就是子狀態機有無正常結束或者異常結束(通過兩個無內容的狀態函數實現)。

4.從站掃描子狀態機:該狀態機的類爲./master/fsm_slave_scan.h/ec_fsm_slave_scan,具體內容如下:

struct ec_fsm_slave_scan
{
    ec_slave_t *slave; /**< Slave the FSM runs on. */

    ec_datagram_t *datagram; /**< Datagram used in the state machine. */
    ec_fsm_slave_config_t *fsm_slave_config; /**< Slave configuration state machine to use. */
    ec_fsm_pdo_t *fsm_pdo; /**< PDO configuration state machine to use. */
    unsigned int retries; /**< Retries on datagram timeout. */

    void (*state)(ec_fsm_slave_scan_t *); /**< State function. */

    uint16_t sii_offset; /**< SII offset in words. */
    ec_fsm_sii_t fsm_sii; /**< SII state machine. */
};

執行到該子狀態機首先就是對從站的配置地址(0x0010~0x0011)的設置,由於最開始是從站變化導致的主站重新掃描,因此從站的配置地址是需要重新設置的,該設置地址是使用EC_DATAGRAM_APWR子報文進行設置的,自增式物理寫入的方式,每個從站都會參與轉發他,且每個從站對該子報文處理完畢後都會在APD位置+1,當那個從站檢測到APD爲0的時候,就會正式處理該子報文。因此該子報文類型適合於從站配置地址無效的情況下進行。

5.寫入從站的配置地址後就可以使用配置尋址方式進行指定從站的尋址了。也就是EC_DATAGRAM_FPRD類型子報文。首先獲取以下當前的從站狀態(0x0130~0x0131)檢測從站有無已知異常。如果沒有就可以繼續之後的獲取從站基礎信息。

6.ec_fsm_slave_scan_state_base()函數用於獲取從站基礎信息,主要包括FMMU個數、sync個數,FMMU是否支持位操作,從在哪是否支持DC,從站DC時間範圍等信息。如果從站支持DC系統,那麼就先進行DC的一些設置(關於EtherCAT的DC系統瞭解的還不是太透徹,之後正確瞭解後單獨寫一章)。

7.獲取DL狀態:DL也就Data link,表示數據鏈路狀態。他在0x0110~0x0111寄存器中存放。分別針對從站4個端口有無連接,有無迴路閉合和信號是否有檢測到進行信息獲取。

8.獲取SII信息,SII信息存放在EEPROM中,且第一個SII信息存放在EEPROM的0x40位置,然後利用SII信息獲取子狀態機對SII信息進行獲取(關於SII信息獲取子狀態機需要單獨列一章),大體來說就是根據SII每個項的存儲格式可以獲取到最終存儲SII信息佔據的空間大小,而後根據該空間大小將所有的SII信息獲取複製到內存中,之後再進行SII信息的提取解析(./master/fsm_slave_scan.c/ec_fsm_slave_scan_state_sii_data())。

9.提取完畢SII信息後,如果支持從站COE協議,那麼就繼續執行./master/fsm_slave_scan.c/ec_fsm_slave_scan_enter_preop()狀態函數,該狀態函數中啓用了從站配置子狀態機,該狀態機器會進行從站狀態轉換過程中一系列配置設置以及設置從站狀態向目標設置狀態變更(關於從站配置子狀態機需要單獨列一章)。

10.大體上一個從站的由init狀態轉變向preop狀態的流程如上,之後就是依次將主站連接的每個從站都執行一次上述流程。之後不斷做從站的重新掃描。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章