基於ZYNQ的雙核CPU之間的通信

項目簡述

我們都知道ZYNQ中有兩個ARM核,但是如何使ZYNQ運行這兩個ARM核,以及雙核之間的數據如何進行交互是非常重要的問題。雙核CPU的運行方式主要有兩種:1、SMP 對稱處理器架構 ,2、 AMP 非對稱處理器架構,SMP結構雙核之間的關係比較密切,AMP架構雙核之間邏輯關係較小,開發難度也比較簡單。

工程描述:運行ZYNQ的兩個ARM核,同時利用OCM3進行雙核之間簡單的數據交互。

本次實驗所用到的軟硬件環境如下:
1、VIVADO 2019.1
2、米聯客MZ7015FA開發板

CPU0代碼

因爲該工程除了在Block Design側例化一個ZYNQ的IP,其他不需要做任何處理,所以我們將不再進行PL側的講解。直接對PS側的代碼進行講解。PS端地址的分佈情況如下:
在這裏插入圖片描述
在沒有做其他設置的情況下ZYNQ上電後地址空間分別如上圖所示。OCM共256KB按照64KB分爲4塊,其中前三塊在SDK中表述爲RAM0佔192KB處於地址空間的最開頭和DDR共用地址空間,最後一塊64KB處於地址空間的最後。ZYNQ的DDR固定佔地址空間的最開頭1GB字節因而ZYNQ的DDR最大容量就只有1GB。爲了避開OCM從上圖可知實際使用的DDR只有1023MB(最開頭的1MB被保留避開OCM的前三塊)。從0x40000000到0xDFFFFFFF的2GB空間留給了自定義IP或者其他IP的寄存器,從BSP的xparameters.h可以看出在PL部分添加的IP其基址都是從0x40000000開始的,而ZYNQ自己的寄存器則從0xE0000000開始編制,具體寄存器內容請查閱UG585的附錄B Register Details。其實Standalone作爲基礎的BSP所作的工作都是在通過指針訪問各個寄存器而已,在不考慮安全性的前提下可以完全不用BSP直接操作寄存器對ZYNQ進行操作。所以我們一般使用OCM3作爲CPU0與CPU1的共享內存使用。
我們這裏給出相應的CPU0的代碼;

#include <stdio.h>
#include "xil_mmu.h"
#include "xil_printf.h"

#define COMM_VAL  (*(volatile unsigned long *)(0xffff0000)) //OCM3

int main()
{
	COMM_VAL =0;
	//disable cache on chip mem
	Xil_SetTlbAttributes(0xffff0000,0x14de2);
	while(1){

		print("Hello World CPU0 \n\r");
		COMM_VAL =1;
		while(COMM_VAL ==1){

		}
	}
    return 0;
}

我們上面的代碼唯一看不懂的就是下面這段話:
在這裏插入圖片描述
這段程序其實就是CPU0中禁止OCM的Cache屬性,以爲內Cache功能會向OCM3中填入一些緩存數據進而讓OCM3中的數據進入不可控的狀態。

CPU1代碼

上面對工程的原理已經進行了講解,這裏我們直接給出相應的CPU1的代碼,如下:

#include <stdio.h>
#include "xil_mmu.h"
#include "xil_printf.h"
#include "sleep.h"

#define COMM_VAL  (*(volatile unsigned long *)(0xffff0000)) //OCM3
int main()
{
	//disable cache on chip mem
		Xil_SetTlbAttributes(0xffff0000,0x14de2);
		while(1){
			while(COMM_VAL ==0){

			}
			print("Hello World CPU1 \n\r");
			usleep(100);
			COMM_VAL =0;
		}

    return 0;
}

但是想要CPU1的代碼成功運行起來,我們需要在CPU1的bsp文件中添加如下代碼:創建CPU1的應用程序時需要設置CPU1的BSP SETTING extra-compel-flags 設置 -DUSE_AMP=1。
在這裏插入圖片描述
在這裏插入圖片描述
因爲是AMP架構,所以得編輯lscript.ld文件,使得CPU0與CPU1的內存區間不相互重疊,如下;
CPU0修改:
在這裏插入圖片描述
CPU1修改:
在這裏插入圖片描述

運行結果

在進行下板運行的過程中也需要進行相應的設置如下:
在這裏插入圖片描述
在這裏插入圖片描述
進行完上面的配置,我們便可以下載相應的代碼到ZYNQ中,並且運行結果如下:
在這裏插入圖片描述

雙核CPU的固化SD卡

我們學完了雙核CPU如何跑相應的程序,那麼也需要進行學習如何固化相應的程序到達SD卡中。
在進行生成的FSBL的main文件中添加如下代碼,該代碼的意義是啓動CPU1的代碼:

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0
#define CPU1STARTMEM 0x02000000
void StartCpu1(void)
{
#if 1
fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r");
Xil_Out32(CPU1STARTADR, CPU1STARTMEM);
dmb(); //waits until write has finished
fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r");
sev();
#endif
}

找到 Load boot image 的位置,把 CPU1 的啓動函數,在此調用:

/*
* Load boot image
*/
HandoffAddress = LoadBootImage();
fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress);
StartCpu1(); /*add starting cpu1*/

然後創建 UBOOT.BIN
在這裏插入圖片描述
最後將生成的bin文件放到SD卡中即可。

參考文獻

[1]、V3學院

總結

創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。或者對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章