本實驗通過學習 https://blog.csdn.net/long_fly/article/details/79335025 而來。
從軟件的角度來看,多核處理器的運行模式有三種:
AMP(非對稱多進程):多個核心相對獨立的運行不同的任務,每個核心可能運行不同的操作系統或裸機程序,但是有一個主要核心,用來控制整個系統以及其它從核心
SMP(對稱多進程):一個操作系統同等的管理各個內核,例如PC機
BMP(受約束多進程):與SMP類似,但開發者可以指定將某個任務僅在某個指定內核上執行
默認情況下,ZYNQ僅運行一個CPU,這裏主要研究AMP模式下,兩個CPU同時運行
本實驗在黑金AC7010 上測試運行成功。
zynq 7000 一般有2個cpu ,我們一般都用一個cpu0,本實驗讓2個cpu 都運行起來,cpu0 ,helloworld, cpu1: 流水燈。
本實驗在zynq 7000 SDK下的流水燈實驗 的基礎上完成,vivado 上的操作與那個工程一樣,現在就在sdk下開始我們的實驗。
建立helloworld 工程
建立helloworld 與建立一般的helloworld 工程無異,只是代碼改了一點點如下:
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
int main()
{
init_platform();
int i=0;
while (1)
{
i++;
printf("%d: Hello World!\n\r",i);
sleep(2);
}
cleanup_platform();
return 0;
}
一般的工程只是顯示一個helloworld ,我這裏每隔2秒顯示一次,並且編號+1。
可以先編譯測試運行看看。
建立流水燈工程
也和流水燈工程一樣建立一個名字爲 cpu1-app 的工程,下面圖例工程名爲led ,這裏特別要注意的是processor 要選擇 ps7_cortexa9_1,這是與原來流水燈實驗不同之處。
工程也是一個helloworld.c 修改爲led.c
程序內容也適當修改了,如下:
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h"
#include "sleep.h"
#define MY_IP 0x41200000
int main()
{
u32 Ledwidth;
init_platform();
print("Hello World\n\r");
while (1)
{
for (Ledwidth = 0x0; Ledwidth < 4; Ledwidth++)
{
Xil_Out32(MY_IP,1 << Ledwidth);
printf("led=%x\n\r",1<<Ledwidth);
sleep(1);
}
}
cleanup_platform();
return 0;
}
這裏的MY_IP 地址可能要根據你的情況修改,可以先編譯鏈接排除錯誤。
CPU1的BSP SETTING中添加 -DUSE_AMP=1
點擊cpu1 的bsp下的system.mss,在出現的界面中點擊按鈕 Modify this BSP's settings,在出現的界面中,點擊 ps7_cortexa9_1, 然後在extra_compiler_flags 的value 中添加 -DUSE_AMP=1 ,如下圖:
至於爲什麼,可以看看 ZYNQ雙核AMP開發詳解(USE_AMP -DUSE_AMP=1 含義和作用詳解)
DDR空間分配
通過修改lscript.ld文件中的內容,可以改變在存儲器中的執行位置,因爲ELF文件是加載到DDR中執行的,所以兩個DDR地址不能重合,這個需要修改lscript.ld
CPU0:只是修改size 改爲原來一半。
cpu1: 這個修改Base Address 和Size
Debug 運行2個程序
這個先要設置debug Configure
主菜單 > Run > Debug Configure...,然後點擊Application 如下界面:
在這裏要選擇好cpu0,cpu1運行的工程
然後點擊 Debug
因爲都是stop at main 出現如下debug 界面
2個cpu 都停在main 函數入口。
點擊cpu0 然後Resume 恢復運行,點擊cpu1 然後Resume 恢復運行,2個cpu 都是運行狀態。
現在就可以debug 這2個程序了,選擇一個,然後就控制那個。
在我的運行界面裏,流水燈在流水,顯示界面是
led=1
led=2
108:Hello World!
...
2個cpu 都可以輸出,因爲hello world 是sleep(2)
所以同時運行的時候,helloworld 顯示一行,led 顯示2行。一直這麼交替顯示。
終於有了2個cpu 運行的感覺了。
程序固化
如果你對程序固化不熟悉,請看:zynq 程序固化和啓動,當然那是單個cpu 的程序固化,當我們以那爲基礎。
這就是在硬件vivado 設計中,需要有qspi 和 SD卡的支持,如果只實驗一種,也可只支持一種。
Xilinx >Create boot image,在這個界面裏添加cpu1_app,如下圖:
然後把BOOT.BIN 文件FLASH 或者複製到SD卡,再啓動
發現只有helloworld 在運行, cpu1沒有運行。
原來還需要啓動cpu1的運行,這需要在fsbl 工程裏做修改。
在FSBL的src中找到main.c文件打開,在裏面添加下面一段代碼,用於啓動CPU1。這段代碼放的位置在main 函數前。
#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0
#define CPU1STARTMEM 0x10000000
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*/
保存並編譯,然後再上面方法建立 BOOT.BIN
把BOOT.BIN 寫入FLASH或者複製到SD卡,
復位或者重新上電,看到2個cpu 的程序都運行起來了。
雙裸覈實驗到此結束。