多核開發(fā)指南)
1. ZYNQ雙核通信到底解決什么問題做嵌入式開發(fā)的老哥們應(yīng)該都有這種經(jīng)歷產(chǎn)品功能一多單核處理器就有點喘不過氣。這邊要跑人機交互和網(wǎng)絡(luò)協(xié)議棧那邊還要實時響應(yīng)電機控制、數(shù)據(jù)采集你爭我搶稍不留神就出現(xiàn)任務(wù)超時。ZYNQ這顆芯片出現(xiàn)在視野里的頻率越來越高就是因為它把ARM Cortex-A9雙核和FPGA可編程邏輯放在同一顆芯片上天生就是為這種“既要又要”的場景準(zhǔn)備的。ZYNQ-7000系列內(nèi)部有兩個ARM Cortex-A9硬核處理器這是它最值錢的地方之一。很多初學(xué)者一開始只用了其中一個核另一個核閑著沒事干這在小項目里沒問題但等你做的產(chǎn)品稍微復(fù)雜一點比如要做EtherCAT主站、要做視覺引導(dǎo)、要跑算法又要實時控制的時候單核會非常吃力。這時你就會想能不能讓CPU0跑Linux處理人機界面和網(wǎng)絡(luò)協(xié)議讓CPU1跑FreeRTOS處理實時任務(wù)這就是異構(gòu)雙核通信的典型應(yīng)用場景。但問題是兩個核各跑各的系統(tǒng)怎么讓它們協(xié)同工作怎么互相傳遞數(shù)據(jù)這就需要一套成熟的通信機制而在ZYNQ平臺上OpenAMP就是目前最主流的解決方案。這篇文章我基于2018.3版本的工具鏈從零開始給你搭建一套完整的OpenAMP開發(fā)環(huán)境把LinuxFreeRTOS的雙核通信跑通。2018.3雖然是好幾年前的版本了但整個架構(gòu)思路和配置方法放到現(xiàn)在依然適用很多老項目的維護也還在用這套流程。適合剛接觸ZYNQ雙核開發(fā)的工程師也適合那些已經(jīng)在用Linux單核、想擴展實時性的老手參考。2. 動手之前先把OpenAMP的底細(xì)摸清2.1 AMP與SMP的區(qū)別你想清楚了嗎在做ZYNQ雙核開發(fā)之前先得搞清楚SMP和AMP這兩個概念的區(qū)別。SMP是Symmetric Multi-Processing對稱多處理兩個核對等對稱共同管理一套操作系統(tǒng)Linux內(nèi)核原生的SMP支持就是干這個的啟動時兩個核都跑Linux共同分擔(dān)負(fù)載。AMP則是Asymmetric Multi-Processing非對稱多處理兩個核跑不同的系統(tǒng)各有各的分工。ZYNQ做雙核通信玩的其實是AMP模式一個核跑Linux另一個核跑FreeRTOS或者裸機程序。兩者獨立運行通過共享內(nèi)存和中斷機制互相通信。Symmetric多處理系統(tǒng)SMP就像公司里兩個能力相同的員工共同負(fù)責(zé)同一個項目彼此之間的協(xié)作緊密。而非對稱多處理系統(tǒng)AMP更像是一個產(chǎn)品經(jīng)理負(fù)責(zé)對外溝通協(xié)調(diào)一個技術(shù)專家負(fù)責(zé)具體技術(shù)攻堅各管一攤通過定期會議同步進(jìn)度。ZYNQ上的雙核通信本質(zhì)就是讓產(chǎn)品經(jīng)理Linux核和技術(shù)專家FreeRTOS核各司其職通過高效的溝通機制協(xié)同工作。明白了這個區(qū)別你才能理解OpenAMP在這套架構(gòu)中扮演的角色。2.2 OpenAMP和它的三個關(guān)鍵組成OpenAMP全稱是Open Asymmetric Multi-Processing是Xilinx在Linux內(nèi)核源碼樹里維護的一套開源框架專門解決異構(gòu)多核通信問題。它不是一個單一模塊而是一套組合方案主要由三部分構(gòu)成remoteproc、rpmsg和libmetal。remoteproc負(fù)責(zé)遠(yuǎn)程處理器的生命周期管理。說白了就是Linux怎么把FreeRTOS的固件加載到CPU1上去、怎么啟動它、怎么在需要的時候把它停下來。它有一套完整的狀態(tài)機從固件驗證到資源分配再到處理器啟動都有標(biāo)準(zhǔn)化的處理流程。rpmsg是Remote Processor Messaging負(fù)責(zé)兩個核之間的消息傳遞。它建立在共享內(nèi)存和中斷機制之上提供一種類似Socket的通信接口讓應(yīng)用層不需要關(guān)心底層共享內(nèi)存的具體位置和中斷的具體配置直接收發(fā)消息就行。libmetal則是一個硬件訪問抽象層把共享內(nèi)存、中斷、IO操作這些東西統(tǒng)一封裝讓用戶程序可以通過標(biāo)準(zhǔn)API訪問底層硬件。這套組合拳打下來你在Linux側(cè)寫一個應(yīng)用程序就可以像訪問普通文件或者Socket一樣和另一個核上的FreeRTOS進(jìn)行通信了。2.3 2018.3版本的技術(shù)棧組成選擇2018.3版本有它特定的技術(shù)背景。這個版本對應(yīng)的Vivado是2018.3PetaLinux也是2018.3對應(yīng)的Linux內(nèi)核是4.14版本。這套組合是當(dāng)時非常穩(wěn)定的組合網(wǎng)上資料豐富踩坑后的解決方案也最容易搜到。如果你用的是更新的版本比如2020.2或2021.1整體流程類似但會有細(xì)節(jié)差異比如PetaLinux的配置命令、設(shè)備樹文件的寫法、OpenAMP驅(qū)動的加載方式都會有調(diào)整。我見過不少人在新版上折騰不出來退回2018.3反而很快跑通了。2018.3版本的核心組件清單如下表所示組件版本/說明Vivado2018.3用于硬件工程設(shè)計和FSBL生成PetaLinux2018.3用于Linux內(nèi)核、根文件系統(tǒng)和設(shè)備樹構(gòu)建Linux內(nèi)核4.14Xilinx維護的分支內(nèi)建OpenAMP驅(qū)動U-Boot2018.01第二級引導(dǎo)程序FreeRTOSXilinx提供的移植版本基于9.0或10.0OpenAMP集成在Linux內(nèi)核和設(shè)備樹中不需要單獨下載3. 搭建環(huán)境的完整實操流程3.1 第一大步用Vivado把硬件工程準(zhǔn)備好在Vivado里新建一個基于ZYNQ的硬件工程芯片型號根據(jù)自己的板卡來選我用的是xc7z020clg400-1這顆芯片也就是ZYNQ-7020。如果你用的是其他型號操作完全一樣不影響后續(xù)流程。硬件工程的關(guān)鍵點在于PS側(cè)的配置。ZYNQ PS側(cè)的配置中有幾個配置項特別重要。首先是UART至少開啟一個串口用來做控制臺輸出和調(diào)試。其次是SD卡接口這個必須有因為后面U-Boot、內(nèi)核和設(shè)備樹都要從SD卡引導(dǎo)。再就是DDR配置按照你的板卡實際DDR型號和容量來設(shè)置配置錯了啟動必掛。如果你想讓Linux和FreeRTOS之間通過GPIO或者中斷互通有無這一步也要預(yù)先在PS-PL配置里使能相應(yīng)的EMIO或中斷控制器。不過做基礎(chǔ)的OpenAMP通信暫時用不到PL側(cè)邏輯保持最簡配置就行。生成硬件工程后導(dǎo)出硬件描述文件也就是那個.xsa文件或者.hdf文件。這個文件包含了整個硬件系統(tǒng)的描述信息后面PetaLinux和FSBL的生成都要依賴它。3.2 第二大步制作FSBL并將其添加到工程中FSBL是First Stage Boot Loader第一級引導(dǎo)程序它是ZYNQ啟動流程中不可或缺的一環(huán)。ZYNQ的啟動流程是BootROM從SD卡或QSPI中加載FSBLFSBL初始化DDR和時鐘然后加載U-Boot或裸機應(yīng)用程序。在Vivado里創(chuàng)建FSBL的過程是點擊菜單欄的File - Export - Export Hardware導(dǎo)出硬件描述文件然后File - Launch SDK打開SDK開發(fā)環(huán)境。新建一個Application Project模板選擇Zynq FSBL編譯生成elf文件。這個步驟有個容易被忽略的坑生成FSBL時一定要確保硬件描述文件中的配置是正確的特別是DDR型號和大小。如果DDR配置錯了FSBL初始化內(nèi)存時序不對后面U-Boot起不來還是小事FreeRTOS加載到DDR里跑飛了排查起來特別鬧心。我調(diào)試的時候遇到過類似情況那時候用的是MT41K256M16HA-125顆粒時序參數(shù)缺了復(fù)位配置結(jié)果FSBL起不來。后來換了型號才跑正常。在生成FSBL時必須檢查DDR型號和參數(shù)是否完整。FSBL工程的源碼可以在SDK中查看它會根據(jù)硬件描述文件自動生成初始化代碼一般不需要手動修改。3.3 第三大步通過PetaLinux構(gòu)建Linux側(cè)系統(tǒng)PetaLinux是Xilinx提供的嵌入式Linux開發(fā)套件用起來比直接手動配置內(nèi)核要省心很多。創(chuàng)建一個PetaLinux工程然后導(dǎo)入上一步導(dǎo)出的硬件描述文件。petalinux-create -t project --name zynq_amp_demo cd zynq_amp_demo petalinux-config --get-hw-description/path/to/export/hw配置界面出來后重點檢查兩處一是Image Packaging Configuration下選擇SD卡啟動方式二是確定根文件系統(tǒng)類型我一般選ext4方便調(diào)試也方便直接掛載讀寫。然后需要進(jìn)行內(nèi)核配置確保OpenAMP相關(guān)驅(qū)動被編譯進(jìn)內(nèi)核。雖然4.14內(nèi)核里默認(rèn)帶了這些驅(qū)動但仍需檢查確認(rèn)一下。petalinux-config -c kernel在內(nèi)核配置菜單中依次檢查以下選項是否開啟Device Drivers - Remoteproc drivers - ZYNQ_REMOTEPROC Device Drivers - RPMSG drivers - RPMSG_VIRTIOZYNQ_REMOTEPROC選項負(fù)責(zé)管理CPU1的生命周期RPMSG_VIRTIO則是rpmsg通信的核心驅(qū)動這兩個都必須編譯進(jìn)內(nèi)核不能只編譯成模塊否則后面加載順序會出問題。接下來配置設(shè)備樹。設(shè)備樹在OpenAMP通信中起著關(guān)鍵作用它告訴Linux內(nèi)核CPU1的固件放在哪里、共享內(nèi)存基地址在哪里、使用哪個中斷號。2018.3版本的PetaLinux設(shè)備樹文件位于項目目錄下的subsystems/linux/device-tree目錄中也可以直接修改project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi。/ { reserved-memory { #address-cells 1; #size-cells 1; ranges; rproc_0_reserved: rproc3e800000 { compatible shared-dma-pool; no-map; reg 0x3e800000 0x1000000; }; }; remoteproc0: remoteproc0 { compatible xlnx,zynq-remoteproc-1.0; firmware freertos.elf; vring0 0x3e800000; vring1 0x3e804000; reg 0x3e808000 0x10000, 0x3e880000 0x10000; }; };這塊講幾個細(xì)節(jié)。reserved-memory節(jié)點的作用是給CPU1預(yù)留一塊物理內(nèi)存Linux內(nèi)核在啟動后不會使用這塊區(qū)域避免兩個系統(tǒng)踩踏。我預(yù)留的是從0x3E800000開始的16MB區(qū)域如果只做簡單的消息通信這個大小足夠了你要是跑更復(fù)雜的算法可以再調(diào)整。vring0和vring1是virtio ring的共享內(nèi)存區(qū)域這兩個地址必須在預(yù)留內(nèi)存范圍內(nèi)。reg屬性定義了兩塊區(qū)域第一塊是CPU1的入口地址第二塊是共享內(nèi)存的基地址這兩塊也要在預(yù)留范圍內(nèi)。配置好設(shè)備樹還要把編譯好的FreeRTOS固件拷貝到PetaLinux的根文件系統(tǒng)中。固件需要放到/lib/firmware目錄下并命名為freertos.elf這樣remoteproc驅(qū)動啟動時就能找到它。petalinux-build petalinux-package --boot --fsbl zynq_fsbl.elf --fpga --u-boot --force編譯完成后生成BOOT.BIN、image.ub等文件拷貝到SD卡中Linux系統(tǒng)就能啟動了。3.4 第四大步編譯FreeRTOS工程FreeRTOS側(cè)的工程Xilinx提供了專門的移植版本可以在Xilinx的GitHub倉庫中找到。下載后在SDK中新建一個Application Project選擇FreeRTOS模板然后把下載的FreeRTOS源碼整合進(jìn)去。FreeRTOS工程的配置有幾個關(guān)鍵點處理器必須選擇Cortex-A9MPx1也就是只使用CPU1這一個核堆大小根據(jù)你的任務(wù)數(shù)量和消息大小來定建議至少16KB起步tick rate選擇1000Hz保證實時調(diào)度的精度。設(shè)置好這些還需要編寫OpenAMP的通信相關(guān)代碼。FreeRTOS側(cè)使用OpenAMP庫需要把libmetal和open-amp的源碼也加進(jìn)工程里這個我會在第4節(jié)詳細(xì)說。FreeRTOS工程編譯后輸出的elf文件就是后面要拷貝到Linux根文件系統(tǒng)里的那個freertos.elf。4. 雙核通信代碼實現(xiàn)細(xì)節(jié)4.1 RPMsg通道的建立與消息收發(fā)OpenAMP的通信核心機制就是rpmsg。使用流程跟Socket通信很像需要先建立通道然后收發(fā)數(shù)據(jù)。Linux側(cè)的代碼如下#include openamp/open_amp.h #include metal/alloc.h #include rpmsg_lite.h #define SHARED_MEM_POOL_SIZE (1024 * 1024) #define RPMSG_SERVICE_NAME amp-demo struct rpmsg_device *rpdev; struct rpmsg_endpoint *epend; static void rpmsg_read_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { printf(received: %s\n, (char *)data); rpmsg_send(ept, ack from Linux, 15); } int main(void) { void *shared_mem; struct rpmsg_virtio_device *rvdev; struct metal_io_region *io; ... }這段代碼的核心邏輯是初始化OpenAMP庫和libmetal創(chuàng)建一個rpmsg端點注冊收到消息后的回調(diào)函數(shù)然后進(jìn)入主循環(huán)等待消息。這里需要提醒的是共享內(nèi)存池的大小要根據(jù)你的業(yè)務(wù)消息最大長度來定不是越大越好太大浪費內(nèi)存太小又會限制消息長度。FreeRTOS側(cè)的代碼結(jié)構(gòu)類似也需要初始化OpenAMP并創(chuàng)建rpmsg端點然后在RTOS的一個獨立任務(wù)中循環(huán)接收和發(fā)送數(shù)據(jù)。void vOpenAMPTask(void *pvParameters) { struct rpmsg_lite_instance *rpmsg_lite; struct rpmsg_lite_endpoint *my_ept; uint32_t src_addr; char buf[256]; rpmsg_lite rpmsg_lite_init((void *)SHM_BASE_ADDR, 0, 0, 0); my_ept rpmsg_lite_create_ept(rpmsg_lite, RPMSG_SERVICE_NAME, rpmsg_read_cb, NULL, src_addr); while (1) { // 任務(wù)循環(huán)按需發(fā)送數(shù)據(jù) vTaskDelay(pdMS_TO_TICKS(100)); } }4.2 共享內(nèi)存地址要理清楚共享內(nèi)存是最容易出問題的地方。發(fā)生通信異常時十有八九就是地址沒對上。安全的排查方式是把三處地址對照檢查Linux側(cè)設(shè)備樹中定義的reg屬性里的共享內(nèi)存基地址、dts里reserved-memory的物理地址、FreeRTOS側(cè)代碼里的SHM_BASE_ADDR宏定義這三處必須一致。我在前面示例中用的是0x3E808000這只是個示例地址。你在實際項目中要根據(jù)自己的硬件布局來確定但原則是一致的。地址不對的表現(xiàn)也很有意思不是完全沒反應(yīng)而是偶爾能收到一兩條消息然后就卡死了。因為Linux已經(jīng)向那塊區(qū)域?qū)懭霐?shù)據(jù)但FreeRTOS讀的是另一塊內(nèi)存區(qū)域讀到的全是垃圾數(shù)據(jù)。4.3 中斷通知機制的配置rpmsg通信除了共享內(nèi)存還需要中斷機制來通知對方有新消息到達(dá)。Linux側(cè)通過remoteproc驅(qū)動配置好SPI中斷FreeRTOS側(cè)則需要初始化GIC并注冊對應(yīng)的中斷服務(wù)函數(shù)。在設(shè)備樹中需要通過interrupts屬性指定中斷號。ZYNQ的PS側(cè)中斷控制器是GICSPI中斷號從32開始編號。Xilinx的OpenAMP例程通常使用SPI中斷號61對應(yīng)的硬件中斷號是93也就是32加61。這里有個關(guān)鍵點中斷號對不對從Linux的啟動日志里基本看不出來一定要在FreeRTOS側(cè)的中斷服務(wù)函數(shù)里加上調(diào)試打印或者狀態(tài)翻轉(zhuǎn)否則中斷是否觸發(fā)完全無感。5. 啟動流程配置與聯(lián)調(diào)經(jīng)驗5.1 啟動順序為什么這么重要ZYNQ上LinuxFreeRTOS的AMP模式啟動順序是一個關(guān)鍵的考慮因素必須先啟動Linux等Linux完全起來后再手動加載FreeRTOS固件。因為FreeRTOS的固件放在Linux的根文件系統(tǒng)中Linux沒起來之前這個文件根本訪問不到。另外FreeRTOS使用的共享內(nèi)存區(qū)域需要Linux預(yù)留好如果Linux還沒初始化完就啟動FreeRTOS兩個系統(tǒng)會爭搶同一塊內(nèi)存區(qū)域。啟動順序確定了在操作上體現(xiàn)為系統(tǒng)啟動后不會自動加載固件而是需要手動執(zhí)行一條命令來加載。echo freertos.elf /sys/class/remoteproc/remoteproc0/firmware echo start /sys/class/remoteproc/remoteproc0/state第一條命令告訴remoteproc驅(qū)動使用哪個固件文件第二條命令觸發(fā)固件加載和CPU1啟動。執(zhí)行成功后FreeRTOS就開始運行了兩個核之間的通信也隨之建立。5.2 如何驗證雙核通信已經(jīng)打通通信跑通了沒有不能靠肉眼猜需要有明確的驗證手段。我通常分成三步來驗證。先確認(rèn)CPU1已經(jīng)啟動。執(zhí)行以下命令看remoteproc的狀態(tài)cat /sys/class/remoteproc/remoteproc0/state狀態(tài)應(yīng)該是running表示CPU1已經(jīng)在運行FreeRTOS了。再驗證共享內(nèi)存可見性。在Linux側(cè)用devmem命令直接讀取預(yù)留內(nèi)存區(qū)域的內(nèi)容能看到FreeRTOS寫入的固定模式數(shù)據(jù)就說明共享內(nèi)存通路是通的。最后測試雙向收發(fā)。在Linux側(cè)運行一個測試程序周期性地向CPU1發(fā)送消息并在回調(diào)函數(shù)中接收CPU1的回應(yīng)。在FreeRTOS側(cè)的任務(wù)中收到消息后打印一串標(biāo)識并通過rpmsg回復(fù)如果Linux側(cè)能一直穩(wěn)定收到回復(fù)且持續(xù)運行一段時間不崩潰說明雙核通信基本穩(wěn)定。5.3 聯(lián)調(diào)過程中的關(guān)鍵調(diào)試手段聯(lián)調(diào)階段調(diào)試手段是省時的關(guān)鍵。我常用的思路是用串口打點、用共享內(nèi)存做鏡像觀察區(qū)和檢查Linux內(nèi)核日志。兩個核分別接一個串口是最好的方式CPU0的Linux控制臺一個串口CPU1的FreeRTOS打印一個串口兩邊各自的運行狀態(tài)一目了然。如果硬件上只有一個串口可以考慮用GPIO翻轉(zhuǎn)加示波器觀察關(guān)鍵節(jié)點的狀態(tài)變化但比較費勁不如加個串口省心。Linux內(nèi)核日志也是重要的參考來源加載固件和啟動CPU1時內(nèi)核會打印remoteproc相關(guān)的日志通過dmesg可以查看到底卡在哪一步。6. 這里有幾個我實際踩過的坑6.1 固件加載失敗提示文件不存在系統(tǒng)執(zhí)行固件加載命令時提示找不到文件首先檢查路徑和文件名是否正確。注意固件需要放在根文件系統(tǒng)/lib/firmware目錄下并且文件名要和echo命令里寫的一致。很多文件系統(tǒng)鏡像打包時會改變文件位置或權(quán)限可以先用ls確認(rèn)文件確實存在同時確認(rèn)這個內(nèi)核帶有固件查找路徑的配置。6.2 共享內(nèi)存地址沖突導(dǎo)致系統(tǒng)卡死這類問題表現(xiàn)最詭異有時候不是啟動時崩而是運行一段時間后整個系統(tǒng)直接hang住。排查思路是確認(rèn)Linux的預(yù)留內(nèi)存是否與內(nèi)核啟動時使用的內(nèi)存區(qū)域沖突、檢查Linux內(nèi)核啟動參數(shù)中的memmap參數(shù)是否正確設(shè)置以及在設(shè)備樹中是否正確配置no-map屬性。還有一個笨辦法但很有效在FreeRTOS側(cè)沒有啟用MMU操作共享內(nèi)存會直接影響物理地址。在Linux側(cè)先寫一部分?jǐn)?shù)據(jù)到共享內(nèi)存中FreeRTOS側(cè)讀取時設(shè)置一個特殊值來判讀是否讀到有效數(shù)據(jù)兩邊對照就能判斷是不是地址沖突的問題。6.3 中斷不觸發(fā)消息收不到消息發(fā)出去后對方?jīng)]有任何反應(yīng)多半是中斷配置有問題。排查時先確認(rèn)設(shè)備樹中的中斷號是否正確再確認(rèn)FreeRTOS側(cè)的GIC初始化是否完成最后檢查兩端是不是用的同一套中斷邏輯。有一個比較隱蔽的問題當(dāng)FreeRTOS側(cè)的GIC沒有正確配置時中斷永遠(yuǎn)進(jìn)不了中斷處理函數(shù)。可以用一個周期性的定時器中斷來驗證GIC是否正常工作如果在FreeRTOS任務(wù)里能看到定時器中斷觸發(fā)說明GIC配置沒問題問題出在rpmsg中斷上。6.4 開機啟動流程不穩(wěn)定的風(fēng)險曾經(jīng)有段時間我想優(yōu)化啟動流程想著不需要手動敲命令直接在Linux的啟動腳本里自動加載FreeRTOS固件。結(jié)果發(fā)現(xiàn)系統(tǒng)啟動時自動加載的時序很微妙如果在內(nèi)核的某些子系統(tǒng)初始化完成之前就啟動CPU1偶爾會發(fā)生莫名其妙的死鎖。后來采用了一種更穩(wěn)妥的方式在系統(tǒng)啟動完成并進(jìn)入用戶態(tài)之后通過一個啟動腳本延時幾秒再加載固件。雖然沒有完全做到自動加載無縫啟動但穩(wěn)定性大幅提升。如果業(yè)務(wù)要求啟動速度可以再研究內(nèi)核啟動流程和remoteproc驅(qū)動的加載時機找到更早但安全的加載點。7. 2018.3版本到新版本遷移的思路先用2018.3版本把流程跑通、把原理吃透這是學(xué)習(xí)階段最好的狀態(tài)。但實際產(chǎn)品落地時你可能會因為需要使用新版Vivado的特性或者需要支持更新的外設(shè)而不得不升級到新版工具鏈。遷移的時候有幾個地方需要特別留意。新版本PetaLinux的內(nèi)核和設(shè)備樹結(jié)構(gòu)與舊版有較多變化。以2020.1版本為例設(shè)備樹的語法、remoteproc驅(qū)動的綁定方式、PetaLinux的命令都有調(diào)整網(wǎng)上找的舊教程基本不能直接套用需要按新版本的文檔重新配置。Xilinx官方發(fā)布過OpenAMP的完整示例工程如果學(xué)習(xí)的話建議先跑官方工程對流程有全局認(rèn)識后再結(jié)合自身需求進(jìn)行修改。官方示例中關(guān)于共享內(nèi)存布局、中斷分配、設(shè)備樹配置的信息是可以作為參考依據(jù)的核對清楚后自己配置起來也不會有什么大問題。FreeRTOS側(cè)的移植也可能遇到接口變化。各版本OpenAMP和libmetal庫的API存在差異升級后需要檢查之前的回調(diào)函數(shù)定義、端點創(chuàng)建接口是否還能編譯通過。8. 給你的最后建議8.1 按這個順序?qū)W習(xí)上手最快學(xué)習(xí)路徑建議是這樣先用Vivado生成最小硬件工程完成FSBL制作和PetaLinux的構(gòu)建確保Linux能在ZYNQ上獨立跑起來然后再配置設(shè)備樹加入OpenAMP節(jié)點把官方例程中的FreeRTOS固件放進(jìn)去先跑通官方自帶的程序最后再自己寫應(yīng)用層的消息收發(fā)代碼把流程徹底吃透。按這個順序走每步都有根基即使出了問題也好定位。8.2 從單核到雙核思路要跟著換ZYNQ雙核開發(fā)跟普通的單片機或者純Linux開發(fā)不太一樣很多問題都是因為系統(tǒng)性的隔離沒做好。共享內(nèi)存的地址分配、中斷的底層配置這部分對Linux內(nèi)核的底層知識掌握程度提出了要求。建議先花時間看看設(shè)備樹語法、閱讀一下remoteproc驅(qū)動的源碼有了對整個啟動流程和內(nèi)存布局的全局理解后續(xù)開發(fā)會更方便。不少工程師剛開始做雙核通信時容易緊張害怕把系統(tǒng)搞崩。其實放心大膽試就行崩了大不了重新燒固件多試幾次對系統(tǒng)的理解就會更深入。我做這套開發(fā)的第三周就徹底搞明白了“預(yù)留內(nèi)存”、“rproc狀態(tài)切換”和“消息回調(diào)”之間的聯(lián)系整個通信鏈路在自己腦子里形成了一個完整閉環(huán)。ZYNQ的雙核通信是個大話題這篇文章從環(huán)境搭建到代碼實現(xiàn)再到問題排查盡量把關(guān)鍵環(huán)節(jié)都過了一遍。如果你的項目里既有界面和網(wǎng)絡(luò)的需求又有實時的控制任務(wù)這套方案是可以認(rèn)真考慮的方向。