2)实验平台:正点原子领航者ZYNQ开拓板3)平台购买地址:https://item.taobao.com/item.htm?&id=6061601087614)全套实验源码+手册+视频下载:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html5)对正点原子FPGA感兴趣的同学可以加群谈论:8767449006)关注正点原子"大众年夜众号,获取最新资料
第十三章双核AMP实验在前面的例程中,实现的都是基于单核CPU的实验,在很多运用处景中,每每只须要利用个中的一个CPU即可实现相应的功能。然而对付繁芜的设计,如多任务处理、并行掌握等,单个CPU将难以胜任。ZYNQ 7000 SOC芯片内部集成了两个独立的Cortex-A9内核处理器,即两个CPU,可以很好的应对各种繁芜的设计。本章我们来学习下基于双核AMP的实验。本章包括以下几个部分:1313.1简介13.2实验任务13.3硬件设计13.4软件设计13.5下载验证13.1简介多核处理器从多核的构造上是否同等,分为两种基本架构:同构多核架构和异构多核架构。同构多核处理器是指系统中的处理器在构造上是相同的;而异构处理器是指系统中的处理器在构造上是不同的,这些处理器可以是通用途理器,也可以是办理某些特定运用的专用硬核。同构多核架构比较于异构多核架构,在硬件和软件设计上较为大略,通用性较高。但在某些特定运用处所下,如异构多核架构专用的硬件加速硬核,异构多核架构的性能会更高。Xilinx的ZYNQ SOC领悟了这两种架构,ZYNQ SOC芯片包含两个独立的Cortex-A9处理器,这两个处理器核在构造上是相同的,同时又包括了可编程的逻辑单元(PL),使得ZYNQ整体系统成为了一个异构多核系统,同时具有较高的通用性和性能。从软件的角度看,多核处理器的运行模式有AMP(非对称多处理)、SMP(对称多处理)和BMP(受约束多处理)三种运行模式。AMP运行模式指多个内核相对独立的运行不同的任务,每个内核相互隔离,可以运行不同的操作系统(OS)或裸机运用程序。SMP运行模式指多个处理器运行一个操作系统,这个操作系统同等的管理多个内核,如PC电脑。BMP运行模式与SMP类似,但开拓者可以指定将某个任务仅在某个指定内核上实行。一样平常来说,SMP为较高等的运用供应统一的OS平台,开拓者在OS之上构建运用时,无需考虑两个内核之间的资源共享和进程间通信。除此之外,对SMP而言存在性能开销,这会对实时性哀求较高的运用,其性能造成较大影响。如PC机电脑的多核处理器一样平常运行在SMP模式,实现的功能较为繁芜,但对实时性的哀求不高。而AMP的运行模式基本没有开销问题,在运行裸机运用程序时,乃至完备没有开销,比较适宜实时性哀求较高的运用,但须要精心定制的软件设计来实现处理器资源共享和处理器间通信。如电力掌握保护设备常日须要与人机接口实现繁芜的通信和高实时性的打算能力,一样平常采取AMP运行模式,一个处理器运行Linux操作系统,另一个处理器运行裸机运用程序,从而兼顾了电力系统掌握设备须要的繁芜功能和实时性。AMP和SMP运行模式的框图如图 13.1.1所示。
图 13.1.1 AMP与SMP运行模式的框图
AMP运行模式给开拓者供应了一个与传统单核CPU系统相类似的运行环境,使得开拓者已有的履历和知识可以连续加以利用;同时,也为程序的移植供应了很大的便利性。本次试验采取的是双核AMP的运行模式,两个CPU分别运行不同的裸机运用程序。ZYNQ SOC供应的两个Cortex-A9处理器,都具有各自私有的资源,同时也有一些共享的资源。私有资源有L1指令缓存、L1数据缓存、私有定时器等。共享的资源有L2 Cache、DDR存储器、外设和OCM(On Chip Memory)等。在AMP运行模式下,这两个处理器彼此隔离、分别运行。但在访问共享资源或者外设时,要把稳避免冲突,否则程序在运行时可能会涌现问题。我们可以通过类似互斥的办法来实现裸机情形下大略的双核利用,在ZYNQ系统中,可以利用软件产生中断(SGI,Software Generated Interrupts)来避免访问的冲突。ZYNQ系统中的每个CPU都能用SGI来中断自己、另一个CPU或同时中断两个CPU。向软件产生的中断寄存器(ICDSGIR)写入中断编号并指向目标CPU,就产生了一个SGI。每个CPU各自有一组SGI寄存器,可以产生16个软件产生中断中的一个或多个。图 13.1.2列出了SGI的中断ID号,范围是0~15。
图 13.1.2 软件中断
SGI可以触发CPU产生中断,但是如果想要通报数据的话,须要利用共享的内存实现数据的交互。共享内存指CPU0和CPU1在内存中约定一块地址及长度已知的内存区域,两个CPU通过读写共享内存中的数据来实现相互通信,而利用CPU产生的软件中断可以避免对共享内存的同时访问。ZYNQ中的OCM共有256KB,分为4个64KB,而外置的DDR3存储器一样平常存储空间较大。当两个CPU须要进行大量数据交互的时候,可以利用DDR3存储器作为共享内存;而当交互的数据较少时,既可以利用OCM作为共享内存,也可以利用DDR3存储器作为共享内存。值得一提的是,当交互的数据量较少时,OCM作为共享内存有着独特的上风,与DDR内存比较,OCM供应了非常高的性能和来自两个处理器的低延迟访问。须要把稳的是,无论是OCM还是DDR3存储器作为共享内存,在访问之前,须要禁止存储空间的Cache(缓存)功能,这样CPU能够及时读到该地址内存中变革的数据,以避免两个CPU访问共享内存的同等性问题。通过Xil_SetTlbAttributes(INTPTR Addr, u32 attrib)函数禁用Cache属性,第一个参数为共享内存的基地址,第二个参数为设置内存的参数,包括是否禁用Cache等。Xilinx官方供应了两个双核AMP的运用文档,“XAPP1078” 是基于两个Linux操作系统的双核AMP运用文档,“XAPP1079”是基于两个裸机运用程序的双核AMP运用文档,感兴趣的朋友可以参考下。13.2实验任务本章的实验任务是通过领航者ZYNQ开拓板完成双核AMP的实验。CPU0吸收串口的数据,并写入OCM中,然后利用软件产生中断触发CPU1;CPU1吸收到中断后,根据从OCM中读出的数据掌握呼吸灯的频率,并在掌握结束后触发CPU0中断,实现了双核CPU通信的功能。13.3硬件设计根据实验任务我们可以画出本次实验的系统框图,如下图所示:
图 13.3.1 系统框图
本次试验的两个CPU都会利用到串口,并且CPU0会对OCM进行写操作,CPU1对OCM进行读操作,这就哀求共享外设和内存不能同时访问,以免产生冲突。我们可以利用软件产生中断(SGI)的办法来规避冲突。在初始状态下,CPU0先利用串口,在吸收到用户数据后,将数据写入OCM中,并产生中断来触发CPU1中断,此时CPU0不在访问串口和OCM;CPU1触发中断后,开始访问串口和OCM,先从OCM中读出数据,通过串口来输出信息,并产生中断触发CPU0中断,之后不再访问串口和OCM;CPU0吸收到CPU1的中断后,此时可以重新通过串口来吸收用户输入的数据,从而避免了共享外设和内存的同时访问。首先创建一个Vivado工程,工程名为“dual_core_amp”。本次试验的硬件环境搭建和“自定义IP核-呼吸灯试验”基本相同,只不过为了将程序固化在SD卡或者Quad SPI Flash中(把稳BANK1的IO电平须要改成LVCMOS 1.8V),本次试验在ZYNQ处理系统中,添加了SD卡掌握器和Quad SPI Flash掌握器(图 5.3.1的框图中未画出)。终极ZYNQ系统硬件搭建的框图如下图所示:
图 13.3.2 ZYNQ系统硬件框图
双核AMP的实验在硬件环境搭建上和单核CPU的利用是同等的,仅在软件设计上存在差异。13.4软件设计在硬件设计的末了,我们打开了SDK开拓环境。首先创建CPU0的运用工程,在菜单栏中选择File->New->Application Project,新建一个SDK运用工程。工程名命名为cpu0_uart,处理器选择ps7_cortexa9_0,如下图所示:
图 13.4.1 创建CPU0运用工程
点击“NEXT”,然后选择“Empty Application”,点击“Finish”按钮完成SDK运用工程的创建。接下来双击lscript.ld(位于cpu0_uart→src下),设置CPU0的访问空间。由于ZYNQ-7020核心板和ZYNQ-7010核心板的DDR3存储空间不同,因此这里设置有所差异。如果大家利用的是ZYNQ-7020核心板,DDR3的存储空间为1GByte,这里将CPU0的访问空间大小设置成约为DDR3存储空间的一半,即存储空间大小为0x1FF00000(Byte),如下图所示。
图 13.4.2 ZYNQ-7020核心板设置CPU0的DDR3访问空间
如果大家利用的是ZYNQ-7010核心板,DDR3的存储空间为512MByte,这里将CPU0的访问空间大小设置成约为DDR3存储空间的一半,即存储空间大小为0xFF00000(Byte),如下图所示。
图 13.4.3 ZYNQ-7010核心板设置CPU0的DDR3访问空间
把稳图中红框标注的地方左侧为基地址,右侧为存储空间大小,修正完成后,按下“Ctrl”+“S”保存。其余图 13.4.2和图 13.4.3中的ps7_ram_0和ps_ram_1为OCM共享内存的基地址。接下来创建CPU1的运用工程。在菜单栏中选择File->New->Application Project,新建一个SDK运用工程。工程名命名为cpu1_led,处理器选择ps7_cortexa9_1,如下图所示:
图 13.4.4 创建CPU1运用工程
点击“NEXT”,然后选择“Empty Application”,点击“Finish”按钮完成SDK运用工程的创建。接下来双击lscript.ld(位于cpu1_led→src下),设置CPU1的访问空间。由于ZYNQ-7020核心板和ZYNQ-7010核心板的DDR3存储空间不同,因此这里设置同样有所差异。如果大家利用的是ZYNQ-7020核心板,这里将地址设置为DDR3存储器的另一半寻址空间,即存储空间大小为0x1FFFFFFF(Byte),如图 13.4.5所示,即基地址为0x02000000,存储空间大小为0x1FFFFFFF。
图 13.4.5 ZYNQ-7020核心板设置CPU1的DDR3访问空间
如果大家利用的是ZYNQ-7010核心板,这里同样将地址设置为DDR3存储器的另一半寻址空间,即存储空间大小为0xFFFFFFF(Byte),如图 13.4.6所示,即基地址为0x01000000,存储空间大小为0xFFFFFFF。
图 13.4.6 ZYNQ-7010核心板设置CPU1的DDR3访问空间
修正完成后,按下“Ctrl”+“S”保存。须要把稳的是,两个CPU设置的DDR3的地址不能重合,否则程序在运行时会涌现非常。接下来还须要对CPU1的板级支持包做额外的设置,才能使双核同时事情。右击cpu1_led_bsp,选择Board Support Package Settings。
图 13.4.7 设置CPU1板级支持包
在弹出的界面中,点击ps7_cortexa9_1,在extra_compiler_flags一栏的Value下,补充“-DUSE_AMP=1”,设置完成后点击“OK”按钮,如下图所示:
图 13.4.8 设置双核启动
接下来编写CPU0的用户代码。在cpu0_uart/src目录上右键,选择New->Source File,在弹出的对话框中Source file一栏我们输入文件名“cpu0_uart.c” ,然后点击“Finish”。我们在新建的cpu0_uart.c文件中输入本次实验的代码。代码的主体部分如下所示:
1 #include "xparameters.h"2 #include "xscugic.h"3 #include "xil_printf.h"4 #include "xil_exception.h"5 #include "xil_mmu.h"6 #include "stdio.h"7 8 //宏定义9 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断ID10 #define SHARE_BASE 0xffff0000 //共享OCM首地址11 #define CPU1_START_ADDR 0xfffffff0 //CPU1开始地址12 #define CPU1_START_MEM 0x10000000 //CPU1程序开始地址13 14 #define SOFT_INTR_ID_TO_CPU0 0 //软件中断号 0 ,范围:0~1515 #define SOFT_INTR_ID_TO_CPU1 1 //软件中断号 1 ,范围:0~1516 #define CPU1_ID 2 //CPU1 ID,0bxxxxxx1x指向CPU117 //"SEV"指令唤醒CPU1并跳转至相应的程序18 #define sev() __asm__("sev")19 20 //函数声明21 void start_cpu1();22 void cpu0_intr_init(XScuGic intc_ptr);23 void soft_intr_handler(void CallbackRef);24 25 //全局变量26 XScuGic Intc; //中断掌握器驱动程序实例27 int rec_freq_flag = 0; //吸收到呼吸灯频率设置的标志28 int freq_gear; //频率档位29 30 //CPU0 main函数31 int main()32 {33 //S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b034 Xil_SetTlbAttributes(SHARE_BASE,0x14de2); //禁用OCM的Cache属性35 36 //启动CPU137 start_cpu1();38 //CPU0中断初始化39 cpu0_intr_init(&Intc);40 while(1){41 if(rec_freq_flag == 0){42 xil_printf("This is CPU0,Please input the numbers 1~5 to change "43 "breath led frequency\r\n");44 scanf("%d",&freq_gear);45 if(freq_gear >= 1 && freq_gear <=5){46 xil_printf("You input number is %d\r\n",freq_gear);47 //向共享的地址中写入输入的数据48 Xil_Out8(SHARE_BASE,freq_gear);49 //给CPU1触发中断50 XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU1,CPU1_ID);51 rec_freq_flag = 1;52 }53 else{54 xil_printf("Error,The number range is 1~5\r\n");55 xil_printf("\r\n");56 }57 }58 }59 return 0 ;60 }在主函数中,首先通过Xil_SetTlbAttributes()函数禁用Cache缓存,以掩护两个CPU访问OCM同等性的问题。个中输入参数SHARE_BASE为共享内存的基地址,这个基地址在lscript.ld可以查找到,即ps7_ram0的基地址或者ps_ram_1的基地址,本次实验利用ps7_ram_1作为两个CPU通信的共享内存。然后通过start_cpu1()函数启动CPU1,须要把稳的是,如果只是通过JTAG模式下载程序的话,是可以不编写这个启动函数,这个函数仅在固化程序的时候起浸染。接下来通过cpu0_intr_init()函数对CPU0的中断进行初始化,以相应CPU1的中断。末了是一个while(1)的无限循环。首先判断rec_freq_flag(吸收到呼吸灯频率设置的标志)的值是否为0,如果即是0,此时打印字符来提示用户输入数据,输入值的范围为1~5,输入的值越大,呼吸灯的呼吸频率就越高。当用户输入精确的值之后,打印用户输入的值,并通过Xil_Out8()函数将数值写入OCM存储器中。然后通过XScuGic_SoftwareIntr()函数向CPU0触发中断。个中函数第二参数为软件中断号,第三个参数为CPU1的ID。由UG585文档可以查询到,0bxxxxxxx1 指向CPU0,0bxxxxxx1x指向CPU1,程序中将CPU1的ID设置为2。触发CPU1中断后,将rec_freq_flag(吸收到呼吸灯频率设置的标志)设置为1,while循环停滞吸收用户输入的数据。如果用户输入的值不是1~5之间的数字,则返回缺点,用户重新输入数字。我们在程序中,除了main()函数之外,其余还编写了三个函数:start_cpu1()、cpu0_intr_init()和soft_intr_handler()。代码如下所示:
62 //启动CPU1,用于固化程序63 void start_cpu1()64 {65 //向 CPU1_START_ADDR(0Xffffffff0)地址写入 CPU1 的访问内存基地址66 Xil_Out32(CPU1_START_ADDR, CPU1_START_MEM);67 dmb(); //等待内存写入完成68 sev(); //通过"SEV"指令唤醒CPU1并跳转至相应的程序69 }70 71 //CPU0中断初始化72 void cpu0_intr_init(XScuGic intc_ptr)73 {74 //初始化中断掌握器75 XScuGic_Config intc_cfg_ptr;76 intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);77 XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,78 intc_cfg_ptr->CpuBaseAddress);79 //设置并打开中断非常处理功能80 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,81 (Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);82 Xil_ExceptionEnable();83 84 XScuGic_Connect(intc_ptr, SOFT_INTR_ID_TO_CPU0,85 (Xil_ExceptionHandler)soft_intr_handler, (void )intc_ptr);86 87 XScuGic_Enable(intc_ptr, SOFT_INTR_ID_TO_CPU0); //CPU0软件中断88 }89 90 //软件中断函数91 void soft_intr_handler(void CallbackRef)92 {93 xil_printf("This is CPU0,Soft Interrupt from CPU1\r\n");94 xil_printf("\r\n");95 rec_freq_flag = 0;96 }代码中第接下来通过start_cpu1()函数启动CPU1,启动函数的代码如代码中第62至第69行代码所示。须要把稳的是,如果只是通过JTAG模式下载程序的话,可以不编写这个启动函数,这个函数仅在固化程序的时候起浸染。启动CPU1的方法在UG585文档中有着详细的先容,即通过Xil_Out32()函数向CPU1的开始地址写入CPU1的DDR3内存地址,等待内存写入完成,然后通过“SEV”指令唤醒CPU1并跳转至相应的程序,UG585文档中启动CPU1的描述如下图所示:
图 13.4.9 启动CPU1cpu0_intr_init()函数用户对CPU0的中断进行初始化。程序将中断函数设置为soft_intr_handler(),软件中断号的范围是0~15之间,这里设置为0。而soft_intr_handler()函数为CPU1触发CPU0中断的软件中断函数,当CPU0进入中断后,打印字符并将rec_freq_flag设置为0,以重新吸收用户输入的呼吸灯频率。程序设计完成后,按快捷键Ctrl+S保存main.c文件,工具会自动进行编译。编译完成后掌握台(Console)中会涌现提示信息“Build Finished”,同时在运用工程的Binaries目录下可以看到天生的elf文件。接下来编写CPU1的用户代码。在cpu1_led/src目录上右键,选择New->Source File,在弹出的对话框中Source file一栏我们输入文件名“cpu1_led.c”,然后点击“Finish”。我们在新建的cpu1_led.c文件中输入本次实验的代码。代码的主体部分如下所示:
1 #include "xparameters.h"2 #include "xscugic.h"3 #include "xil_printf.h"4 #include "xil_exception.h"5 #include "xil_mmu.h"6 #include "stdio.h"7 #include "breath_led_ip.h"8 9 //宏定义10 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断ID11 #define SHARE_BASE 0xffff0000 //共享OCM首地址12 #define SOFT_INTR_ID_TO_CPU0 0 //软件中断号 0 ,范围:0~1513 #define SOFT_INTR_ID_TO_CPU1 1 //软件中断号 1 ,范围:0~1514 #define CPU0_ID 1 //CPU1 ID,0bxxxxxxx1指向CPU015 16 #define LED_IP_BASEADDR XPAR_BREATH_LED_IP_0_S0_AXI_BASEADDR //LED IP基地址17 #define LED_IP_REG0 BREATH_LED_IP_S0_AXI_SLV_REG0_OFFSET //LED IP寄存器地址018 #define LED_IP_REG1 BREATH_LED_IP_S0_AXI_SLV_REG1_OFFSET //LED IP寄存器地址119 20 //函数声明21 void cpu1_intr_init(XScuGic intc_ptr);22 void soft_intr_handler(void CallbackRef);23 24 //全局变量25 XScuGic Intc; //中断掌握器驱动程序实例26 int soft_intr_flag = 0; //软件中断的标志27 int freq_gear; //频率档位28 29 //CPU1 main函数30 int main()31 {32 int freq_step = 0;33 //S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b034 Xil_SetTlbAttributes(SHARE_BASE,0x14de2); //禁用OCM的Cache属性35 36 //CPU1中断初始化37 cpu1_intr_init(&Intc);38 //打开呼吸灯39 BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG0, 1);40 while(1){41 if(soft_intr_flag){42 freq_gear = Xil_In8(SHARE_BASE); //从共享OCM中读出数据43 xil_printf("CUP1 Received data is %d\r\n",freq_gear) ;44 switch(freq_gear){45 case 1 : freq_step = 20;break;46 case 2 : freq_step = 50;break;47 case 3 : freq_step = 100;break;48 case 4 : freq_step = 200;break;49 case 5 : freq_step = 500;break;50 default : freq_step = 50;break;51 }52 //设置呼吸灯频率,最高位为1,设置有效53 BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR,LED_IP_REG1,(0x80000000|freq_step));54 //给给CPU0触发中断55 XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU0,CPU0_ID);56 soft_intr_flag = 0;57 }58 }59 return 0 ;60 }在主函数中,同样是先通过Xil_SetTlbAttributes()函数禁用Cache缓存,以掩护两个CPU访问OCM同等性的问题。然后通过cpu1_intr_init()函数用户对CPU1的中断进行初始化。中断初始化完成后,通过LED_IP_mWriteReg()函数打开呼吸灯,此时呼吸灯的频率因此默认的频率进行渐变的。接下来同样是一个无限循环while(1),实现了根据从OCM读取到的值,来掌握呼吸灯的频率。当吸收到CPU0的软件中断后(soft_intr_flag的值为1),从OCM读取数据的函数为Xil_In8(),根据读取到的值,通过LED_IP_mWriteReg()函数设置输出呼吸灯的频率。这里将呼吸灯的频率共分为5档,用户输入的值越大,呼吸灯的频率步长越大,呼吸灯的呼吸频率就越大。末了通过XScuGic_SoftwareIntr()函数给CPU0触发中断,并设置soft_intr_flag(软件中断的标志)为0。我们在程序中,除了main()函数之外,其余还编写了两个函数:cpu1_intr_init()和soft_intr_handler()。代码如下所示:
62 //CPU1中断初始化63 void cpu1_intr_init(XScuGic intc_ptr)64 {65 //初始化中断掌握器66 XScuGic_Config intc_cfg_ptr;67 intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);68 XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,69 intc_cfg_ptr->CpuBaseAddress);70 //设置并打开中断非常处理功能71 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,72 (Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);73 Xil_ExceptionEnable();74 75 XScuGic_Connect(intc_ptr, SOFT_INTR_ID_TO_CPU1,76 (Xil_ExceptionHandler)soft_intr_handler, (void )intc_ptr);77 78 XScuGic_Enable(intc_ptr, SOFT_INTR_ID_TO_CPU1); //CPU1软件中断79 }80 81 //软件中断函数82 void soft_intr_handler(void CallbackRef)83 {84 xil_printf("This is CUP1,Soft Interrupt from CPU0\r\n") ;85 soft_intr_flag = 1;86 }cpu1_intr_init()函数对CPU1的中断进行初始化。程序将中断函数设置为soft_intr_handler(),软件中断号的范围是0~15之间,这里设置为0。soft_intr_handler()函数为CPU0触发CPU1中断的软件中断函数,当CPU1进入中断后,打印字符并将soft_intr_flag的值设置为1,从而在main()函数中设置呼吸灯的频率。程序设计完成后,按快捷键Ctrl+S保存main.c文件,工具会自动进行编译。编译完成后掌握台(Console)中会涌现提示信息“Build Finished”,同时在运用工程的Binaries目录下可以看到天生的elf文件。13.5下载验证首先我们将下载器与领航者底板上的JTAG接口连接,下载器其余一端与电脑连接。然后利用Mini USB连接线将开拓板左侧的USB_UART接口与电脑连接,用于串口通信。末了连接开拓板的电源,并打开电源开关。在SDK软件下方的SDK Terminal窗口中点击右上角的加号设置并连接串口。右击运用程序cpu0_uart(或者cpu1_led),选择Run As→Run Configurations,在弹出的界面中双击Xilinx C/C++ application(System Debug),即对下载的选项进行设置。在Target Setup选项页中选中“Reset entire system”,此时“Program FPGA”也会自动选中,如下图所示:
图 13.5.1 “Target Setup”设置
将选项也切换至“Application”,把“ps_cortexa9_1”也选中,如下图所示:
图 13.5.2 “Application”设置
设置完成后,点击“Run”按钮开始运行。此时ZYNQ核心板上的LED1(PL LED)灯开始呈现呼吸灯的效果,如图 13.5.3所示:
图 13.5.3 开拓板实验征象
与此同时,在SDK Terminal窗口中可以看到CPU1打印的字符。此时我们可以在SDK Terminal窗口中输入“5”,来改变LED灯的呼吸频率,如下图所示:
图 13.5.4 设置呼吸灯的频率
从SDK Terminal窗口中可以看到CPU1吸收到了CPU0的数据,数值为5,如下图所示:
图 13.5.5 SDK Terminal窗口打印实验结果
与此同时,不雅观察ZYNQ核心板上的LED1灯,其呼吸频率变快,解释双核AMP实验在ZYNQ FPGA开拓板上验证成功。把稳:如果SDK Terminal窗口打印信息缺点或者未打印信息,请检讨cpu0_uart和cpu1_led运用程序的DDR3基地址和存储空间大小的设置是否精确。在实验的末了,我们再来向大家先容双核AMP实验的程序固化方法。由于本次实验会有两个运用程序的板级支持包,在建立FSBL的时候,大家可以选择创建一个新的BSP或者选择已经存在的cpu0_uart_bsp(不可以选择cpu1_led_bsp,CPU1的程序是由CPU0唤醒的)。其它的操作和单核CPU的实验基本同等,只是在Creat Boot Image时,在末了添加CPU1的elf即可,如下图所示:
图 13.5.6 创建Boot Image
须要把稳的是,文件添加的顺序不能弄错。文件从上到下的顺序分别是FSBL.elf、sys_wrapper.bit、cpu0_uart.elf和cpu1_led.elf。