女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

CANopenNode的移植接口詳解

CHANBAEK ? 來源:安德魯的設計筆記本 ? 作者:安德魯蘇 ? 2023-06-23 15:49 ? 次閱讀

引言

CANopen是實現CAN設備組網的典型協議棧和規范,對應于軟件系統中,有一些開源的軟件組件,實現了CANopen協議棧,例如CANopenNode和CAN Festival。CANFestival和CANopenNode都是用于在嵌入式系統上實現CANopen協議通信的開源軟件協議棧,但需要注意的是,它們使用了不同的開源協議:

  • CANFestival使用LGPLv2開源協議,這意味著CANFestival的源代碼是免費提供的,任何人都可以使用、修改和分發,但衍生作品使用相同的GPL許可證。如果一個公司在產品中使用CANFestival組件,他們也必須按照同樣的LGPLv2開源協議提供其產品的源代碼。
  • CANopenNode使用 Apache v2.0開源協議。這是一個自由度比LGPLv2更為開發的一個開源協議,允許在使用軟件方面有更大的靈活性。任何人都可以使用、修改和發布CANopenNode,甚至用于商業目的,而不需要發布其衍生作品的源代碼。

表x CANopenNode vs CAN Festival

image.png

本文將以CANopenNode為例,講解CANopen協議的一種實現,并在具體的微控制器平臺上適配運行。

CANopenNode項目簡介

CANopenNode是一個免費的開源CANopen協議棧的實現。CANopen協議棧是一個在嵌入式控制器上的基于CAN總線高層應用協議,遵循國際標準CiA 301(EN 50325-4)。CANopenNode實現了CANopen協議棧的絕大多數功能:

  • 網絡管理協議中,NMT從站狀態機(啟動、停止、復位設備)和簡單的NMT主站。
  • 錯誤控制協議中,心跳消息的生產者(發送方)和消費者(接收方)
  • PDO連接和動態映射到過程變量的快速交互
  • SDO快速傳輸、常規(分段)傳輸和塊傳輸
  • SDO主站
  • 緊急消息
  • 同步協議中的生產者(發送方)和消費者(接收方)
  • 授時協議中的生產者(發送方)和消費者(接收方)
  • 非易失性存儲
  • LSS服務的主站和從機,LSS快速掃描

CANopenNode的源碼在開源軟件網站GitHub上發布,https://github.com/CANopenNode/CANopenNode,開發者可以直接下載完整的CANopenNode源碼。此處需要注意,v1.3之后,持續開發的v2.0/4.0,在實現內容上有較大變化。本文選用已經標注“Verified”的v1.3版本,這也是目前最新的相對穩定的發布版本。

圖片

figure-conode-github-pack

圖x 在GitHub上下載CANopenNode源碼包CANopenNode組件是以ANSI C語言編寫,可以作為一個標準的應用組件,方便地移植到不同的微控制器平臺,或者是實時操作系統上。通過使用CANopenNode組件,可以在CANopen設備節點上創建一個對象字典(Object Dictionary),其中包含若干個變量(代表著配置信息),可以由本機直接通過C語言訪問,也可以由別的CANopen節點通過CAN網絡訪問,以此來實現CAN總線網絡系統中的信息交換,以及軟件系統對硬件系統的控制。

CANopenNode組件本身并不是一個完整的應用程序,它包含一組實現CANopen協議棧的源碼和基于本身的樣例工程。如果要運行CANopenNode組件,還需要在一個具體的硬件平臺上進行適配,例如文本中即將用到的集成FlexCAN外設模塊的MM32F0140微控制器。

CANopenNode的開源站點上還開放了更多CANopen的功能組件,例如可以運行在Linux主機系統作為master的CANopenSocket項目,在多微控制器平臺上實現演示用例和測試工具的CANopenDemo項目,可以編輯對象字典生成C源碼文件的CAnopenEditor項目等等。

CANopenNode實現的工作流,如圖x所示。

圖片

figure-conode-workflow

圖x CANopenNode的工作流程其中,CAN總線接收線程和定時器周期執行線程,可以在微控制器的中斷服務程序中實現,主線線程可以在main()函數的主循環中實現。至于SDO客戶端和LSS(一個配置CANopen節點ID和比特率的服務)客戶端,可以在應用層的用戶程序中根據需要調用。

CANopenNode的源碼文件組織結構,如圖x所示。

圖片

figure-conode-source-files

圖x CANopenNode源碼文件的組織結構CANopenNode項目的stack目錄下分別實現了CANopen協議中的對象(通信過程),并封裝在各自獨立的源文件中。特別地,在stack/drvTemplate目錄中,為開發者提供了一個向具體目標平臺移植CANopenNode的源碼模板,同時還提供了在多種不同微控制器平臺上移植CANopenNode的范例,例如stack/STM32stack/LPC1768stack/PIC32等。

CANopenNode的移植接口

CANopenNode的源碼目錄中,專門為在具體微控制器平臺上實現移植提供了源碼模板,位于stack/drvTemplate目錄中。本節簡要分析其中的代碼結構,為后續基于具體目標平臺實現移植奠定基礎。

stack/drvTemplate目錄下包含四個源文件:CO_driver.h, CO_driver_target.h, eeprom.c和eeprom.h。

CO_driver_target.h

CO_driver_target.h源文件包含了支持如下功能的數據類型定義、函數原型和宏定義:

  • 基本的數據類型
  • CANopen消息的接收和發送緩沖區
  • 同微控制器集成CAN外設模塊的接口
  • CAN外設的接收和發送中斷函數的聲明(將用于在移植過程中嵌入硬件中斷服務程序中)

這個源文件定義了的CANopen的底層驅動程序,還定義了一些專用于優化協議執行過程的數據結構,它不再使用的CAN消息隊列,而是直接將數據連接CANopen設備的對象(通信過程)上,盡量提高響應速度,并減少不必要的計算和內存開銷。

CO_CANmodule_t結構類型中,包含了一組接收消息對象(CO_CANrx_t類型)和一組發送消息對象(CO_CANtx_t類型),每個CANopen通信對象都有自己專屬的其中一個成員。例如,心跳消息生產者可以創建一個CANopen發送對象,它就需要在CO_CANtx_t數組中預留一個表項。同步模塊可能產生一個同步對象或是接收一個同步的對象,它就需要在CO_CANtx_t數組或者CO_CANrx_t數組中預留一個表項。

接收過程

在接收到CAN消息之前,CO_CANrx_t中的每個成員都必須被初始化,此時需要調用CO_CANrxBufferInit()函數,例如,在CO_HBconsumer中就使用了CO_CANrx_t中的多個成員(需要監控多個遠程節點),就需要多次調用CO_CANrxBufferInit()函數,對每個CO_CANrx_t進行初始化。CO_CANrxBufferInit()函數的兩個主要參數,一個是CAN ID,另一個是一個回調函數的指針,這兩個參數將被寫入到CO_CANrx_t數組中。其中的回調函數是根據具體功能模塊實現的,用以處理接收的幀消息,將必要的數據搬運到合適的內存中,然后觸發其他任務以繼續處理接收數據。回調函數的程序必須要短小精悍,僅做少量必要的計算和數據搬運工作,以避免耽誤后續接收幀的時機。

接收CAN幀的操作將在CAN外設模塊的接收中斷服務中進行。當在接收中斷服務程序中捕獲到CAN消息后,程序首先將它的CAN ID同CO_CANrx_t數組中的成員進行匹配,如果匹配到預先配置好的CO_CANrx_t,就會執行其中的回調函數。

回調函數有兩個傳入參數:

  • object - CO_CANrxBufferInit()函數注冊的一個指向傳輸對象的指針
  • msg - 一個指向CO_CANrxMsg_t類型CAN消息的指針

回調函數可以返回CO_ReturnError_t類型的狀態值:

  • CO_ERROR_NO
  • CO_ERROR_RX_OVERFLOW
  • CO_ERROR_RX_PDO_OVERFLOW
  • CO_ERROR_RX_MSG_LENGTH
  • CO_ERROR_RX_PDO_LENGTH。

發送過程

在發送CAN消息之前,CO_CANtx_t列表中的成員必須被CO_CANtxBufferInit()函數初始化。例如,心跳消息生產者就必須初始化它在CO_CANtx_t數組中的成員。CO_CANtxBufferInit()函數翻譯一個指向CO_CANtx_t類型結構體的指針,其中包含了一個緩沖區,可以存放即將要發送幀的數據。之后,可以通過調用CO_CANsend()函數啟動發送過程。如果恰巧微控制器硬件的發送緩沖區是可用的,就可以直接將發送消息從內存中搬運到CAN外設的硬件緩沖區中等待發送,否則,CO_CANsend()函數將設定_bufferFull_標志位為True,之后將通過發送中斷觸發的硬件發送緩沖區可用事件,觸發數據搬運過程并啟動發送。CO_CANtx_t中的數據在通過CAN外設發送出去之前,是不可改動的。這里CO_CANtx_t隊列中可能有多個成員的_bufferFull_標志位為True,此時,編號更小的CO_CANtx_t將被優先發送出去。

關鍵區域的函數

CANopenNode被設計基于多個線程運行,不同系統平臺對多線程的實現方式也不盡相同。在微控制器平臺,可以使用不同優先級的中斷服務程序實現多個線程。此時,需要將多個線程可能共同訪問的資源保護起來。一種簡單的實現,可以在中斷服務程序或者后臺的調度器使用這些共享資源時,禁用對方,或者使用信號量等同步機制。

部分函數可以在不同的線程被調用:

  • CO_driver.h中的CO_CANsend()函數
  • CO_Emergency.h中的CO_errorReport()函數和CO_errorReset()函數

通常只有兩個線程會訪問到對象字典變量:一個是主線程,另一個是定時器線程。CANopenNode在主線程中運行CANopenNode的初始化過程和SDO服務端程序。PDO的程序運行在周期更短的定時器線程中,并且處理PDO的過程不能被主線程打斷。主線程必須保護定時器線程同時在訪問的對象字典變量,應用層的程序也是如此。需要注意的是,并不是所有的對象字典變量可以被映射到PDO,所以這些不被PDO操作的變量是不需要被保護起來的。SDO服務端操作是會保護操作對象字典中的變量。

CAN接收線程對接收到的CAN消息幀進行簡單處理后,將它們寫入對應的對象中,交由別的線程在后續繼續處理。這個過程不需要保護任何關鍵區域。但有一個例外,當同步消息出現在CANopen的總線上時, 需要臨時禁用CANrx(),直到所有的PDO都處理完畢。

這里需要開發者在移植CANopenNode到具體的微控制器平臺上時,需要實現保護關鍵區的宏函數:

#define CO_LOCK_CAN_SEND()  /**< Lock critical section in CO_CANsend() */
#define CO_UNLOCK_CAN_SEND()/**< Unlock critical section in CO_CANsend() */

#define CO_LOCK_EMCY()      /**< Lock critical section in CO_errorReport() or CO_errorReset() */
#define CO_UNLOCK_EMCY()    /**< Unlock critical section in CO_errorReport() or CO_errorReset() */

#define CO_LOCK_OD()        /**< Lock critical section when accessing Object Dictionary */
#define CO_UNLOCK_OD()      /**< Unock critical section when accessing Object Dictionary */

內存同步函數

在接收CAN通信幀和處理消息的線程間同步消息緩沖區。當在中斷服務程序中運行接收函數,則不需要進行任何同步操作,因為一旦中斷發生,CPU的使用權會自動從其它處理消息幀的線程切換到中斷服務程序。否則,需要使用一些同步機制,確保先接收到完整的CAN消息幀之后再處理它們。例如,使用GCC編譯器時,可以使用GCC編譯器內置的內存邊界函數__sync_synchronize(),此時,只要將CANrxMemoryBarrier()函數映射到這個內存邊界函數即可。

#define CANrxMemoryBarrier() {__sync_synchronize();}

CO_driver_target.h文件中定義了一組內存同步相關的函數:

/** Memory barrier */
#define CANrxMemoryBarrier()
/** Check if new message has arrived */
#define IS_CANrxNew(rxNew) ((uintptr_t)rxNew)
/** Set new message flag */
#define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;}
/** Clear new message flag */
#define CLEAR_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)0L;}

CO數據類型

CO_driver_target.h文件的后續,還定了一些基本數據類型:

/**
 * @defgroup CO_dataTypes Data types
 * @{
 *
 * According to Misra C
 */
/* int8_t to uint64_t are defined in stdint.h */
typedef unsigned char           bool_t;     /**< bool_t */
typedef float                   float32_t;  /**< float32_t */
typedef long double             float64_t;  /**< float64_t */
typedef char                    char_t;     /**< char_t */
typedef unsigned char           oChar_t;    /**< oChar_t */
typedef unsigned char           domain_t;   /**< domain_t */
/** @} */

以及CANopenNode在操作CAN硬件驅動時涉及到的結構體類型的定義,包括:

  • CO_CANrxMsg_t - 接收CAN幀結構體
  • CO_CANrx_t - 接收消息對象
  • CO_CANtx_t - 發送消息對象
  • CO_CANmodule_t - CAN外設模塊對象

以及最后聲明了CO_CANinterrupt()函數,便于開發者在移植時嵌入中斷服務程序:

void CO_CANinterrupt(CO_CANmodule_t *CANmodule);

CO_driver.c

CO_driver.c文件是CANopenNode對接微控制器的底層接口,在CO_driver.c文件的函數中,添加操作目標微控制器平臺包含CAN外設模塊在內的電路系統的代碼,建立CANopenNode同具體微控制器平臺的綁定。CO_driver.c文件中實現了一些對CAN外設驅動進行抽象的函數,如表x所示。

表x CANopenNode抽象的CAN外設驅動函數清單

image.png

在具體的目標微控制器平臺上移植CANopenNode時,需要結合具體的硬件CAN外設模塊,補充這些函數中對硬件的操作。

eeprom.h & eeprom.c

eeprom.h和eeprom.c文件,綁定了讀寫EEPROM存儲器的驅動程序,可以在CANopen協議運行的過程中,將對象字典保存在EEPROM存儲器中。在基本的移植中,可以不實現將對象字典存儲在外部存儲器的功能。

/**
 * Eeprom object.
 */
typedef struct{
    uint8_t     *OD_EEPROMAddress;      /**< From CO_EE_init_1() */
    uint32_t     OD_EEPROMSize;         /**< From CO_EE_init_1() */
    uint8_t     *OD_ROMAddress;         /**< From CO_EE_init_1() */
    uint32_t     OD_ROMSize;            /**< From CO_EE_init_1() */
    uint32_t     OD_EEPROMCurrentIndex; /**< Internal variable controls the OD_EEPROM vrite */
    bool_t       OD_EEPROMWriteEnable;  /**< Writing to EEPROM is enabled */
}CO_EE_t;

/**
 * First part of eeprom initialization. Called after microcontroller reset.
 *
 * @param ee This object will be initialized.
 * @param OD_EEPROMAddress Address of OD_EEPROM structure from object dictionary.
 * @param OD_EEPROMSize Size of OD_EEPROM structure from object dictionary.
 * @param OD_ROMAddress Address of OD_ROM structure from object dictionary.
 * @param OD_ROMSize Size of OD_ROM structure from object dictionary.
 *
 * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_DATA_CORRUPT (Data in eeprom corrupt) or
 * CO_ERROR_CRC (CRC from MBR does not match the CRC of OD_ROM block in eeprom).
 */
CO_ReturnError_t CO_EE_init_1(
        CO_EE_t                *ee,
        uint8_t                *OD_EEPROMAddress,
        uint32_t                OD_EEPROMSize,
        uint8_t                *OD_ROMAddress,
        uint32_t                OD_ROMSize);

/**
 * Second part of eeprom initialization. Called after CANopen communication reset.
 *
 * @param ee          - This object.
 * @param eeStatus    - Return value from CO_EE_init_1().
 * @param SDO         - SDO object.
 * @param em          - Emergency object.
 */
void CO_EE_init_2(
        CO_EE_t                *ee,
        CO_ReturnError_t        eeStatus,
        CO_SDO_t               *SDO,
        CO_EM_t                *em);

/**
 * Process eeprom object.
 *
 * Function must be called cyclically. It strores variables from OD_EEPROM data
 * block into eeprom byte by byte (only if values are different).
 *
 * @param ee This object.
 */
void CO_EE_process(CO_EE_t *ee);

基于FlexCAN適配CANopenNode

(未完待續)

一個CANopenNode的應用樣例

(未完待續)

總結

(未完待續)

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5133

    文章

    19500

    瀏覽量

    314180
  • 接口
    +關注

    關注

    33

    文章

    8918

    瀏覽量

    153117
  • 移植
    +關注

    關注

    1

    文章

    394

    瀏覽量

    28559
  • 開源
    +關注

    關注

    3

    文章

    3569

    瀏覽量

    43388
  • CANopen
    +關注

    關注

    8

    文章

    335

    瀏覽量

    44429
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    基于MM32G5330的FlexCAN實現CANopenNode協議棧移植

    本文將介紹如何基于靈動MM32G5330的FlexCAN實現CANopenNode協議棧的移植,并使用靈動官方提供的開發板Mini-G5333進行驗證。
    發表于 04-12 09:15 ?2107次閱讀
    基于MM32G5330的FlexCAN實現<b class='flag-5'>CANopenNode</b>協議棧<b class='flag-5'>移植</b>

    串行通訊接口詳解

    本帖最后由 eehome 于 2013-1-5 09:52 編輯 串行通訊接口詳解
    發表于 08-08 11:20

    uCOS-II如何在STM32上的移植詳解

    下載用uCOS-II在STM32上的移植詳解.pdf (1.64 MB )
    發表于 05-26 02:13

    STM32程序的移植詳解步驟

    一,概括程序的移植包括以下幾步1.觀察待移植程序調用了哪些文件,將這些文件放入移植的工程當中2.在keil當中添加這些文件,并且添加.h文件的路徑3.處理頭文件及軟件版本匹配的問題二,詳解
    發表于 08-23 07:27

    RTAI分析及在s3c4510上的移植詳解

    RTAI分析及在s3c4510上的移植詳解
    發表于 03-28 09:52 ?24次下載

    uCOSII在LPC2210上的移植詳解

    uCOSII在LPC2210上的移植詳解:嵌入式實時操作系統在目標處理器平臺上的移植是嵌入式軟件開發的基礎和前提。論文實現了源碼公開的嵌入式實時操作系統μC/OS- II 在ARM7 微控制器LPC2
    發表于 12-31 15:11 ?144次下載

    嵌入式Linux內核移植詳解(頂嵌)

    嵌入式內核移植步驟詳解 含配置含義及內容等方面
    發表于 11-20 16:00 ?19次下載

    LCD接口類型詳解

    LCD接口類型詳解--大盛唐電子,專業代理啊ALLANCEMXICISOCOMEXARHKCATO天馬屏!
    發表于 06-06 14:48 ?0次下載

    PCI-Express接口術語詳解

    計算機接口中關于PCI-Express的詳解
    發表于 09-01 14:55 ?0次下載

    幾種串行通信接口標準詳解

    幾種串行通信接口標準詳解
    發表于 01-03 11:34 ?0次下載

    網絡接口跨平臺移植擴展控件設計

    網絡接口跨平臺移植擴展控件設計_魏惠茹
    發表于 01-07 21:39 ?0次下載

    《Linux設備驅動開發詳解》第23章、Linux設備驅動的移植

    《Linux設備驅動開發詳解》第23章、Linux設備驅動的移植
    發表于 10-27 10:58 ?9次下載
    《Linux設備驅動開發<b class='flag-5'>詳解</b>》第23章、Linux設備驅動的<b class='flag-5'>移植</b>

    Uboot移植步驟詳解

    Uboot移植步驟詳解
    發表于 10-30 08:46 ?21次下載
    Uboot<b class='flag-5'>移植</b>步驟<b class='flag-5'>詳解</b>

    uCOS_ARM移植要點詳解

    uCOS_ARM移植要點詳解
    發表于 10-31 11:25 ?11次下載
    uCOS_ARM<b class='flag-5'>移植</b>要點<b class='flag-5'>詳解</b>

    基于FlexCAN適配CANopenNode

    總結在微控制器平臺上移植CANopenNode,需要根據具體硬件條件,適配2個源文件。
    的頭像 發表于 06-23 15:51 ?1908次閱讀
    基于FlexCAN適配<b class='flag-5'>CANopenNode</b>