寫在前面
承接前文:ZYNQ-雙核AMP通信(一),前文對雙核AMP架構(gòu)通信的相關(guān)內(nèi)容進(jìn)行了簡單的介紹,本文完成AMP架構(gòu)通信的程序并驗(yàn)證。
開發(fā)環(huán)境
vivado 18.3&SDK,PYNQ-Z2開發(fā)板。
工程設(shè)計
CPU0 接收串口的數(shù)據(jù),并寫入OCM 中,然后利用軟件產(chǎn)生中斷觸發(fā) CPU1;CPU1 接收到中斷后,根據(jù)從 OCM 中讀出的數(shù)據(jù)并用串口打印,并在控制結(jié)束后觸發(fā) CPU0 中斷,實(shí)現(xiàn)了雙核 CPU 通信的功能。
系統(tǒng)框圖
在這里插入圖片描述
硬件平臺搭建
首先新建工程,創(chuàng)建 block design。添加ZYNQ7 ip,根據(jù)本次工程需要對IP進(jìn)行配置。勾選本次工程使用的資源。
這里添加SPI和SD的資源是為了進(jìn)行雙核的固化程序的驗(yàn)證。硬件系統(tǒng)構(gòu)建完成如下:
然后我們進(jìn)行g(shù)enerate output product 然后生成HDL封裝。這里只用到了MIO引腳,所以不需要進(jìn)行管腳分配,XADC測量是內(nèi)部的電壓信息,并且使用的是PS_XADC接口。點(diǎn)擊導(dǎo)出硬件資源(不包含bit流文件,因?yàn)橹挥玫搅薖S資源),接著launch SDK。
SDK軟件部分
新建應(yīng)用工程,這里可以先進(jìn)行創(chuàng)建CPU0的程序,這里和之前配置相同,無需特殊更改。點(diǎn)擊NEXT后,完成建立一個空工程。
然后修改cpu0的DDR的地址空間,打開src文件夾中的==lscript.ld==文件,該文件是鏈接腳本,可以進(jìn)行配置應(yīng)用程序的地址空間的大小。在圖中可以看到OCM的兩塊區(qū)域的對應(yīng)的大小和起始地址以及該應(yīng)用程序的DDR的起始地址和大小。
這里修改cpu0占用ddr的一半空間也即把==0x1FF00000==修改為==0x0FF00000==。
完成修改后ctrl + s 保存即可完成地址映射的修改。
同樣的操作進(jìn)行新建xpu1工程創(chuàng)建。處理器選擇ps7_1。
創(chuàng)建完成后修改ddr的地址映射,這里需要進(jìn)行簡單的計算,cpu0的起始地址為0x100000,大小為0x0FF00000,所以cpu1的起始地址為兩者之和,也即為0x1000000
所以對cpu1的程序修改地址映射如下圖:
打開板級支持包的設(shè)置界面
同時加入AMP的一個交叉編譯的宏定義-DUSE_AMP=1
,添加在末尾。
cpu0程序
#include "xparameters.h"
#include "xscugic.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "stdio.h"
//宏定義
#defineINTC_DEVICE_IDXPAR_SCUGIC_SINGLE_DEVICE_ID //中斷ID
#defineSHARE_BASE 0xffff0000 //共享OCM首地址
#defineCPU1_COPY_ADDR 0xfffffff0 //存放CPU1應(yīng)用起始地址的地址
#defineCPU1_START_ADDR 0x10000000 //CPU1應(yīng)用起始地址
#defineCPU1_IDXSCUGIC_SPI_CPU1_MASK //CPU1ID
#defineSOFT_INTR_ID_TO_CPU0 0 //軟件中斷號 0 ,范圍:0~15
#defineSOFT_INTR_ID_TO_CPU1 1 //軟件中斷號 1 ,范圍:0~15
//"SEV"指令喚醒CPU1并跳轉(zhuǎn)至相應(yīng)的程序
#definesev() __asm__("sev") //C語言內(nèi)嵌匯編寫法 sendevent指令
//函數(shù)聲明
voidstart_cpu1();
voidcpu0_intr_init(XScuGic *intc_ptr);
voidsoft_intr_handler(void *CallbackRef);
//全局變量
XScuGicIntc; //中斷控制器驅(qū)動程序?qū)嵗?intrec_flag = 0; //接收標(biāo)志
charchar_input='\0';
//CPU0main函數(shù)
intmain()
{
//S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0
Xil_SetTlbAttributes(SHARE_BASE,0x14de2); //禁用OCM的Cache屬性
//S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0
Xil_SetTlbAttributes(CPU1_COPY_ADDR,0x14de2);//禁用0xfffffff0的Cache屬性
//啟動CPU1
start_cpu1();
//CPU0中斷初始化
cpu0_intr_init(&Intc);
while(1){
if(rec_flag == 0){
xil_printf("CPU0:請輸入字符\r\n");
scanf("%c",&char_input);
if(char_input != 13){
//向共享的地址中寫入輸入的數(shù)據(jù)
Xil_Out8(SHARE_BASE,char_input);
xil_printf("CPU0: %c\n",char_input) ;
//給CPU1觸發(fā)中斷
XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU1,CPU1_ID);
}
rec_flag = 1;
}
}
return 0 ;
}
//啟動CPU1,用于固化程序
voidstart_cpu1()
{
//向 CPU1_COPY_ADDR(0Xffffffff0)地址寫入 CPU1 的訪問內(nèi)存基地址
Xil_Out32(CPU1_COPY_ADDR, CPU1_START_ADDR);
dmb(); //等待內(nèi)存寫入完成(同步)
sev(); //通過"SEV"指令喚醒CPU1并跳轉(zhuǎn)至相應(yīng)的程序
}
//CPU0中斷初始化
voidcpu0_intr_init(XScuGic *intc_ptr)
{
//初始化中斷控制器
XScuGic_Config *intc_cfg_ptr;
intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,
intc_cfg_ptr->CpuBaseAddress);
//設(shè)置并打開中斷異常處理功能
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);
Xil_ExceptionEnable();
XScuGic_Connect(intc_ptr, SOFT_INTR_ID_TO_CPU0,
(Xil_ExceptionHandler)soft_intr_handler, (void *)intc_ptr);
XScuGic_Enable(intc_ptr, SOFT_INTR_ID_TO_CPU0); //CPU0軟件中斷
}
//軟件中斷函數(shù)
voidsoft_intr_handler(void *CallbackRef)
{
xil_printf("CPU0 : Soft Interrupt from CPU1\n");
rec_flag = 0;
}
cpu1程序
#include "xparameters.h"
#include "xscugic.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "stdio.h"
//宏定義
#defineINTC_DEVICE_IDXPAR_SCUGIC_SINGLE_DEVICE_ID //中斷ID
#defineSHARE_BASE 0xffff0000 //共享OCM首地址
#defineCPU0_IDXSCUGIC_SPI_CPU0_MASK //CPU0ID
#defineSOFT_INTR_ID_TO_CPU0 0 //軟件中斷號 0 ,范圍:0~15
#defineSOFT_INTR_ID_TO_CPU1 1 //軟件中斷號 1 ,范圍:0~15
//函數(shù)聲明
voidcpu1_intr_init(XScuGic *intc_ptr);
voidsoft_intr_handler(void *CallbackRef);
//全局變量
XScuGicIntc; //中斷控制器驅(qū)動程序?qū)嵗?intsoft_intr_flag = 0; //軟件中斷的標(biāo)志
charread_data;
//CPU1main函數(shù)
intmain()
{
//S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0
Xil_SetTlbAttributes(SHARE_BASE,0x14de2); //禁用OCM的Cache屬性
//CPU1中斷初始化
cpu1_intr_init(&Intc);
while(1){
if(soft_intr_flag){
read_data = Xil_In8(SHARE_BASE);//從共享OCM中讀出數(shù)據(jù)
xil_printf("CPU1:%c\n",read_data) ;
//給給CPU0觸發(fā)中斷
XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU0,CPU0_ID);
soft_intr_flag = 0;
}
}
return 0 ;
}
//CPU1中斷初始化
voidcpu1_intr_init(XScuGic *intc_ptr)
{
//初始化中斷控制器
XScuGic_Config *intc_cfg_ptr;
intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,
intc_cfg_ptr->CpuBaseAddress);
//設(shè)置并打開中斷異常處理功能
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);
Xil_ExceptionEnable();
XScuGic_Connect(intc_ptr, SOFT_INTR_ID_TO_CPU1,
(Xil_ExceptionHandler)soft_intr_handler, (void *)intc_ptr);
XScuGic_Enable(intc_ptr, SOFT_INTR_ID_TO_CPU1); //CPU1軟件中斷
}
//軟件中斷函數(shù)
voidsoft_intr_handler(void *CallbackRef)
{
xil_printf("CUP1:Soft Interrupt from CPU0\n") ;
soft_intr_flag = 1;
}
下載程序
和之前不同這次需要在config界面進(jìn)行勾選,確保兩個cpu的程序都下載進(jìn)去。如下圖:
運(yùn)行效果
在這里插入圖片描述
固化雙核程序
創(chuàng)建fsbl程序。
點(diǎn)擊next,選擇FSBL點(diǎn)擊finish。
選中cpu0的工程,右擊創(chuàng)建鏡像工程,
添加cpu1的elf文件
添加完成創(chuàng)建鏡像即可。燒錄flash操作如下圖:
references
- 正點(diǎn)原子開發(fā)視頻
- UG585
- xapp1079