寫在前面
承接前文:ZYNQ-雙核AMP通信(一),前文對雙核AMP架構通信的相關內容進行了簡單的介紹,本文完成AMP架構通信的程序并驗證。
開發環境
vivado 18.3&SDK,PYNQ-Z2開發板。
工程設計
CPU0 接收串口的數據,并寫入OCM 中,然后利用軟件產生中斷觸發 CPU1;CPU1 接收到中斷后,根據從 OCM 中讀出的數據并用串口打印,并在控制結束后觸發 CPU0 中斷,實現了雙核 CPU 通信的功能。
系統框圖
在這里插入圖片描述
硬件平臺搭建
首先新建工程,創建 block design。添加ZYNQ7 ip,根據本次工程需要對IP進行配置。勾選本次工程使用的資源。
這里添加SPI和SD的資源是為了進行雙核的固化程序的驗證。硬件系統構建完成如下:
然后我們進行generate output product 然后生成HDL封裝。這里只用到了MIO引腳,所以不需要進行管腳分配,XADC測量是內部的電壓信息,并且使用的是PS_XADC接口。點擊導出硬件資源(不包含bit流文件,因為只用到了PS資源),接著launch SDK。
SDK軟件部分
新建應用工程,這里可以先進行創建CPU0的程序,這里和之前配置相同,無需特殊更改。點擊NEXT后,完成建立一個空工程。
然后修改cpu0的DDR的地址空間,打開src文件夾中的==lscript.ld==文件,該文件是鏈接腳本,可以進行配置應用程序的地址空間的大小。在圖中可以看到OCM的兩塊區域的對應的大小和起始地址以及該應用程序的DDR的起始地址和大小。
這里修改cpu0占用ddr的一半空間也即把==0x1FF00000==修改為==0x0FF00000==。
完成修改后ctrl + s 保存即可完成地址映射的修改。
同樣的操作進行新建xpu1工程創建。處理器選擇ps7_1。
創建完成后修改ddr的地址映射,這里需要進行簡單的計算,cpu0的起始地址為0x100000,大小為0x0FF00000,所以cpu1的起始地址為兩者之和,也即為0x1000000
所以對cpu1的程序修改地址映射如下圖:
打開板級支持包的設置界面
同時加入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應用起始地址的地址
#defineCPU1_START_ADDR 0x10000000 //CPU1應用起始地址
#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并跳轉至相應的程序
#definesev() __asm__("sev") //C語言內嵌匯編寫法 sendevent指令
//函數聲明
voidstart_cpu1();
voidcpu0_intr_init(XScuGic *intc_ptr);
voidsoft_intr_handler(void *CallbackRef);
//全局變量
XScuGicIntc; //中斷控制器驅動程序實例
intrec_flag = 0; //接收標志
charchar_input='\0';
//CPU0main函數
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){
//向共享的地址中寫入輸入的數據
Xil_Out8(SHARE_BASE,char_input);
xil_printf("CPU0: %c\n",char_input) ;
//給CPU1觸發中斷
XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU1,CPU1_ID);
}
rec_flag = 1;
}
}
return 0 ;
}
//啟動CPU1,用于固化程序
voidstart_cpu1()
{
//向 CPU1_COPY_ADDR(0Xffffffff0)地址寫入 CPU1 的訪問內存基地址
Xil_Out32(CPU1_COPY_ADDR, CPU1_START_ADDR);
dmb(); //等待內存寫入完成(同步)
sev(); //通過"SEV"指令喚醒CPU1并跳轉至相應的程序
}
//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);
//設置并打開中斷異常處理功能
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軟件中斷
}
//軟件中斷函數
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
//函數聲明
voidcpu1_intr_init(XScuGic *intc_ptr);
voidsoft_intr_handler(void *CallbackRef);
//全局變量
XScuGicIntc; //中斷控制器驅動程序實例
intsoft_intr_flag = 0; //軟件中斷的標志
charread_data;
//CPU1main函數
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中讀出數據
xil_printf("CPU1:%c\n",read_data) ;
//給給CPU0觸發中斷
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);
//設置并打開中斷異常處理功能
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軟件中斷
}
//軟件中斷函數
voidsoft_intr_handler(void *CallbackRef)
{
xil_printf("CUP1:Soft Interrupt from CPU0\n") ;
soft_intr_flag = 1;
}
下載程序
和之前不同這次需要在config界面進行勾選,確保兩個cpu的程序都下載進去。如下圖:
運行效果
在這里插入圖片描述
固化雙核程序
創建fsbl程序。
點擊next,選擇FSBL點擊finish。
選中cpu0的工程,右擊創建鏡像工程,
添加cpu1的elf文件
添加完成創建鏡像即可。燒錄flash操作如下圖:
references
- 正點原子開發視頻
- UG585
- xapp1079