zynq 7000 AMP模式 雙裸核CPU同時運行

本實驗通過學習 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 的程序都運行起來了。

雙裸覈實驗到此結束。

 

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