ZHCAAA2A April 2019 – May 2021 AM5706 , AM5708 , AM5716 , AM5718 , AM5726 , AM5728 , AM5729 , AM5746 , AM5748 , AM5749 , TIOL111 , TIOL1113 , TIOL1115 , TPS2660
為了將 IO-Link 集成到 Linux,此處選擇了第三個方案,因為它不會增加 Arm Cortex-A15 的 CPU 負載,并且計時不會因 Linux 上的 CPU 負載而發生干擾或改變。隨后,該項目本身分為兩個子項目,一個在 A15 內核上基于 Linux 運行,另一個作為 RTOS 項目在 Arm Cortex-M4 內核之一上運行。這兩個子項目共享通用的命令定義,并通過處理器間通信 (IPC) 進行通信。
在 Linux 一端,編譯到內核中的 Remoteproc 框架負責加載 Arm Cortex M4。必須將主內存配置為具有分割區,以使 Linux 不會接觸到 Arm Cortex-M4 使用的內存,否則它們會相互干擾。此配置在 Linux dts 文件 am57xx-beagle-x15-common.dtsi 中完成,ipu2_cma_pool 部分針對第二個 IPU(這是 Arm Cortex-M4 子系統之一)進行此配置。
ipu2_cma_pool: ipu2_cma@95800000 {
compatible = "shared-dma-pool";
reg = <0x0 0x95800000 0x0 0x3800000>;
reusable;
status = "okay";
};
必須在 Arm Cortex-M4 項目的資源配置中完成相同的配置。此資源表會編譯到項目中,并由 Remoteproc 驅動程序在啟動時正確配置 MMU,從而向 IPU 提供所有必要的資源。
Arm Cortex-M4 在邏輯地址 0x0000 0000 處啟動。該邏輯地址由 MMU 映射到分割區域中的相應物理 DDR 內存地址 (0x9580 0000)。Linux 驅動程序將二進制文件加載到該 DDR 位置,并且 Arm Cortex-M4 會因復位被釋放。
Arm Cortex-M4 啟動后,可在兩個內核之間建立通信通道。這基本上就是一個客戶端/服務器模型。Arm Cortex-M4 內核提供了一個服務器,可打開消息隊列。在 Arm Cortex-A15 上的 Linux 中,可打開此消息隊列,并傳遞數據。
Arm Cortex-M4 上的 RTOS 有兩項任務,一項是處理 IO-Link 通信,另一項是等待從 Linux 接收到通信隊列中的數據。一旦接收到數據,就可對數據進行處理并傳遞給 IO-Link 任務。
僅有少量數據被交換,因此所有內容均以 32 位字進行編碼。Arm Cortex-M4 上的一個名為 void Server_handle_cmd(unsigned int *cmd) 的函數會處理從主機處理器接收到的命令(存儲在 cmd 中)并將響應寫入相同的位置。此后會發送回去。如果是發出讀取 ISDU 請求,可能看起來像這樣:
void Server_handle_cmd(unsigned int *cmd) {
switch ((*cmd) & App_CMD_MASK) {
...
case App_CMD_GET_ISDU_START:
MOD_Read_req((*cmd & 0x00f00000)>>20, (*cmd & 0x0000ffff), (*cmd & 0x000f0000)>>16);
isdu_read_state = 1;
break;
...
}
}
上面的代碼片段會分析收到的命令,并將數據傳遞到堆棧。32 位寬命令的高 8 位對應用命令進行編碼,此處的命令為 App_CMD_GET_ISDU_START,用于請求讀取 ISDU。命令的其余位包括端口、索引以及子索引。通過調用 MOD_Read_req,可提取這些參數并將它們傳遞給 IO-Link 堆棧的讀取函數。除了設置內部標志 isdu_read_state 之外,還可由其他應用程序命令將其用于傳輸讀取請求的狀態。此處的狀態包括該請求是否已由堆棧處理以及數據是否已傳遞到 Linux 主機。
Linux 主機必須將所有命令編碼為 32 位字并將它們傳遞到通信隊列中。一個開始在指定端口上讀取 ISDU 的函數如下所示:
void isdu_read_start(int port, int index, int subindex){
App_Msg *msg;
/* allocate message */
msg = (App_Msg *)MessageQ_alloc(Module.heapId, Module.msgSize);
/* fill in message payload */
msg->cmd = App_CMD_GET_ISDU_START | port<<20 | subindex<<16 | index;
/* send message */
MessageQ_put(Module.slaveQue, (MessageQ_Msg) msg);
/* wait for return message */
MessageQ_get(Module.hostQue, (MessageQ_Msg *) &msg, MessageQ_FOREVER);
/* free memory */
MessageQ_free((MessageQ_Msg)msg);
}
MessageQ_get 返回后,來自 Arm Cortex-M4 的響應將存儲在 msg 中,并接受進一步處理。例如,在此處執行讀取命令后,可以存儲已回讀的值。
除了用于啟動讀取請求的函數之外,還實現了一個用于檢查狀態并回讀緩沖區的函數。
啟動讀取請求后,主機處理器必須檢查讀取命令是否已完成,然后從讀取緩沖區中獲取數據。如下所示的例子中實現了一個完整的讀取函數,用于讀取字符串數據,例如產品名稱。
void isdu_read_char(int port, int index, int subindex, char *buf, int *len){
isdu_read_start(port, index, subindex);
while(isdu_read_state() != READ_COMPLETED);
isdu_read_data(buf, len);
buf[*len] = '\0';
}
在此抽象級上,可在用戶應用中使用諸如 get_port_state、isdu_read_char 和 isdu_write_char 之類的簡單函數來從 Linux 用戶空間控制 IO-Link。
此處的實現示例在機器視覺應用中使用這些函數。用戶應用會利用 HALCON 庫,將 GigE Vision 攝像機連接到 Sitara AM5728 處理器的以太網端口之一。同樣的應用控制著一個塔燈以發出信號,指示是否正確識別了某個物體,并將結果通過以太網發送到服務器進行監控。