【ZYNQ入门】第三篇、双核AMP运行模式程序开发

目录

第一部分、基础知识

1、多核CPU三种主要运行模式

2、ZYNQ内部FSBL涉及到的启动过程

2.1、BootRom是啥?

2.2、FSBL是啥?

2.3、ARM与cortex的关系

2.4、本次实验的启动流程

第二部分、FSBL环境配置过程

1、vivado配置硬件

2、SDK新建FSBL配置CPU1程序的启动地址

3、CPU0的工程创建及程序编写

4、CPU1的工程创建及程序编写

5、BOOT.bin文件的生成办法

6、仿真的办法

7、核间中断的方式

第三部分、总结


第一部分、基础知识

        完成两件事,介绍了ZYNQAMP模式的搭建方法以及生成BOOT.bin文件的办法。

1、多核CPU三种主要运行模式

  • AMP(非对称多进程):多个核心相对独立的运行不同的任务,每个核心可能运行不同的操作系统或裸机程序,但是有一个主要核心,用来控制整个系统以及其它从核心的运行
  • SMP(对称多进程)一个操作系统同等的管理各个内核,例如 windows,linux操作系统。
  • BMP(受约束多进程):与 SMP 类似,但开发者可以指定将某个任务仅在某个指定内核上执行。

        默认情况下, 裸机程序 ZYNQ 仅运行一个 CPU,这里主要讲解 AMP 模式下,两个 CPU 同时运行的裸机程序开发方法。

2、ZYNQ内部FSBL涉及到的启动过程

        ARM上电后执行BootROM,发现有合法镜像(BOOT.BIN)后判断是否要在FLASH中执行。若没有合法镜像则到下一个32K的偏移处寻找镜像。如果不XIP,则将FSBL载入到OCM中执行(因为此时是不能使用DDR的),之后开始执行FSBL。

        关于XIP技术:利用XIP技术就不用把代码读到RAM中了,NOR FLASH支持XIP技术与Flash博客园

        更多知识参考博客:   ZYNQ_FSBL学习-CSDN博客 (下图来源于这篇博客

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第1张图片

2.1、BootRom是啥?

        BootRom可翻译为启动代码zynq内部的BootROM存储有一段在CPU上电后/复位后固定执行的代码,这段代码用来配置一个ARM CPU和一些必要外设,从而能从一个启动设备中获取FSBL(first stage boot loader)并执行。

        BootROM是一个ROM,不可写,PL的配置不是通过BootROM实现的。BootROM不能使用DDR和SCU,因为它们还没有初始化。

2.2、FSBL是啥?

        FSBL通常存储在FLASH中(U盘、SD卡、TF卡、SSD固态硬盘都是以FLASH闪存颗粒为介质的一类存储器),BootROM从选定的FLASH中拷贝FSBL到片上存储器OCM中执行。

2.3、ARM与cortex的关系


参考文章:到底什么是Cortex、ARMv8、arm架构、ARM指令集、soc?知乎 (zhihu.com)

  • ARM公司的名字,叫ARM:Advanced RISC Machines;
  • ARM前身Acorn公司设计的第一款微处理器,叫ARM:Acorn RISC Machine;
  • ARM处理器名字: 以前叫ARM9、ARM11, 新的命名规则改以Cortex命名,分别是Cortex-A,Cortex-R,Cortex-M; 这三个字母A、R、M
  • ARM指令集,就是ARM架构,比如ARMv8,每个处理器都需要依赖一定的ARM架构来设计;
  • SOC:各大厂商买来ARM的授权,得到ARM处理器的源代码,而后自己搞一些外围设备的IP(或者买或者自己设计),组成一个SOC,比如三星的Exynos 4412,华为的麒麟990。

2.4、本次实验的启动流程

        第一步、ARM上电后执行BootROM,从SD卡发现有合法镜像(BOOT.BIN文件,需要提前拷贝到SD卡中

1、Bin 文件是经过压缩的可执行文件,去掉ELF格式的东西。是直接的内存映像的表示。在系统没有加载操作系统的时候可以执行。

2、elf文件(executable  and   link   format)文件里面包含了符号表,汇编等。

3、BIN文件是将elf文件中的代码段,数据段,还有一些自定义的段抽取出来做成的一个内存的镜像。

        第二步、再将FSBL载入到OCM中执行,load boot image。(将FSBL载入到OCM的这个过程中没有使用cache,因为如果用到cache,CPU1不能及时读到OCM的内容,从而出现问题。缓存一致性

        第三步、FSBL在OCM中运行,根据启动模式的选择,FSBL从FLASH中复制启动镜像的其他部分。如果有bitstream,那么就加载到FPGA中如果有elf应用程序存在,那么就加载到DDR中并将执行权限移交给它

第二部分、FSBL环境配置过程

        实现基本的CPU1和CPU0交互打印信息。

        注意:FSBL工程的主要目的就用用来生成BOOT镜像文件。

1、vivado配置硬件

        不同器件配置不同,ZYNQ7020的bank0为LVCMOS3.3V和bank1为LVCOM1.8V。

        需要注意:后面如果出现SD下载bin文件后,程序无法启动,很有可能是SD卡模块的工作电压不对,也就是Bank0和Bank1的电压配置错误。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第2张图片

创建顶层文件,再生成bit流文件

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第3张图片

2、SDK新建FSBL配置CPU1程序的启动地址

第一步、fsbl工程的处理器选择cpu0,因为AMP模式需要一个主要的核心来控制系统的运行

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第4张图片

第二步、选择zynq FSBL工程模板

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第5张图片

第三步、修改zynq FSBL工程模板

注意:这段代码尽量加在main函数的上方,这样调用的就不需要去声明,比较方便。

        下面的代码中CPU1STARTADR表示的是cpu1的开始地址,这个是固定的,由厂家决定的。然后CPU1STARTMEM表示的是CPU1程序开始的地址(一般是用户分配给CPU1的DDR内存的基地址的),CPU1STARTMEM是可以根据ddr的地址,看情况给的,也就是由用户设置的,可以改变的。

//增加的代码
/*****************************配置cpu1的启动地址代码*******************************/
//更改CPU1应用程序的启动地址
#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0//应用程序地址
#define CPU1STARTMEM 0x2000000
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
}

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第6张图片

第四步、调用上面的函数,调用位置为580-600行,注释为load boot image(启动引导镜像文件)

为什么是这里?

        因为只有在镜像文件加载完成后,才能让cpu0去触发cpu1,让cpu1去加载控制程序。

        如果在这之前就去调用该函数,DDR里面都还没有镜像文件,没有程序,cpu1就跑不起来。

什么是镜像文件?

        所谓镜像文件其实和rar ZIP压缩包类似,它将特定的一系列文件按照一定的格式制作成单一的文件。这里可以包含引导文件,系统文件等。

        .bin就是一种常见的镜像文件的后缀。bin是binary的缩写,二进制文件。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第7张图片

第五步、ctrl + s保存,ctrl + b编译

        尽量编译一次,避免后面调试的时候出现文件不全的问题。

3、CPU0的工程创建及程序编写

第一步、再新建一个cpu0的工程。处理器一定要选择cpu0

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第8张图片

第二步、为了方便,选择hellow world模板。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第9张图片

第三步、修改.c文件的名称为main.c

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第10张图片

第四步、修改main.c文件如下

#include 
#include "platform.h"
#include "xil_printf.h"

//将内存中指向0xFFFF0000地址的指针进行解引用,volatile关键词是防止这个地址的变量被程序优化掉,
//使这个地址内的存的变量更加稳定,地址必须在共享内存范围
#define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000))


int main()
{
    COMM_VAL=0;
        //Disable cache on OCM
        Xil_SetTlbAttributes(0xFFFF0000,0x14de2);//关闭cache
        while(1)
        {
        print("Hello World cpu0 \n\r");
        COMM_VAL = 1;
        while(COMM_VAL == 1)
        {
        }
        }
    return 0;
}

第五步、修改cpu0的代码空间,

注意:这里应该是私有ram存储cpu0运行的程序及产生的一些实时文件,只属于cpu0。因此这里的地址范围不可以和cpu1重复。

MEMORY
{
   ps7_ddr_0 : ORIGIN = 0x100000, LENGTH = 0x1E00000
   ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000
   ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
}

        通过修改lscript.ld文件来修改cpu0的内存大小,后期如果出现栈溢出的问题,就可以来到这里将内存改大一点。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第11张图片

第六步、ctrl + s保存,ctrl + b编译

        尽量编译一次,避免后面调试的时候出现文件不全的问题。

4、CPU1的工程创建及程序编写

第一步、再新建一个cpu1的工程。处理器一定要选择cpu1

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第12张图片

第二步、为了方便,选择hellow world模板。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第13张图片

第三步、修改.c文件的名称为main.c

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第14张图片

第四步、修改main.c文件如下

#include 
#include "platform.h"
#include "xil_printf.h"


#define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000))

int main()
{
    COMM_VAL=0;
        //Disable cache on OCM
        Xil_SetTlbAttributes(0xFFFF0000,0x14de2);//关闭cache
        while(1)
        {
        print("Hello World cpu1 \n\r");
        COMM_VAL = 0;//这里与CPU0不同,cpu0这里拉高,cpu1这里就需要拉低,这样才能让两个cpu交互起来。
        while(COMM_VAL == 0)
        {
        }
        }
    return 0;
}

第五步、修改cpu1的代码空间

        注意:这里应该是私有ram存储cpu1运行的程序及产生的一些实时文件,只属于cpu1。因此这里的地址范围不可以和cpu0重复。

MEMORY
{
   ps7_ddr_0 : ORIGIN = 0x2000000, LENGTH = 0x1F00000
   ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000
   ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
}

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第15张图片

第六步、ctrl + s保存,ctrl + b编译

        尽量编译一次,避免后面调试的时候出现文件不全的问题。

第七步、修改cpu1的bsp代码,将其设置为AMP模式

        注意:如果这里不设置,那么生成的bin文件是无法使用的

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第16张图片

第八步、在原代码上加上 -DUSE_AMP=1

-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -nostartfiles -g -Wall -Wextra -DUSE_AMP=1

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第17张图片

5、BOOT.bin文件的生成办法

第一步、创建镜像文件

        注意:

        1、这里要看你鼠标放在那个文件夹上,如果是bsp文件夹,那么去添加的时候就没有文件。

        2、但是如果想要顺序正确,那么就要把把鼠标先点击app_cpu0这个文件夹,这样生成镜像文件的顺序就是对的(需手动添加cpu1的elf文件),如果放在app_cpu1,那么就是elf bit cpu1,这样cpu1的顺序就提前了

        猜想:对于3核或者更多核,应该也是放在控制核的文件夹上生成bin文件。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第18张图片

第二步、如果默认文件夹,保存bin文件

        注意:如果默认系统的文件夹不新建文件夹,那么系统会默认你选择的那个文件下(我选的是app_cpu0)生成一个bootimage文件夹。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第19张图片

第二步、如果新建文件夹,保存bin文件

        注意:不能是上一次工程的路径,系统会默认是上一次工程的文件夹。

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第20张图片

第三步、添加三个.elf文件,和一个bit流文件。

        注意:一定不能是上一次工程的文件夹

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第21张图片

注意:顺序一定是下面的顺序1、fsbl.elsf,2、.bit,3、cpu0.elsf,4、cpu1.elsf

在app_cpu0下无法调换顺序

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第22张图片

1、amp_fsbl位置

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第23张图片

2、bit文件位置

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第24张图片

 3、app0.elf和app1.elf位置

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第25张图片

第四步、生成镜像文件

注意:bin文件复制到SD卡后用不了的可能问题

        1、SD卡的电平配置错误,或者说BANK0和BANK1的电平不对(√)

        2、四个文件的顺序不对(√)

        3、添加文件时,路径错误,因为系统会默认上一次工程的文件路径(√)

        4、办卡上的SD启动的拨码开关没有拨过去(√)

        5、cpu1没有没有设置为AMP模式,也就是少了 -DUSE_AMP=1这个代码(√)

        6、没有关闭cache

        7、串口选择错误

        8、共享内存的数据越界

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第26张图片

第五步、生成的结果

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第27张图片

6、仿真的办法

        选择cpu0的工程进行仿真

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第28张图片

        勾选cpu1

【ZYNQ入门】第三篇、双核AMP运行模式程序开发_第29张图片

7、核间中断的方式

        关于核间中断的配置代码请参考这篇博客:【ZYNQ入门】第二篇、ZYNQ的中断系统及常用中断初始化程序-CSDN博客

第三部分、总结

        这篇博客是我在学习AMP模式的整理笔记,希望对你有帮助。

你可能感兴趣的:(FPGA的学习之旅,fpga开发,zynq)