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 的程序都运行起来了。

双裸核实验到此结束。

 

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