1. 程式人生 > >ZYNQ基礎系列(五) AMP模式 雙裸核CPU同時執行

ZYNQ基礎系列(五) AMP模式 雙裸核CPU同時執行

AMP模式 雙核CPU同時執行

從軟體的角度來看,多核處理器的執行模式有三種:
AMP(非對稱多程序):多個核心相對獨立的執行不同的任務,每個核心可能執行不同的作業系統或裸機程式,但是有一個主要核心,用來控制整個系統以及其它從核心
SMP(對稱多程序):一個作業系統同等的管理各個核心,例如PC機
BMP(受約束多程序):與SMP類似,但開發者可以指定將某個任務僅在某個指定核心上執行
預設情況下,ZYNQ僅執行一個CPU,這裡主要研究AMP模式下,兩個CPU同時執行

實驗目的

使用ZYNQ7010完成
1> CPU0在裸核下執行helloworld,CPU1在裸核下執行流水燈
2> CPU0在linux下執行helloworld,CPU1在裸核下執行流水燈

硬體環境

硬體環境過於簡單,這裡只文字描述
1.建立原理圖,新增PS核,雙擊進入PS的配置介面
2.peripheral I/O pin裡開啟串列埠和EMIO和SD卡
3.在MIO configuration中,配置EMIO寬度為4
4.在clock configuration和DDR configuration中,設定對應的時鐘頻率和DDR型號
5.關閉配置介面,原理圖如下
這裡寫圖片描述
6.右擊原理圖,生成輸出檔案
7.右擊原理圖,生成頂層檔案
8.對LED進行引腳約束

set_property PACKAGE_PIN N15 [get_ports {LED_tri_io[0
]}] set_property PACKAGE_PIN N16 [get_ports {LED_tri_io[1]}] set_property PACKAGE_PIN M19 [get_ports {LED_tri_io[2]}] set_property PACKAGE_PIN M20 [get_ports {LED_tri_io[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED_tri_io[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED_tri_io[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED_tri_io[2
]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED_tri_io[3]}]

9.綜合、實現、生成bit檔案,並匯出硬體,執行SDK

SDK環境

AMP模式的使用,重點在SDK上
1.建立CPU0工程,選擇生成helloworld例程,內容為:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
int main()
{
    init_platform();
    while (1)
    {
      print("Hello World\n\r");
      sleep(2);
    }
    cleanup_platform();
    return 0;
}

2.建立CPU1工程
這裡寫圖片描述
注意選擇核1,建立led.c為主函式,內容為:

#include "xgpiops.h"
#include "sleep.h"
int main()
{
static XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int xStatus;
GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
if(GpioConfigPtr == NULL) return XST_FAILURE;
xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr,GpioConfigPtr->BaseAddr);
if(XST_SUCCESS != xStatus) return -1;

XGpioPs_SetDirectionPin(&psGpioInstancePtr, 54,1);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 55,1);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 56,1);
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 57,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 54,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 55,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 56,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 57,1);
while(1)
{
XGpioPs_WritePin(&psGpioInstancePtr, 54, 1);
sleep(1);
XGpioPs_WritePin(&psGpioInstancePtr, 54, 0);
XGpioPs_WritePin(&psGpioInstancePtr, 55, 1);
sleep(1);
XGpioPs_WritePin(&psGpioInstancePtr, 55, 0);
XGpioPs_WritePin(&psGpioInstancePtr, 56, 1);
sleep(1);
XGpioPs_WritePin(&psGpioInstancePtr, 56, 0);
XGpioPs_WritePin(&psGpioInstancePtr, 57, 1);
sleep(1);
XGpioPs_WritePin(&psGpioInstancePtr, 57, 0);
sleep(1);
}
return 0;
}

3.工程結構為:
這裡寫圖片描述

4.CPU1的BSP SETTING中新增 -DUSE_AMP=1
這裡寫圖片描述

5.DDR空間分配
通過修改lscript.ld檔案中的內容,可以改變在儲存器中的執行位置,
因為ELF檔案是載入到DDR中執行的,所以兩個DDR地址不能重合
CPU0:
這裡寫圖片描述
CPU1:
這裡寫圖片描述

6.執行debug
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
兩個CPU都執行起來了,且不相互干擾

7.固化到SD卡中啟動
再建立一個FSBL的工程,在FSBL的src中找到main.c檔案開啟,在裡面新增下面一段程式碼,用於啟動CPU1:

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0
#define CPU1STARTMEM 0x20000000
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
}

前面新增的是CPU1的啟動函式,再找到Load boot image的位置,將CPU1的啟動函式,放置於此位置,改動後的程式碼段如下:

    /*
     * Load boot image
     */
    HandoffAddress = LoadBootImage();

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

這裡寫圖片描述
將上述檔案合併為BIN檔案,並放入SD卡中,ZYNQ啟動模式要為SD啟動,正常情況下將正常工作
注—-若是沒出現正常的現象,則可能是:
1>SD卡的bank電壓及引腳速度選擇錯誤
2>CPU0和CPU1的DDR地址衝突
3>未在FSBL的main.c中加入StartCpu1函式

那麼,雙裸核實驗到此結束

分界線:下面是linux+裸核的實驗,但是CPU1只能短暫工作,即實驗暫時失敗,之後有需要再研究,下面是失敗案例,不要看

雙核分別跑不同的系統

接下來,將在已有的雙核基礎上,實現雙核的linux+裸核工作
CPU0的linux系統將通過petalinux方式移植,CPU1則按照上述的方式照舊
linux具體的移植方式參考:petalinux方式移植linux

硬體上:

在之前的硬體基礎上,新增TTC:
這裡寫圖片描述
重新生成的PS核:
這裡寫圖片描述
更新輸出檔案後,重新綜合、實現、生成bit檔案、匯出硬體,上述工作完成後,可以在/(工程資料夾)/(工程名).sdk這個資料夾下找到.hdf字尾的檔案,待用

開啟linux虛擬機器:

在普通使用者(非超級使用者)模式下:

 #工作目錄
  cd PRO
 #定位編譯鏈
  source /home/hlf/mnt/petalinux/settings.sh
 #建立工程並命名
  petalinux-create --type project --template zynq --name h2_amp
 #進入工程目錄
  cd h2_amp
 #將.hdf檔案拷到資料夾中,並引用硬體描述檔案,遇到配置介面做如下修改後,直接save並exit,等待預設配置
  petalinux-config --get-hw-description=/home/hlf/PRO/h2_amp

Subsystem AUTO Hardware Settings —>
Memory Settings —>
這裡寫圖片描述

 #獲取資料夾許可權(工程資料夾和petalinux的安裝資料夾),否則編譯的時候,會發生錯誤
  sudo chmod -R 777 /home/hlf
 #編譯u-boot,直接save為u-boot.config,並exit
  petalinux-config -c u-boot
 #編譯kernel,操作同上(save為kernel.config)
  petalinux-config -c kernel
 #編譯rootfs,操作同上(save為預設即可)
  petalinux-config -c rootfs

裝置樹配置:在工程資料夾下,Ctr+F搜尋.dts就可以找到相關檔案
這裡寫圖片描述
開啟裝置樹檔案,修改DDR地址,還是注意與petalinux-config時的設定值一致,不要和CPU1的DDR地址重疊
這裡寫圖片描述

 #一切就緒後,編譯工程
  petalinux-build

編譯完成後:進入(工程目錄)/image/linux目錄,將u-boot.elf和image.ub檔案拷貝出來
開啟SDK:新建CPU1的工程,和之前例子裡的配置相同(主要注意修改BSP和DDR地址),然後新建一個FSBL的工程,其步驟也是和之前一樣的(新增CPU1的啟動函式),然後按照順序FSBL.elf — xxx.bit — u-boot.elf — CPU1_APP.elf 的順序製作BOOT.bin檔案,將BOOT.bin和image.ub拷貝到SD卡中,開機

#現象:linux系統正常執行,但是流水燈正常執行一段時間後停止執行,卡在某一個燈,可能是linux的執行影響了CPU1的工作