PIL 基本介紹
在航空和汽車等安全攸關(guān)的行業(yè),如果采用基于模型的設(shè)計方法論(MBD),需要額外引入背靠背測試的概念,具體來說,使用模型開發(fā)的過程中,背靠背測試包含 SIL(Software-in-the-Loop)和 PIL(Processor-in-the-Loop)兩種。其中 PIL 測試是驗證模型和目標(biāo)碼(Object code,即編譯鏈接之后的產(chǎn)物)等效性的有效手段,也是諸如 DO178C,ISO26262 等功能安全標(biāo)準(zhǔn)推薦的一種測試方法。
為了更好的理解本文,首先來看看什么是硬件支持包(注:PIL 功能通常是一個完整硬件支持包的其中一個功能),在 MBD 語境下,一個相對完整的硬件支持包通常包含以下組件:
Toolchain - 實現(xiàn)將 Simulink 模型或 M 代碼一鍵自動化編譯、鏈接和下載的核心手段
Device Driver - MCU/MPU/FPGA 等的外設(shè)或者片外設(shè)備,比如 ADC,PWM,GPIO,SCI 等
Code Replacement Library(CRL) - 將生成的標(biāo)準(zhǔn)代碼替換成廠商的高效庫函數(shù)/匯編碼
Processsor-In-the-Loop(PIL) - 將算法模型生成可執(zhí)行文件后(如.out)放到目標(biāo)硬件上執(zhí)行并和主機(jī)上的仿真結(jié)果進(jìn)行對比的一種等效性測試手段
External Mode - 將(算法)模型生成可執(zhí)行文件后獨立運(yùn)行在目標(biāo)硬件上并和原模型保持連接,此時原模型可理解為一種上位機(jī)“界面”,上位機(jī)模型和下位機(jī)目標(biāo)碼可以聯(lián)動。
注:MathWorks 官方推出的硬件支持包通常是兼顧芯片級和板級,以芯片級為主,板級主要是支持一些官方或熱門的開發(fā)板。
硬件支持包的開發(fā)要求開發(fā)人員具備相應(yīng)的知識和技能,以下是最基本的要求:
嵌入式軟硬件知識,通常包括使用 MCU/MPU/FPGA,調(diào)試工具和常用設(shè)備等技能
嵌入式軟件知識,通常包括熟悉嵌入式操作系統(tǒng),編程,常用 IDE 的使用,通信協(xié)議,手寫 makefile 等能力
Embedded Coder 定制化知識和代碼生成的深刻理解
MATLAB 面向?qū)ο缶幊痰闹R
常見通信協(xié)議知識,包括 SCI,TCP/IP,CAN 等
只有在具備以上能力的前提下才能較好的開發(fā)出硬件支持包。另外,MathWorks 官方以及三方芯片廠商也會提供一些熱門芯片的現(xiàn)成的硬件支持包,在確定開發(fā)之前,應(yīng)該進(jìn)行相關(guān)調(diào)研,如果市面上已經(jīng)存在相應(yīng)的支持包,建議直接使用現(xiàn)成的。比如 NXP 針對其各系列芯片就提供了對應(yīng)的硬件支持包供客戶選擇。
本文將聚焦硬件支持包中 PIL 功能的開發(fā),介紹如何開發(fā)自己的 PIL 支持包。
PIL 基本原理
? ?
首先介紹下 PIL 的基本概念,如圖所示,PIL 測試供包含兩次仿真,分別是:
1)將軟件的Simulink模型首先在Simulink環(huán)境中運(yùn)行一次,在給定激勵下會產(chǎn)生一些輸出,記錄下來;
2)接著將軟件的 Simulink 模型生成代碼并編譯鏈接成可執(zhí)行目標(biāo)碼,下載至下位機(jī)板子上運(yùn)行,在相同的激勵下軟件在板子上運(yùn)行也會產(chǎn)生一些輸出,也記錄下來。
3)最后將兩次輸出的結(jié)果進(jìn)行等效性比對。
目前這些基本操作在 MathWorks 提供的工具鏈中都是傻瓜式操作,大家可自行查閱文檔學(xué)習(xí),本文不做贅述。
如圖所示,一個完整的 PIL 仿真過程由以下各階段組成:
選擇三種 PIL 仿真方式中的一種啟動 PIL 仿真,至于哪三種方式可參考文檔
驗證上位機(jī)下位機(jī)連接配置
模型生成核心代碼
實例化 PIL API 組件(即 PIL Framework,就是幾個 PIL 專用的 MATLAB 類文件)
繼續(xù)生成額外的 PIL 需要用到的輔助代碼,配合模型生成的核心代碼組成一個包含上位機(jī)下位機(jī)通信和控制的完整應(yīng)用代碼
基于注冊好的 ToolchainInfo 對象中的編譯信息,調(diào)用三方交叉編譯器將完整的應(yīng)用代碼生成可執(zhí)行的目標(biāo)文件。同時調(diào)用上位機(jī)的 C/C++ 編譯器 (MinGW 或 Visual Studio) 把 PIL Framework 中涉及的 C/C++ 代碼編譯成 C Mex S Function(可簡單理解成加殼的 dll 或 so 文件),這些代碼主要是上位機(jī)端的 C/C++ 通訊源碼。
上位機(jī) Simulink 模型下發(fā)指令啟動下位機(jī)運(yùn)行目標(biāo)代碼
Simulink Engine 通過 C Mex S Function 和下位機(jī)進(jìn)行數(shù)據(jù)交互
上位機(jī) Simulink 模型下發(fā)指令終止下位機(jī)目標(biāo)代碼的運(yùn)行
Simulink 模型停止 PIL 仿真
PIL 開發(fā)方法論
第一步
軟硬件開發(fā)環(huán)境
開發(fā)的第一步是搭建軟硬件開發(fā)環(huán)境,具體來說:
●硬件環(huán)境:開發(fā)板,調(diào)試器,外圍電路,通訊接口等
●軟件環(huán)境:IDE,MATLAB 等,特別注意 IDE 一定要支持命令行調(diào)用,這是自動化的前提,有些 IDE 的非商業(yè)版本只允許界面操作,這個是做不了支持包的!
●資料收集:各種可能涉及的參考資料,比如芯片的數(shù)據(jù)表,開發(fā)板的原理圖,IDE 的使用手冊等等
●通訊:PIL 會涉及上位機(jī)和下位機(jī)通信,所以通訊協(xié)議和通訊的硬件部分必須匹配,比如我們希望所開發(fā)的支持包支持上位機(jī)下位機(jī)通過 CAN 進(jìn)行程序的燒寫和數(shù)據(jù)交互,那么要求板子上的硬件必須支持 CAN 通訊,并且上位機(jī)一般要通過 USB-CAN 卡與下位機(jī)相連,如下圖所示。理論上,任何通訊協(xié)議都可以,MathWorks 內(nèi)置有部分現(xiàn)成的上位機(jī)通訊協(xié)議,包括串口和 TCP/IP,下位機(jī)部分仍然需要自己編寫。其他協(xié)議如 CAN 則需要自己編寫上位機(jī)和下位機(jī)通訊驅(qū)動。
一個良好的軟硬件開發(fā)環(huán)境可以通過寫個 makefile 來點燈的例子進(jìn)行驗證。一旦完成點燈,意味著我們已經(jīng)具備的基本的軟硬件開發(fā)環(huán)境。
第二步
Toolchain 的開發(fā)和 Hardware Board 注冊
從上文知道 PIL 仿真過程需要一鍵編譯鏈接和下載目標(biāo)碼,這個動作是由 Toolchain 來實現(xiàn)的,因此開發(fā) PIL 的第一步是開發(fā) Toolchain。
這里先解釋下 Toolchain 在本文的含義,我們知道嵌入式開發(fā)自動化腳本通常就是 makefile,而 Toolchain 大家可以認(rèn)為就是 MATLAB 版本的 makefile,是用 M 語言按照一定的要求和格式進(jìn)行編寫,其中需要寫明匯編器、編譯器、鏈接器、下載器、格式轉(zhuǎn)換器等工具的命令行調(diào)用方法,編譯成目標(biāo)碼所需要使用的各種依賴庫等。這樣可以將其自動嵌入到代碼生成的流程中去,實現(xiàn)所謂的“一鍵編譯下載”。
為了更好的講解后續(xù)內(nèi)容,建議大家先跳到 第5步 - 細(xì)節(jié)學(xué)習(xí),安裝 C2000 的官方支持包,這是一個非常好的學(xué)習(xí)對象。這里就以 C2000 支持包為例講解下 Toolchain 開發(fā)的要點。
C2000 支持包的安裝目錄(位置參考第 5 步中的截圖)找到 tiCCS.m 文件,大家可以直接使用這個文件作為自己 Toolchain 開發(fā)的模板,這個文件中最核心的部分包括:
●coder.make.ToolchainInfo:定義 ToolchainInfo 對象,下圖是該對象的透視圖,可以說開發(fā) Toolchain,本質(zhì)就是操作這個 ToolchainInfo 對象
●使用上述對象的 getBuildTool 方法注冊各類工具,比如 Assembler,Compiler,Linker,Archiver
●使用上述對象的 getPrebuildTool/getPostbuildTool 方法注冊各類代碼生成前后處理工具,比如編譯后自動下載等
●使用上述對象的 getBuildConfiguration 方法提供不同等級的 Build Configuration,比如保留調(diào)試能力的編譯配置,高度優(yōu)化的編譯配置等,它們的本質(zhì)區(qū)別就是編譯器優(yōu)化等級不同
一旦完成上述內(nèi)容的開發(fā),下一步就是注冊該文件,這里我們以 TI TMS320 C6678 DSP 的 Toolchain 開發(fā)為例介紹:
●TI_TMS320C6678_toolchain.m – 所開發(fā)的toolchain 的 M 代碼
●sl_customization.m – 用來注冊硬件板子和 Toolchain 對象,這樣用戶可以在 Hardware Implementation 和 Code Generation 下面看到板子和 Toolchain 可供選擇。
function sl_customization(cm) cm.registerTargetInfo(@loc_createDevice); end function thisDev = loc_createDevice thisDev(1) = RTW.HWDeviceRegistry; thisDev(1).Vendor = 'Texas Instruments'; thisDev(1).Type = 'TMS320C6678'; thisDev(1).Alias = {}; thisDev(1).Platform = {'Prod', 'Target'}; thisDev(1).setWordSizes([8 16 32 32 32 32 64 32]); thisDev(1).LargestAtomicInteger = 'Long'; thisDev(1).LargestAtomicFloat = 'Double'; thisDev(1).Endianess = 'Little'; thisDev(1).IntDivRoundTo = 'Zero'; thisDev(1).ShiftRightIntArith = true; end
●refreshTITMS320C6678Toolchain.m – 注冊 Toolchain的 腳本,包括調(diào)用 TI_TMS320C6678_toolchain.m 并將其保存成 TI_TMS320C6678_toolchain.mat 格式,進(jìn)一步調(diào)用 RTW.TargetRegistry.getInstance('reset') 注冊 Toolchain。
function refreshTITMS320C6678Toolchain %Make sure we are in the right directory currentDir = pwd; toolchainPath = getpref(' MyToolchainName', 'TOOLCHAINPATH'); cd(toolchainPath); % Create a new configuration gtc= MyToolchainName_toolchain; tc=gtc(1); save([toolchainPath ' TI_TMS320C6678_toolchain.mat'], 'tc'); % Refresh customisations defined by rtwTargetInfo.m RTW.TargetRegistry.getInstance('reset'); % Return to directory cd(currentDir) end
一旦注冊完成后我們就可以在模型參數(shù)配置界面上找到這個 Toolchain 作為代碼生成的選項,其中:
Hardware Implementation->Hardware board 中可選擇剛剛注冊的板子:
Code Generation中可選擇剛剛注冊的板子:
最后構(gòu)建一個極簡的模型來驗證該Toolchain能夠完成模型的一鍵編譯下載。
第三步
PIL 工具鏈的組成
接著就是 PIL 最核心的開發(fā)部分,圖中紅色部分就是我們需要開發(fā)的內(nèi)容,其中 PIL API Components 即 MathWorks 官方提供的一套標(biāo)準(zhǔn)的 PIL 開發(fā)框架,包括:上位機(jī)和下位機(jī)端各自的通訊協(xié)議,Build Process 和 Launcher等,該框架的核心就是名為 Connectivity Configuration 的幾個類文件組成,以下為開發(fā)要點:
●開發(fā) PIL Target 核心功能類(即 Connectivity Configuration 類的編寫)
●桌面端和 IDE 中分別調(diào)通上位機(jī)和下位機(jī)的通訊功能,移植到核心功能類中
●下位機(jī) Timer 配置并注冊核心功能類中,主要服服務(wù)于后續(xù)下位機(jī)上任務(wù)運(yùn)行時間的統(tǒng)計和分析
這里對上述要點進(jìn)一步展開介紹下,還是以 TI TMS320 C6678 DSP 的支持包開發(fā)為例,下圖是一個典型的 PIL Target 目錄,這里便于我們進(jìn)行講解:
1)開發(fā)上位機(jī)和下位機(jī)通訊協(xié)議
比如截圖中是使用串口協(xié)議,并把上位機(jī)的串口協(xié)議和下位機(jī)的串口協(xié)議代碼分別放到 host_dll 和 target_src 中。如果是其他通訊協(xié)議,則把相應(yīng)的協(xié)議代碼分門別類放好即可。通訊協(xié)議代碼需要按照一定的格式使用 rtiostream 函數(shù)進(jìn)行封裝。
關(guān)于 rtiostream 函數(shù)的使用請查閱文檔示例或者 C2000 支持包安裝目錄中的代碼。另外,對于串口和 TCP/IP,MATLAB 官方提供了現(xiàn)成的上位機(jī)協(xié)議 dll 供使用,具體位置請查閱幫助文檔。
2)開發(fā) PIL Target 核心功能類
其中 +tic6678codetargetpil 中存放了 PIL 的核心功能類,這些類文件都是通用的,大家可以直接使用官方 C2000 支持包安裝目錄中的 pil 代碼作為模板進(jìn)行微調(diào)基本就能滿足要求。各個類的使用細(xì)節(jié)請直接參考文檔。
3)注冊硬件定時器 Timer
Timer 的注冊有兩種方式:1)crtool;2)Timer 類。C2000 支持包使用的是 crtool 方式,在文檔中搜索:Specify Hardware Timer 關(guān)鍵字即可找到操作指南,這種方式略微復(fù)雜些。當(dāng)然也可以使用類的方式進(jìn)行 Timer 注冊,以下為前述 C6678 示例中 Timer 的注冊方式:
classdef Timer < rtw.connectivity.Timer % TIMER Get timing information for C6678 application % ? Copyright 2022 The MathWorks, Inc. ? ?methods ? ? ? ?function this = Timer(varargin) ? ? ? ? ? ? ? ? ? ? ? ?this.setTimerDataType('uint32'); % i.e. unsigned long ? ? ? ? ? ?% Look for an input providing ticks per second ? ? ? ? ? ?if (nargin > 0) ticksPerSecond = varargin{1}; else ticksPerSecond = round(1.0e9/6); end this.setTicksPerSecond(ticksPerSecond); % The timer counts upwards this.setCountDirection('up'); % Extract path information from MATLAB Preferences timerSrcFolder = fullfile(fileparts(mfilename('fullpath')),'..','rtiostream','rtiostreamserial','target_src'); % Configure source files required to access the timer timerHeaderFile = fullfile(timerSrcFolder, 'ProfilerTimer.h'); timerSourceFile = fullfile(timerSrcFolder, 'ProfilerTimer.c'); this.setSourceFile(timerSourceFile); this.setHeaderFile(timerHeaderFile); % Configure the expression used to read the timer readTimerExpression = 'profileTimerRead()'; this.setReadTimerExpression(readTimerExpression); end end end
4)注冊整個 PIL 硬件支持包
function rtwTargetInfo(tr) %RTWTARGETINFO Target info callback,register individual targets with Coder Target % Copyright 2022 The MathWorks, Inc. tr.registerTargetInfo(@loc_createToolchain); tr.registerTargetInfo(@loc_createConfig); codertarget.TargetRegistry.addToTargetRegistry(@loc_registerThisTarget); codertarget.TargetBoardRegistry.addToTargetBoardRegistry(@loc_registerBoardsForThisTarget); end % ------------------------------------------------------------------------- % Create ToolchainInfoRegistry entries for TI TMS320C6678 function config = loc_createToolchain config = coder.make.ToolchainInfoRegistry; % initialize % Append to last in the toolchain registry base config(end).Name = 'TI TMS320C6678 Toolchain v1.0 | gmake (win64)'; toolchainPath = mfilename('fullpath'); [toolchainDir, ~] = fileparts(toolchainPath); config(end).FileName = fullfile(toolchainDir,'toolchain','TI_TMS320C6678_toolchain_win64.mat'); %MODIFY %List the platform or platforms supported by the custom toolchain %'*' means it supports any hardware device. config(end).TargetHWDeviceType = {'*'}; %config(end).Platform = {computer('arch')}; config(end).Platform = {'win64'}; end function ret = loc_registerThisTarget() ret.Name = 'TI TMS320C6678'; [targetFilePath, ~, ~] = fileparts(mfilename('fullpath')); ret.TargetFolder = targetFilePath; end % ------------------------------------------------------------------------- function boardInfo = loc_registerBoardsForThisTarget() target = 'TI TMS320C6678'; [targetFolder, ~, ~] = fileparts(mfilename('fullpath')); boardFolder = codertarget.target.getTargetHardwareRegistryFolder(targetFolder); % Point to folder registry/targethardware boardInfo = codertarget.target.getTargetHardwareInfo(targetFolder, boardFolder, target); end % ------------------------------------------------------------------------- % Specify settings for valid PIL configuration function config = loc_createConfig % Create object for serial connectivity configuration config(1) = rtw.connectivity.ConfigRegistry; % Assign connectivity configuration name config(1).ConfigName = 'TMS320C6678 PIL Serial'; % Associate the connectivity configuration with the connectivity % API implementation config(1).ConfigClass = 'tic6678codetargetpil.SerialConnectivityConfig'; % match TI C6678 toolchains config(1).Toolchain = {'TI TMS320C6678 Toolchain v1.0 | gmake (win64)'}; % Match only ert.tlc config(1).SystemTargetFile = {'ert.tlc'}; % Through the HardwareBoard and TargetHWDeviceType properties, % define compatible code for the target connectivity configuration % match only TI C6678 config(1).HardwareBoard = {}; config(1).TargetHWDeviceType = {'Texas Instruments->TMS320C6678'}; end
第四步
PIL 支持包的測試
可以自行構(gòu)建一個簡單的模型,使用 SIL/PIL Manager 進(jìn)行測試,具體的操作技巧請查閱文檔,這里不做贅述。
第五步
細(xì)節(jié)學(xué)習(xí)
限于篇幅和嵌入式本身的復(fù)雜性,本文無法面面俱到,最好的學(xué)習(xí)資料就是仔細(xì)研究一些現(xiàn)成的硬件支持包,比如 MathWorks 官方提供的 C2000 硬件支持包:
大家安裝完成后,結(jié)合本文,仔細(xì)翻閱支持包安裝目錄,基本就能把各種細(xì)節(jié)摸清楚。幫助文檔中也有 PIL 的示例和資料,相對來說篇幅較多也比較零散,需要耐心閱讀。R2019a 引入了 target Package,即一組高度抽象的 API 來便利化硬件支持包的開發(fā),由于其高度抽象性,建議仍然使用本文描述的方法進(jìn)行 PIL 支持包開發(fā),這樣調(diào)試起來會方便很多。
說的再多,都不如找一塊板子實際開發(fā)一遍,祝大家都能掌握PIL開發(fā)的方法論,在項目中引入PIL測試環(huán)節(jié),以期提高產(chǎn)品質(zhì)量,減少后期枯燥地調(diào)試工作。
審核編輯:劉清
-
FPGA
+關(guān)注
關(guān)注
1635文章
21837瀏覽量
608334 -
GPIO
+關(guān)注
關(guān)注
16文章
1223瀏覽量
52744 -
MBD
+關(guān)注
關(guān)注
0文章
26瀏覽量
9062 -
PIL
+關(guān)注
關(guān)注
0文章
19瀏覽量
8671 -
SIL
+關(guān)注
關(guān)注
0文章
11瀏覽量
2589
原文標(biāo)題:PIL (Process-in-the-Loop) 硬件支持包開發(fā)指南
文章出處:【微信號:MATLAB,微信公眾號:MATLAB】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
兆易創(chuàng)新AN056 GD32F4xx系列硬件開發(fā)指南
兆易創(chuàng)新AN057 GD32F3x0系列硬件開發(fā)指南
兆易創(chuàng)新AN069 GD32L233系列硬件開發(fā)指南
兆易創(chuàng)新AN074 GD32E23x系列硬件開發(fā)指南
兆易創(chuàng)新GD32W51x硬件開發(fā)指南
MSPM0 G系列MCU硬件開發(fā)指南

MSPM0 L 系列 MCU硬件開發(fā)指南

評論