現(xiàn)指南)
Zynq UltraScale MPSoC 這款芯片在實(shí)際項(xiàng)目里用了好幾年了從最初在裸機(jī)上調(diào)外設(shè)到后來在 APU 上跑 Linux再到需要在 RPU 上并行跑裸機(jī)實(shí)時(shí)任務(wù)一步步踩過來的。最近剛好把一套 OpenAMP 點(diǎn)對點(diǎn)通信方案從零搭完Vitis IDE 里 RPU 裸機(jī)程序這邊從平臺創(chuàng)建到跑通 echo 測試過程其實(shí)比想象中要繞網(wǎng)上資料也比較碎所以我把整套操作流程、配置要點(diǎn)和踩坑記錄整理出來希望能幫你少走些彎路。這套方案能解決什么問題簡單說就是在 Zynq UltraScale MPSoC 里讓跑著 Linux 的 Cortex-A53APU和跑著裸機(jī)程序的 Cortex-R5FRPU之間通過共享內(nèi)存和 OpenAMP 框架實(shí)現(xiàn)高效的消息通信。對于需要做電機(jī)控制、工業(yè)網(wǎng)絡(luò)協(xié)議棧、實(shí)時(shí)信號采集同時(shí)又需要 Linux 承擔(dān)人機(jī)交互、網(wǎng)絡(luò)通信的場合這個(gè)軟件架構(gòu)非常實(shí)用。我寫這篇的適用讀者是手里有 ZynqMP 開發(fā)板想在 RPU 上跑裸機(jī)實(shí)時(shí)程序又需要和 APU 側(cè)互通數(shù)據(jù)的嵌入式工程師無論你是剛接觸 Vitis 還是已經(jīng)能跑通 hello world這條鏈路都能用。1. 項(xiàng)目概述與整體架構(gòu)拆解1.1 先理清 Zynq UltraScale MPSoC 的異構(gòu)架構(gòu)Zynq UltraScale MPSoC 的 PS 端集成了三套關(guān)鍵處理單元四核 Cortex-A53APU64位主頻可達(dá) 1.5GHz、雙核 Cortex-R5FRPU32位主頻可達(dá) 600MHz以及 Mali-400 GPU。對嵌入式開發(fā)來說最核心的就是 APU 和 RPU 的協(xié)同工作——A53 適合跑 Linux、跑復(fù)雜協(xié)議棧R5F 則非常適合跑裸機(jī)實(shí)時(shí)程序中斷延遲低、行為可預(yù)測而且還專門配備了 TCM緊耦合內(nèi)存非常適合做時(shí)序敏感的控制任務(wù)。RPU 雙核有兩種運(yùn)行模式Split 模式和 LockStep 模式。LockStep 模式下兩個(gè) R5 核心像一個(gè)核心一樣同步執(zhí)行適合對安全性要求極高的場景Split 模式下兩個(gè)核各自獨(dú)立運(yùn)行各自訪問各自的外設(shè)和中斷適合把一個(gè)核留給裸機(jī)實(shí)時(shí)控制另一個(gè)核跑別的任務(wù)。我們這套方案用的是 Split 模式默認(rèn)讓 R5_0 作為 OpenAMP 的遠(yuǎn)端處理器實(shí)例R5_1 暫不啟用。1.2 OpenAMP 框架與 RPU 裸機(jī)的角色分工OpenAMPOpen Asymmetric Multi-Processing是個(gè)開源異構(gòu)多核通信框架它提供了遠(yuǎn)程處理器生命周期管理、消息傳遞、多核同步等能力。在 ZynqMP 里OpenAMP 主要做了以下幾件事管理 RPU 的資源表resource table比如共享內(nèi)存地址、vring 地址、通知機(jī)制等通過 RPMsgRemote Processor Messaging協(xié)議在 APU 和 RPU 之間建立通道化的消息通信依靠 libmetal 硬件抽象層屏蔽不同處理器、不同操作系統(tǒng)的差異。在這套方案里APU 側(cè)負(fù)責(zé)主導(dǎo)通常是主處理器它負(fù)責(zé)加載 RPU 的固件ELF 文件、啟動(dòng)和停止 R5 核心RPU 側(cè)是遠(yuǎn)端處理器運(yùn)行一個(gè)裸機(jī)程序不做啟動(dòng)引導(dǎo)的活只在被通知后執(zhí)行通信和應(yīng)用邏輯。這個(gè)角色分工非常像“師傅帶徒弟”——APU 把固件放到共享內(nèi)存告訴 R5 從哪里開始執(zhí)行之后兩者通過 RPMsg 通道你一言我一語地交換數(shù)據(jù)。1.3 為什么選擇 Vitis IDE 而不是傳統(tǒng) SDKVitis IDE 是 Xilinx現(xiàn)在叫 AMD官方推出的統(tǒng)一開發(fā)環(huán)境它最大的優(yōu)勢在于把硬件平臺配置文件XSA、BSP板級支持包、多核異構(gòu)工程管理、調(diào)試下載都整合在一起了。相比老一代 SDKVitis 對多域、多處理器的工程管理做得更好你可以基于同一個(gè)平臺工程分別為 R5 建 standalone 裸機(jī)工程、為 A53 建 Linux 工程或裸機(jī)工程并且可以在同一窗口里調(diào)試不同核。這里有個(gè)經(jīng)驗(yàn)值得說如果你只是做 RPU 裸機(jī)開發(fā)不涉及 Linux那么 Vitis 的輕量級創(chuàng)建方式只建 standalone 域就夠了。但如果要同時(shí)調(diào)試 Linux 側(cè)的 remoteproc 驅(qū)動(dòng)最好把 Linux 域和 standalone 域放在同一個(gè)平臺工程里這樣后續(xù)交叉調(diào)試時(shí)路徑、宏定義、依賴關(guān)系都不容易亂。2. 開發(fā)環(huán)境準(zhǔn)備與工程創(chuàng)建2.1 硬件平臺與軟件工具鏈清單我個(gè)人實(shí)測用的是 ZCU104 開發(fā)板但這套流程對 ZCU102、Ultra96 等同樣適用因?yàn)楹诵脑砗蛙浖J墙y(tǒng)一的。硬件上你需要Zynq UltraScale MPSoC 開發(fā)板一塊USB-UART 線用于 APU 和 RPU 的串口輸出JTAG 調(diào)試器板載 JTAG 或外部 USB-JTAGZCU104 板載 JTAG 即可。軟件方面我使用的是 Vitis IDE 2022.1 版本Vivado 硬件工程配套導(dǎo)出的 XSA 文件作為平臺輸入。注意不同版本的 Vitis 內(nèi)置的 OpenAMP 和 libmetal 版本會(huì)有差異代碼接口細(xì)節(jié)略有不同但整體流程一致。如果你用的是 2023.x 或 2023.2API 差異也不大遇到編譯報(bào)錯(cuò)時(shí)優(yōu)先查看頭文件定義即可。在開始之前建議先在 Vivado 里完成 PS 配置DDR、UART、SD 等外設(shè)按需使能并導(dǎo)出 XSA 文件。這里強(qiáng)調(diào)一個(gè)關(guān)鍵點(diǎn)在 Vivado 的 PS-PL 配置界面中PSU DDR 的地址段決定了 R5 和 A53 能看到的內(nèi)存窗口建議給共享內(nèi)存預(yù)留一個(gè)固定且不與 Linux 內(nèi)核重疊的高端地址區(qū)域比如 0x3ED00000后續(xù) OpenAMP 配置會(huì)用到這個(gè)值。2.2 創(chuàng)建 Vitis 平臺工程這一步?jīng)Q定后續(xù)程序結(jié)構(gòu)打開 Vitis IDE先設(shè)置工作空間目錄然后通過File - New - Platform Project創(chuàng)建平臺工程。在向?qū)е羞x擇前面 Vivado 導(dǎo)出的 XSA 文件操作系統(tǒng)這里重點(diǎn)來了——要同時(shí)勾選standalone和linux兩個(gè)域如果不想做 Linux 側(cè)可以只選 standalone但以后想加 Linux 調(diào)試就得重新建平臺不如一次到位。處理器選擇psu_cortexr5_0作為 standalone 域的處理器Linux 域則自動(dòng)關(guān)聯(lián)psu_cortexa53。點(diǎn)擊完成并等 Vitis 自動(dòng)編譯平臺會(huì)在工程里生成 standalone BSP里面的xparameters.h包含所有硬件基地址和中斷號等關(guān)鍵宏定義。這個(gè)文件后面寫裸機(jī)程序時(shí)會(huì)頻繁用到尤其要留意XPAR_XUARTPS_0_BASEADDR、XPAR_PSU_DDR_0_S_AXI_BASEADDR等宏的值。平臺工程創(chuàng)建完最好立即檢查一下 BSP 里支持的庫列表右鍵平臺工程中的psu_cortexr5_0選擇Board Support Package Settings在 Libraries 選項(xiàng)卡里確認(rèn)openamp和libmetal有對應(yīng)的條目。如果在 Vitis 2022.1 里沒有看到 openamp 庫選項(xiàng)那是因?yàn)椴糠职姹灸J(rèn)不顯示你需要通過手動(dòng)添加庫路徑的方式解決具體方法我在第 3 節(jié)展開講。2.3 創(chuàng)建 RPU 裸機(jī)應(yīng)用工程優(yōu)先用官方模板在平臺工程上右鍵選擇New - Application Project應(yīng)用名稱可以叫r5_openamp_demo處理器選psu_cortexr5_0語言選 C然后在模板頁面選擇OpenAMP echo-test。這個(gè)模板包含了 RPU 側(cè)的通信測試代碼、資源表、鏈接腳本等是官方提供的“最小可跑通”工程特別適合用來驗(yàn)證硬件環(huán)境和 OpenAMP 框架是否工作。如果你沒找到OpenAMP echo-test模板也可以先選擇Empty Application(C)然后手動(dòng)添加 OpenAMP 相關(guān)的源文件和配置。不過我還是建議先用官方模板跑通一次再自行修改到自己的業(yè)務(wù)代碼邏輯這樣排查問題會(huì)簡單很多。官方模板生成的代碼結(jié)構(gòu)比“從零寫”要清晰尤其資源表那部分直接手寫很容易出錯(cuò)。創(chuàng)建完成后Vitis 會(huì)自動(dòng)生成echo_test.c、rsc_table.c、rsc_table.h、lscript.ld等關(guān)鍵文件。先不要急著改代碼先編譯一遍確?;A(chǔ)工程能通過再往下進(jìn)行配置調(diào)整。3. 核心配置讓 OpenAMP 在 RPU 上跑起來3.1 啟用 BSP 中的 OpenAMP 與 libmetal 庫在 Vitis 2022.1 里如果平臺工程采用 standalone 域BSP 設(shè)置中默認(rèn)并不會(huì)自動(dòng)把 OpenAMP 庫編譯進(jìn)來。你需要右鍵psu_cortexr5_0-Board Support Package Settings左側(cè)選中l(wèi)ibraries勾選libmetal和openamp。如果這里沒有這些庫選項(xiàng)說明這個(gè)版本的 Vitis 沒有內(nèi)置匹配的編譯依賴一個(gè)可行的辦法是修改platform.spr文件里的 BSP 配置或者在應(yīng)用工程的 Makefile 里主動(dòng)鏈接庫路徑但我更推薦直接在應(yīng)用工程源碼目錄下手動(dòng)加入 OpenAMP 頭文件和源碼在官方模板里已經(jīng)附帶了一部分以模板為準(zhǔn)。還有一個(gè)容易忽略的細(xì)節(jié)BSP 里stdin和stdout設(shè)備要設(shè)置為可用的串口設(shè)備。在 Vitis 默認(rèn)設(shè)置中standalone BSP 會(huì)優(yōu)先尋找psu_uart_0如果 Vivado 里使能的是psu_uart_1輸出就會(huì)莫名其妙地消失這不是程序邏輯問題純粹是 BSP 配置問題。排查時(shí)一看到 R5 程序跑起來但串口毫無反應(yīng)先檢查這里。3.2 鏈接腳本與內(nèi)存區(qū)域規(guī)劃RPU 裸機(jī)程序的鏈接腳本lscript.ld決定了固件在內(nèi)存中的布局。對于 OpenAMP 方案至少需要兩個(gè)內(nèi)存區(qū)域程序運(yùn)行區(qū)域代碼、數(shù)據(jù)、堆棧放在 DDR 或 TCM 中。TCM 訪問延遲低又沒有緩存一致性問題但只有 128KB I-TCM、128KB D-TCM如果你的程序不大放 TCM 很合適。缺點(diǎn)是 TCM 空間有限且要注意 TCM 的訪問權(quán)限配置。OpenAMP 共享內(nèi)存區(qū)域用于 vring 和 RPMsg 消息緩沖必須同時(shí)能被 APU 和 RPU 訪問所以一般都制定在 DDR 的固定地址上比如 0x3ED00000 這個(gè)地址附近。以官方模板為例它生成的lscript.ld默認(rèn)把程序起始放在psu_ddr_0_S_AXI_BASEADDR 0x10000000也就是 DDR 的某個(gè)偏移共享內(nèi)存則放在OPENAMP_MEM段地址可以從資源表里的 vdev 定義看出來。實(shí)際使用中你需要確認(rèn)這個(gè)地址是否和 Linux 設(shè)備樹中預(yù)留的內(nèi)存區(qū)間不沖突否則 APU 上的 Linux 可能會(huì)寫入同一地址導(dǎo)致數(shù)據(jù)互相踩踏。這里我建議的分配方式比如 DDR 基地址是 0x00000000給 RPU 程序 1MB 用于代碼和堆棧例如 0x3EB00000 ~ 0x3EC00000給 OpenAMP 共享內(nèi)存 1MB例如 0x3ED00000 ~ 0x3EE00000。這樣 A53 Linux 內(nèi)存從 0x0 一直到 0x3EAFFFFF完全不沖突。具體地址可以在 Vivado 里查 DDR 地址映射也可以在實(shí)際運(yùn)行時(shí)通過 resource table 回調(diào)打印驗(yàn)證。3.3 資源表Resource Table到底在配置什么資源表是 OpenAMP 通信的核心數(shù)據(jù)結(jié)構(gòu)它告訴主處理器APU遠(yuǎn)端處理器RPU如何把共享內(nèi)存區(qū)域轉(zhuǎn)換成通信隊(duì)列。資源表里最關(guān)鍵的是firmware resource unit其中最核心的條目是fw_rsc_vdev里面定義了 virtio 設(shè)備的兩個(gè) vring 信息vring 的地址、對齊方式、描述符數(shù)量、通知 ID??茨0逯衦sc_table.c的示例代碼resources.offset[0] 0x120這個(gè)偏移量對應(yīng)到resources.rsc_tbl[0]中定義的那個(gè)fw_rsc_vdev結(jié)構(gòu)體。結(jié)構(gòu)體里vring[0].da指向 0x3ED40000vring[1].da指向 0x3ED41000每個(gè) vring 有 64 個(gè)描述符對齊是 4096 字節(jié)。這些值設(shè)計(jì)得很講究vring 需要 4096 字節(jié)對齊兩個(gè) vring 之間預(yù)留了足夠的空間避免描述符表互相覆蓋。實(shí)操里經(jīng)常出現(xiàn)的問題就是 APU 側(cè)和 RPU 側(cè)的資源表不一致比如 vring 地址不同、num 不同、notifyid 不同導(dǎo)致握手失敗或者報(bào)錯(cuò)。所以當(dāng)你修改了 RPU 側(cè)的共享內(nèi)存地址務(wù)必同步修改 APU 側(cè) remoteproc 設(shè)備樹里的資源表定義。4. 通信程序?qū)崿F(xiàn)與驗(yàn)證4.1 RPU 側(cè) echo 測試程序核心邏輯梳理官方模板的 RPU 側(cè)核心代碼主要做三件事初始化 OpenAMP 運(yùn)行時(shí)、注冊 RPMsg 回調(diào)函數(shù)、輪詢等待消息并原樣回發(fā)。關(guān)鍵的流程是初始化 libmetal 底層metal_init初始化底層設(shè)備抽象如內(nèi)存映射、設(shè)備樹節(jié)點(diǎn)解析初始化遠(yuǎn)程處理器rproc_init傳入傳輸層比如基于共享內(nèi)存的虛擬傳輸并啟動(dòng)該處理器初始化 RPMsgrpmsg_init創(chuàng)建 RPMsg 虛擬設(shè)備并注冊rpmsg_channel_created、rpmsg_channel_destroyed、rpmsg_read_cb三個(gè)回調(diào)函數(shù)進(jìn)入主循環(huán)程序不斷輪詢并調(diào)用rpmsg_poll或metal_poll來處理接收到的消息收到消息后讀取內(nèi)容再原樣調(diào)用rpmsg_send回發(fā)到源地址。static int rpmsg_read_cb(struct rpmsg_channel *rp_chnl, void *data, int len, void *priv, unsigned long src) { xil_printf(Received: %.*s, echoing...\r\n, len, (char *)data); return rpmsg_send(rp_chnl, data, len); }回調(diào)函數(shù)里要注意data緩沖區(qū)是共享內(nèi)存區(qū)域中的副本還是直接指向共享內(nèi)存不同版本的 OpenAMP 行為不一樣。Vitis 自帶的實(shí)現(xiàn)中數(shù)據(jù)讀入的是本地緩沖所以可以直接在data上操作但在某些 openamp 版本里data是共享內(nèi)存的虛擬地址別名如果你在這里長時(shí)間持有該地址并再次寫入需要留意緩存一致性問題。R5 在默認(rèn)配置下是帶緩存的而共享內(nèi)存區(qū)域通常配置為普通內(nèi)存此時(shí)操作數(shù)據(jù)前后沒有顯式 flush/invalidate 的話很容易出現(xiàn)數(shù)據(jù)“半新半舊”的現(xiàn)象。4.2 APU 側(cè)Linux如何配合 RPU 通信如果 APU 側(cè)跑的是 Linux你需要先在 Linux 內(nèi)核菜單中確認(rèn)以下配置已開啟CONFIG_REMOTEPROCy CONFIG_RPMSGy CONFIG_RPMG_CHARy CONFIG_ZYNQMP_R5_REMOTEPROCy如果內(nèi)核里沒有CONFIG_ZYNQMP_R5_REMOTEPROC說明內(nèi)核版本里的 remoteproc 驅(qū)動(dòng)沒有包含 ZynqMP R5 支持這在高版本 Linux如 5.10 之后通常是有的。編譯內(nèi)核時(shí)還可以開啟CONFIG_RPMG_CHAR以便在用戶空間通過/dev/rpmsg_ctrl0直接收發(fā)消息。設(shè)備樹里需要為 R5 預(yù)留內(nèi)存并添加 remoteproc 節(jié)點(diǎn)。以 5.15 內(nèi)核為例可以在設(shè)備樹中添加reserved-memory { #address-cells 2; #size-cells 2; ranges; rproc_0_reserved: rproc3ed00000 { no-map; reg 0x0 0x3ed00000 0x0 0x100000; }; }; zynqmp-r5-remoteproc0 { compatible xlnx,zynqmp-r5-remoteproc; reg 0x0 0x3ed00000 0x0 0x10000; core_conf split; r5-tcm-a psu_r5_tcm_a; r5-tcm-b psu_r5_tcm_b; memory-region rproc_0_reserved; };之后在 Linux 用戶空間可以通過 configfs 或 sysfs 把編譯好的 R5 ELF 固件加載到 remoteproc再觸發(fā)啟動(dòng)。例如mkdir /sys/kernel/config/remoteproc/remoteproc0 echo -n /path/to/r5_openamp_demo.elf /sys/kernel/config/remoteproc/remoteproc0/firmware echo start /sys/kernel/config/remoteproc/remoteproc0/state啟動(dòng)成功后可以通過rpmsg_char或直接寫測試程序進(jìn)行消息收發(fā)。一個(gè)最簡單的 Linux 側(cè) RPMsg 測試程序通過/dev/rpmsg_ctrl0創(chuàng)建通道后往/dev/rpmsg0寫入數(shù)據(jù)就能看到 R5 原樣回發(fā)的數(shù)據(jù)。4.3 編譯下載與運(yùn)行驗(yàn)證的完整流程在 Vitis 中先編譯平臺工程再編譯 RPU 裸機(jī)應(yīng)用工程。編譯無誤后你可以直接用 Vitis 的Run Configuration將程序下載到 R5 并運(yùn)行前提是 JTAG 連接正常。選擇 R5 核添加 ELF 文件路徑然后啟動(dòng)調(diào)試會(huì)話。比較關(guān)鍵的一點(diǎn)是如果你打算最終用 Linux 來加載 R5 固件那么 Vitis 調(diào)試階段對 R5 的內(nèi)存寫入和 Linux 后續(xù)的 remoteproc 加載會(huì)互相影響。我通常的做法是先在 Vitis 里單獨(dú)用 JTAG 跑通 R5 側(cè)通信確認(rèn)沒有硬件問題后再聯(lián)合 Linux 做整體驗(yàn)證。這樣做的好處是萬一通信不成功你能快速判斷是 R5 程序本身的問題還是 APU 側(cè)配置的問題。串口輸出是主要驗(yàn)證手段。R5 側(cè)的 UART 打印建議用xil_printf而不是重定向到標(biāo)準(zhǔn)庫的printf前者的實(shí)現(xiàn)更輕量而且針對裸機(jī)環(huán)境做了適配。Linux 側(cè)的用戶程序則直接printf到終端方便對比兩端日志。實(shí)際驗(yàn)證成功時(shí)的輸出效果大致是Linux 側(cè)往 RPMsg 通道寫入一條 hello r5 字符串R5 串口打印出收到該消息并同時(shí)通過 RPMsg 把消息原樣回發(fā)Linux 側(cè)讀取到回包打印出回復(fù)內(nèi)容。這個(gè) echo 來回如果穩(wěn)定 1000 次不丟包說明通信鏈路是可靠可用的。5. 常見問題與排查技巧實(shí)錄5.1 高頻問題盤點(diǎn)按癥狀給解決方案這幾個(gè)問題我在這類項(xiàng)目里碰到最多次整理成表方便你速查現(xiàn)象可能原因解決辦法R5 程序一啟動(dòng)就死機(jī)不打印任何信息BSP 里 stdout 串口配置錯(cuò)誤TCM 或 DDR 地址訪問權(quán)限不對核對 BSP 的 stdin/stdout 設(shè)備在 Vivado PS 配置中確認(rèn) R5 的 DDR slave 訪問權(quán)限OpenAMP 模板編譯報(bào)錯(cuò)找不到openamp/open_amp.hBSP 未啟用 openamp 庫xparameters.h 中宏定義缺失檢查 BSP 的 Libraries 勾選確認(rèn)平臺工程重新編譯過echo 測試進(jìn)行中消息收發(fā)偶爾失敗vring 地址不是 4096 對齊共享內(nèi)存與 Linux 內(nèi)存沖突檢查資源表 vring 地址核對設(shè)備樹預(yù)留內(nèi)存范圍R5 收到消息內(nèi)容亂碼共享內(nèi)存緩存一致性問題在 R5 側(cè)讀取前做 cache invalidate發(fā)送前 flush或者把共享內(nèi)存區(qū)域配置為 non-cacheable使用 Linux remoteproc 加載 R5 固件失敗ELF 格式或加載地址不匹配設(shè)備樹 remoteproc 節(jié)點(diǎn)地址錯(cuò)誤檢查 ELF 加載地址和設(shè)備樹 reg、memory-region 是否一致確認(rèn)core_conf正確RPU 雙核配置時(shí)另一個(gè)核不執(zhí)行Split 模式未正確配置兩個(gè)核的入口點(diǎn)相同檢查 Vivado 中 RPU 工作模式在 Vitis 中分別為 R5_0、R5_1 配置不同程序5.2 一些調(diào)試經(jīng)驗(yàn)和特別提醒第一個(gè)經(jīng)驗(yàn)是關(guān)于“先確認(rèn)裸機(jī)基礎(chǔ)再上 OpenAMP”。很多新手一上來就想把 echo 跑通結(jié)果 RPU 連最基本的串口打印都沒搞定。我自己的習(xí)慣是先創(chuàng)建一個(gè)最簡單的空應(yīng)用只調(diào)用xil_printf打印一行字符用 JTAG 下載運(yùn)行確認(rèn) R5 能正常啟動(dòng)、串口輸出正常再去啟動(dòng) OpenAMP 工程。這一步能省下至少一晚上的排查時(shí)間。第二個(gè)經(jīng)驗(yàn)是關(guān)于共享內(nèi)存地址的規(guī)劃。這個(gè)地址牽涉三處R5 鏈接腳本、資源表、Linux 設(shè)備樹。三處必須一致否則兩邊的數(shù)據(jù)根本不在同一塊物理內(nèi)存上。我在實(shí)際項(xiàng)目中用過 0x3ED00000 這個(gè)地址當(dāng)時(shí)是參考了某方案的內(nèi)存布局但你自己做項(xiàng)目時(shí)要根據(jù) DDR 容量、Linux 保留區(qū)域、R5 代碼大小綜合確定。建議將地址規(guī)劃直接寫到設(shè)計(jì)文檔里并在代碼中加宏定義避免改一處漏兩處。第三個(gè)經(jīng)驗(yàn)比較特別當(dāng)通信頻率高、數(shù)據(jù)量大時(shí)單靠 RPMsg 通道效率可能不夠用。RPMsg 是復(fù)制語義每次發(fā)送都要把數(shù)據(jù)從用戶緩沖區(qū)拷貝到共享內(nèi)存再從共享內(nèi)存拷貝到接收緩沖區(qū)開銷不小。如果對實(shí)時(shí)性要求高一個(gè)折中方案是用 RPMsg 傳遞小消息而大數(shù)據(jù)走共享內(nèi)存加硬件同步機(jī)制。這個(gè)方案我們在多個(gè)項(xiàng)目里驗(yàn)證過既保持了 OpenAMP 的標(biāo)準(zhǔn)通信又能滿足帶寬需求。最后再分享一個(gè)小技巧在 Vitis 的調(diào)試視圖里可以同時(shí)連接 APU 和 RPU 兩個(gè)目標(biāo)進(jìn)行源碼級聯(lián)調(diào)。啟動(dòng)兩個(gè)調(diào)試配置一個(gè)是 A53 的 Linux 內(nèi)核調(diào)試或裸機(jī)一個(gè)是 R5 的裸機(jī)調(diào)試然后分別在兩個(gè)核上打斷點(diǎn)。這樣就能非常直觀地看到消息從 Linux 側(cè)發(fā)出后有沒有真正進(jìn)入 R5 的回調(diào)函數(shù)。單看串口日志只能確定最終結(jié)果源碼聯(lián)調(diào)可以看到中間每一層的數(shù)據(jù)流轉(zhuǎn)排查問題快很多。