软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! 31.1概述ZYNQ中存在两个独立的ARM核,在很多应用场景中往往只需使用其中的1个核心即可。然而,对于复杂的设计,例如多任务,并行控制、处理等,单个核心将难以胜任。因此,为了尽可能发挥ZYNQ中双ARM核的优势和性能,进行双核应用的开发显得尤为重要。同时,也进一步为Xilinx下一代MPSOC多核异构处理器的使用打下基础。 在ZYNQ中实现双ARM核AMP应用可以参考Xilinx官方的XAPP1078和XAPP1079。在SDK中也有用于双核应用开发的openamp库可以使用。 本例程未使用openamp库,通过自行设计的代码实现了一个简单的双核应用,旨在说明:
31.2基本原理本例程在ARM核的CORE0建立一个TCP Server,CORE0通过TCP Server从外部TCP Client接收数据。当CORE0接收到1个TCP包后,将数据复制到DDR3中的缓存区域内,然后将数据信息(长度、首地址)放入CORE0和CORE1在DDR3的共享内存中。 接着,CORE0通过触发软件中断通知CORE1数据信息已存入共享内存中,CORE1接到中断后从共享内存读出数据信息,并将对应长度的数据复制到缓存区中,然后通过UART将数据输出。当CORE1通过串口完成数据输出后,同样通过触发软件中断通知CORE0数据发送已完成,CORE0接到中断后通过串口打印完成信息,然后开始接收下一个TCP包,重复上述过程。 最后,通过FSBL实现双核的QSPI BOOT。 31.2.1软件中断在UG585的Interrupts 部分7.2.1章节可以找到关于软件中断(SGI)的说明。简而言之,软件中断就是CPU自己产生的中断,可用于触发自身和其他CPU。ZYNQ中共有16个软件中断可以使用,对应的中断号为0~15,如下图所示。通过软件中断可以实现CPU之间的相互通信。本例程使用了编号1和2的软件中断。 31.2.2共享内存通信所谓共享内存就是,CORE0和CORE1在DDR3内存中约定一块地址及长度已知的内存区域。然后,两者之间便可通过这片区域进行数据的传递。 两个核心各自拥有独立的L1 DCache,并且共享同一个L2 DCache,在ZYNQ中存在一个Snoop Control Unit (SCU)用于维护CORE0和CORE1的L1 DCache与L2 DCache之间的一致性,无需用户干预。因此,虽然CORE0和CORE1的共享内存区域位于DDR中,两者之间的数据传递并不需要考虑DCache一致性的维护。但是,为了更好阐明多级存储器结构的特性以及DCache一致性维护的问题,本例程在两核间通过DDR3共享内存进行数据交互时加入了DCache一致性操作,最终达到的效果与不使用DCache一致性操作时相同。 DCache一致性维护的原理为:在多级存储器结构中,CPU通过1级或多级Cache与DDR产生连接,CPU本身不直接访问DDR,而是通过Cache访问DDR。Cache中始终会暂存一小部分(通常是KB~几MB量级)CPU最近访问的DDR某些地址区域中的数据。因此,在应用程序中对DDR进行读或写操作,实际上都是CPU对Cache进行读或写操作。当DDR中某个地址范围内的数据突然被除CPU以外的Master(如DMA)改变时,若此时Cache中保存了这些区域的数据,且这些数据在Cache中状态为有效时,当CPU需要再次读取DDR这片区域的数据时,就不会让Cache去读取DDR中此区域内最新的数据来更新Cache,再从Cache里读取最新的数据,而是直接从Cache中读取原来的旧数据,显然这不是我们所期望的结果。这时,便引入了所谓的Cache一致性问题。 ZYNQ中存在ICache和DCache,ICache用于缓存可执行程序,DCache用于缓存数据。一般情况下,用于保存可执行程序的DDR地址范围不会被除CPU以外的对象访问。因此,一般不存在ICache的一致性问题。而DCache在很多应用中却经常会被除CPU以外的对象访问,所以存在一致性问题。 ZYNQ中维护DCache一致性的方法为:写入方将数据写入DDR对应地址区域后,需将残留在DCache中相应地址范围内的数据全部刷入DDR3中。读取方在从DDR相应地址读取数据之前,需将DCache中DDR相应地址范围内的数据全部设置为invalid,然后CPU会再次通过DCache从DDR3中读取该地址范围内最新的数据。 31.2.3双核BOOT裸机双核BOOT的方法参考自Xilinx的XAPP1079。首先,通过FSBL实现CORE0的BOOT。当CORE0启动进入main函数后,配合FSBL再实现CORE1的启动。 具体原理参考XAPP1079,此处不作赘述。 31.3驱动程序CORE0工程的驱动程序文件位于c_driver文件夹中的core0文件夹中,CORE1工程的驱动程序文件位于c_driver文件夹中的core1文件夹中。需要说明的是,core0和core1的工程在DDR所占用的地址区域进行如下划分:
设计双核应用,两个工程的内存分配是一个关键的前提,程序所占用的DDR空间不能发生重合,应完全分隔开。 31.3.1 CORE0工程31.3.1.1 main函数main函数的完成的功能如下:
31.3.1.2建立TCP Server基于LWIP库在ARM中建立一个TCP Server,IP地址为192.168.1.10,端口号为5010。
见“基于TCP的QSPI Flash bin文件网络烧写”例程。
见“基于TCP的QSPI Flash bin文件网络烧写”例程。 31.3.1.3 初始化软件中断通过software_intr.c中的Init_Software_Intr()函数初始化软件中断,对于CORE0,该函数完成如下功能。
31.3.1.4 启动CORE1通过main.c中的Start_cpu1()函数配合FSBL完成CORE1的启动。Start_cpu1()原理如下:
#define APP_CPU1_ADDR 0x02000000
31.3.1.5 数据写入共享内存CORE0通过TCP协议接收外部TCP Client发送的数据包,并将数据信息写入CORE0和CORE1共享内存中。共享内存首地址定义为: #define SHARED_BASE_ADDR0x08000000 为共享内存区域在shared_mem.h中定义结构体shared region,其中包含了两核间所需交互的数据长度及数据指针。 typedefstruct { u32data_length; u8* dataload; }shared_region; CORE0通过shared_mem.c中的put_data_to_region()函数将所需传递的数据长度及指针存入shared region结构体中。在put_data_to_region函数中调用Xil_DCacheFlushRange函数将DCache中该数据指针所指向内存区域的数据刷入DDR中,进行DCache一致性维护。 CORE0将此结构体放置于共享内存首地址SHARED_BASE_ADDR,CORE1便可以从该地址读取CORE0所需传递的数据信息,从而进一步获取数据。 31.3.1.6 触发软件中断CORE0通过调用shared_mem.c中的Gen_Software_Intr函数触发CORE0到CORE1的软件中断,中断号为1,中断目标CPU设置为CORE1。 31.3.1.7响应软件中断当CORE1向CORE0触发中断号为2的软件中断时,CORE0调用Cpu0_Intr_Hanedler函数响应此中断。然后,CORE0通过串口打印相应信息。 31.3.2 CORE1工程31.3.2.1 main函数main函数的完成的功能如下:
31.3.2.2初始化软件中断通过software_intr.c中的Init_Software_Intr()函数初始化软件中断,对于CORE1,该函数完成如下功能。
31.3.2.3响应软件中断当CORE0向CORE1触发中断号为1的软件中断时,CORE1调用Cpu1_Intr_Hanedler函数响应此中断。然后,CORE1开始从共享内存中读取CORE0所传递的数据。 31.3.2.4共享内存数据读出CORE1从共享内存区域SHARED_BASE_ADD地址中获取CORE0传递的数据信息,通过shared_mem.c中的get_data_from_region()函数将CORE0传递的数据长度及指针读出,并复制到本地缓存中。 在get_data_from_region函数中,在将CORE0传递的数据复制到本地缓存区域之前,调用Xil_DCacheInvalidateRange函数将DCache中该数据指针所指向内存区域的数据设置为invalid,进行DCache一致性维护。 31.3.2.5触发软件中断当CORE1将从共享内存中读取的数据通过串口输出完毕后,CORE1通过调用shared_mem.c中的Gen_Software_Intr函数触发CORE1到CORE0的软件中断,中断号为2,中断目标CPU设置为CORE0。以此通知CORE0,CORE1串口输出数据完成。 31.4工程创建及设置关键步骤创建工程,搭建硬件系统。 Step1:创建硬件工程,添加ZYNQ IP,并配置DDR型号、时钟、串口、网口。 Step2:如下对ZYNQ IP进行修改 最后生成的ZYNQ IP Step3:综合编译,生成bit文件。导出,加载SDK。 SDK中创建工程。 Step4:创建CORE0工程。新建工程tcp_lwip_core0,并修改BPS包,修改见“基于TCP的QSPI Flash bin文件网络烧写”例程。 Step5:创建CORE1工程。新建工程uart_core1,如下所示进行修改。
在CORE1工程的bsp中要增加编译选项“-DUSE_AMP=1”,如下图所示。该编译选项将影响到CORE1工程代码里中断控制器SCUGIC的初始化函数以及Cache操作函数的编译,若不增加该选项,可能会出现CORE0和CORE1中断异常和Cache一致性维护异常。 Step6:对CORE0 和CORE1的 lscript.ld文件重新设置,参考5.3。
31.5工程调试关键步骤Step1 :system debugger里同时添加core0和core1工程文件,如下图所示。 Step2 : Debug时先让CORE0运行。 Step3:连接串口,连接网口。 在SDK中下载程序至ZYNQ中。打开网络调试助手,选择TCP Client方式,输入ARM中定义的TCP Server的IP地址和端口号,然后点击连接按键,建立TCP连接。 此时串口输出信息。 Step4 :再让CORE1运行。 此时串口输出信息。 在网络调试助手中输入任意文字发送,如图所示。 此时串口输出信息。 继续通过网络调试助手发送信息,串口输出如下图所示。 31.6生成BOOT.bin及双核BOOT验证31.6.1 生成BOOT.bin创建FSBL文件。 对main.c文件进行修改,在main.c中增加以下代码
找到Load boot image的位置,把CPU1的启动函数,在此调用:
创建UBOOT.BIN 31.6.2 双核BOOT验证将BOOT.bin文件烧入QSPI flash中,重启开发板。SDK串口终端输出信息,如下图所示。当提示“core1:application start”,代表CORE0和CORE1都已成功启动。 使用网络调试助手进行TCP连接并发送数据,串口输出如下图所示。此时,验证了双核BOOT后,CORE0和CORE1均运行正常。 |
XILINX 官网|站点统计|Archiver|手机版|米联客品牌主页|UISRC工程师开源站 ( 苏ICP备19046771号-2 )
GMT+8, 2025-4-3 14:44 , Processed in 0.295117 second(s), 86 queries .