ZEDBOARD运行AMP总结

本文详细介绍了在ZYNQ AMP模式下实现双核通信及内存管理的方法,包括修改FSBL支持多ELF加载,使用openAMP在Linux下启动次核,以及如何在SDK中配置内存映射防止地址重叠,确保两核独立运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(1)参考XAPP1078,修改FSBL,加入DUMMY。
修改FSBL,支持load多个elf,直到遇到标志LOAD地址后,停止load,并返回。之后运行SSBL。

(2)参考UG1186,使用openAMP。
在linux中支持RPMSG,使得linux在CPU0上面启动后,由linux加载CPU1所需要的elf,并由linux启动CPU1。

(3)参考XAPP1079,下载repo,并放置到VIVADO SDK 2017.4中。
新建FSBL时,选择FSBL for AMP。
需要分别建立两个CPU的APP项目,其中CPU1的向导中要注意处理器选项选择CPU1。
CPU1的BSP SETTING需增加-DUSE_AMP=1。该编译选项将影响到CORE1工程代码里中断控制器SCUGIC的初始化函数以及Cache操作函数的编译,若不增加该选项,可能会出现CORE0和CORE1中断异常和Cache一致性维护异常。
每个CPU的APP项目的src目录中按照自己预想的存储器分配方案修改lscript.ld文件中的内容,千万注意不要让两个CPU的DDR地址重合,因为你APP的ELF文件是加载到DDR中执行的。由于没有OS,ELF肯定是加载到每个CPU的DDR起始地址。如果有重合那么一个CPU的ELF会覆盖另一个的。
一旦我们为内核创建了应用程序,我们需要正确的定义DDR内存的映射地址,因为程序将从这些地址开始执行。我们需要编辑链接脚本,如下图所示显示除了 DDR内存的基地址和大小。这一步很重要,如果我们不能正确的为Core 0和 Core 1定义内存地址和大小,在程序执行的过程中就会产生内核间的冲突,出现段地址错误。

(4)自己动手,移植修改SDK的SRC。(推荐!)
直接在standalone_v6_5源码上进行修改。
通过新建一个工程,并打开System.mss,我们可以发现,在SDK2017.4下,OS type只能选择standalone version 6.5.
所以,我们要移植的standalone_amp,也是复制的6.5版本的源码。
另存为standalone_amp_6_5。并在repo中添加。

然后修改其中的某些文件。

我们的依据,是xapp1078的说明文档。
standalone BSP.
Note: The standalone v4.2 BSP was modified as follows:
- armcc/_sys_write.c, gcc/write.c, printc, xil_printf.c: These changes add a new define ‘STDOUT_REDIR’
that prevents the removal of calls to outbyte() if STDOUT_BASEADDRESS is not defined
- armcc/boot.S, gcc/boot.S: These changes remove remapping of virtual address 0x20000000 to physical
address 0x00000000, configures address 0x00000000-0x2fffffff to be unavailable, and disables sharing
and L2 cache on address 0x30000000-0x3fffffff. The startup code was also modified to allow redirecting
cpu0 or cpu1 to a different starting address (This redirecting ability is not used for xapp1078).
- xtime_l.c: The change to this file prevents re-initializing the global timer.
- asm_vectors.S: Two extra vectors are added at the end of the vector table and are used by the boot.S
redirecting code. (This redirecting ability is not used for xapp1078).

先进入SRC的目录。
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9

(a)STDOUT_REDIR 宏定义
在D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9\armcc_sys_write.c,
在D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\common\gcc\write.c, 中,

D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\common\print.c中,

D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\common\xil_printf.c中,

所有涉及到print打印函数的地方,都增加了对应的宏定义,如:

#if defined STDOUT_BASEADDRESS || STDOUT_REDIR
outbyte( *lp++);
#endif

双核通信过程:cpu1会通过xil_printf()函数将打印消息发送给cpu0,cpu0再通过系统uart1将打印消息发送给显示器。
bsp设置中,Select Overview->standalone and change stdin and stdout to None,没有定义输入输出端设备,即没有STDOUT_BASEADDRESS 宏。为了避免xil_printf()无效,才有了STDOUT_REDIR 宏定义。

(我的配置:在vivado中使能uart0:使用EMIO引脚,使能uart1:使用ps侧标准IO;在cpu1的bsp配置中使用uart0;

因此,不需要定义STDOUT_REDIR,demo也可以正常运行)

(b)D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9\armcc\boot.S
作用:限定cpu1的裸机程序不可访问低内存空间(保留给linux系统专用)
第一:将虚拟地址0x20000000重新映射到物理地址0x00000000 部分的代码注释(注意:sdk软件自带的standalone不会有这段代码,可忽略此步,这段代码可能是xilinx以前增加的)

第二:将地址0x00000000-0x2fffffff(768M)配置为不可用。注意:这里配置的DDR是1G,因此cpu1运行裸机程序的情况下,配置低768M给cpu0使用,cpu1只是用高256M。如果DDR是512M,分为模式应该是:384M+128M。

第三:设置0x30000000-0x3fffffff仅作为CPU1的内部使用。如果DDR是512M,因该是高128M。

//第一步:注释代码
//	/* In case of AMP, map virtual address 0x20000000 to 0x00000000  and mark it as non-cacheable */
//#if USE_AMP==1
//	ldr	r3, =0x1ff			/* 512 entries to cover 512MB DDR */
//	ldr	r0, =TblBase			/* MMU Table address in memory */
//	add	r0, r0, #0x800			/* Address of entry in MMU table, for 0x20000000 */
//	ldr	r2, =0x0c02			/* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b0 */
//mmu_loop:
//	str	r2, [r0]			/* write the entry to MMU table */
//	add	r0, r0, #0x4			/* next entry in the table */
//	add	r2, r2, #0x100000		/* next section */
//	subs	r3, r3, #1
//	bge	mmu_loop			/* loop till 512MB is covered */
//#endif
 
	/* In case of AMP, mark address 0x00000000 - 0x2fffffff DDR as unassigned/reserved */
	/* and address 0x30000000 - 0x3fffffff DDR as inner cached only */
 
#if USE_AMP==1
 
//第二步:保留低768M(如果DDR是512M,可将768M修改为384M,cpu0也可以正常运行系统)
	ldr	r3, =0x2ff			  /* 768 entries to cover 768MB DDR */
	ldr	r0, =TblBase			/* MMU Table address in memory */
	ldr	r2, =0x0000			  /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
mmu_loop:
	str	r2, [r0]			    /* write the entry to MMU table */
	add	r0, r0, #0x4			/* next entry in the table */
	add	r2, r2, #0x100000	/* next section */
	subs	r3, r3, #1
	bge	mmu_loop			    /* loop till 768MB is covered */
 
//第三步:设置高256M专为CPU1使用(如果DDR是512M,这里的256M需修改为128M)
	ldr	r3, =0x0ff			  /* 256 entries to cover 256MB DDR */
	movw r2, #0x4de6		  /* S=b0 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b1 */
                              //注意:CB为01:表示cpu1的MMU设置为了分段地址管理,不支持cache但支持buffer;mmu域是15;保护标志位为0;访问权限为11:可读可写;在ARMv5以上版本处理器中有定义,如果TEX等于1,表示系统支持写时分配cache,这里没有分配cache;s为0:表示此内存不共享!
	movt r2, #0x3000      /* S=b0, Section start for address 0x30000000 */
mmu_loop1:
	str	r2, [r0]			    /* write the entry to MMU table */
	add	r0, r0, #0x4			/* next entry in the table */
	add	r2, r2, #0x100000	/* next section */
	subs	r3, r3, #1
	bge	mmu_loop1			    /* loop till 256MB is covered */

AMP模式禁用L2 cache(必须)
作用:如果是AMP模式,cpu1就需要禁用L2 cache;(这段代码两个sdk源码均有,不需要用户添加)

/* For AMP, assume running on CPU1. Don't initialize L2 Cache (up to Linux) */
#if USE_AMP!=1
	ldr	r0,=L2CCCrtl			/* Load L2CC base address base + control register */
	mov	r1, #0				/* force the disable bit */
	str	r1, [r0]			/* disable the L2 Caches */
 
	ldr	r0,=L2CCAuxCrtl			/* Load L2CC base address base + Aux control register */
	ldr	r1,[r0]				/* read the register */
	ldr	r2,=L2CCAuxControl		/* set the default bits */
	orr	r1,r1,r2
	str	r1, [r0]			/* store the Aux Control Register */
 
	ldr	r0,=L2CCTAGLatReg		/* Load L2CC base address base + TAG Latency address */
	ldr	r1,=L2CCTAGLatency		/* set the latencies for the TAG*/
	str	r1, [r0]			/* store the TAG Latency register Register */
 
	ldr	r0,=L2CCDataLatReg		/* Load L2CC base address base + Data Latency address */
	ldr	r1,=L2CCDataLatency		/* set the latencies for the Data*/
	str	r1, [r0]			/* store the Data Latency register Register */
 
	ldr	r0,=L2CCWay			/* Load L2CC base address base + way register*/
	ldr	r2, =0xFFFF
	str	r2, [r0]			/* force invalidate */
 
	ldr	r0,=L2CCSync			/* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */
						/* Load L2CC base address base + sync register*/
......

(c)
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9\xtime_l.c修改(必须)
作用:在AMP模式下,global全局定时器肯定会在CPU0的系统中完成初始化,因此避免CPU1启动或是运行过程中CPU1重启时,将global全局定时器reset!

void XTime_SetTime(XTime Xtime)
{
 
#ifdef USE_AMP
	if(Xil_In32(GLOBAL_TMR_BASEADDR + GTIMER_CONTROL_OFFSET) && 0x1) {
		//Timer is already enabled so don't reset it
		return;
	}
#endif
	
	/* Disable Global Timer */
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_CONTROL_OFFSET, 0x0);
 
	/* Updating Global Timer Counter Register */
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_COUNTER_LOWER_OFFSET, (u32)Xtime);
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_COUNTER_UPPER_OFFSET,
		(u32)(Xtime>>32));
 
	/* Enable Global Timer */
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_CONTROL_OFFSET, 0x1);
}

注意:
其中用到的宏,名字叫做USE_AMP,而网上很多帖子里,介绍FLAG时,是用的DUSE_AMP,有什么区别,还不清楚。

(d)修改FSBL的模板,修改为FSBL_AMP
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl文件夹,复制为D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl_amp。
在新文件夹中,
找到main.c文件打开,在里面添加下面一段代码,用于启动CPU1:

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0 //这是ZYNQ约定的用来放CPU1的PC的指针地址
#define CPU1STARTMEM 0x20000000 // 这里可以修改为自己的地址
void StartCpu1(void)
{
    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();
}

再找到Load boot image的位置,将CPU1的启动函数,放置于此位置,改动后的代码段如下:

 /*
     * Load boot image
     */
    HandoffAddress = LoadBootImage();

    fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress);
    StartCpu1();   /*add starting cpu1*/

修改tcl和mss。
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl_amp\data\zynq_fsbl.tcl
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl_amp\data\zynq_fsbl.mss
先改名为zynq_fsbl_amp.tcl和zynq_fsbl_amp.mss。
然后修改其中的内容,把里面的“standalone”全部修改为“standAMP”。

修改BSP的SRC,将之前修改的AMP版本的BSP包,放在Thirdparty下。
D:\Xilinx\SDK\2017.4\data\embeddedsw\ThirdParty\bsp\standAMP_v6_5\data下,把文件名全部改为standAMP.*。
打开文件,把里面的"standalone"全部改为"standAMP"。

在preference里面,加入我们复制并修改好的repo。

文档共60页。主要向初学者提供了Zynq开发的技术方向,针对不同应用给出了基本的参考文档;同时对Zynq双核AMP加载方式做了详细描述,对Zynq的fsbl启动流程做了简单介绍。章节如下: Zynq User Guide 1 介绍 4 2 快速上手指南 4 3 多核开发教程 4 3.1 AMP开发说明 6 3.1.1 快速生成amp工程 6 3.1.2 Generating Boot File 8 3.1.3 烧写程序 9 3.1.4 启动 10 3.1.5 调试 10 3.1.6 总结 11 3.2 SMP开发说明 11 4 ZC706启动代码分析 11 4.1 启动代码 12 4.2 FSBL流程(FOR AMP) 13 4.3 CPU0启动CPU1流程 14 5 程序在线烧写方案及流程 14 5.1 程序烧写需求 14 5.2 提出该需求的原因 14 5.3 程序烧写方案 14 5.3.1 BOOT.BIN组成 14 5.3.2 BOOT.BIN生成方法 15 5.4 FSBL.BIN和APP.BIN等的生成 15 5.5 制作*BIN及烧写的具体步骤 15 5.5.1 制作*bin流程 15 5.5.2 BOOT.bin制作过程 15 5.5.3 FSBL.bin和APP.bin等的生成过程 22 5.6 烧写BOOT.BIN步骤 26 5.6.1 通过SDK工具烧写步骤 26 5.6.2 通过上位机烧写软件的烧写步骤 29 5.6.3 通过串口调试助手烧写步骤 29 6 Zynq Qspi控制器 30 6.1 基本特性 30 6.2 I/O接口 31 6.3 QSPI控制器模式 33 6.3.1 I/O模式 33 6.3.2 线性地址(linear address)模式 33 6.3.3 传统(legacy)SPI模式 34 6.4 QSPI 例程 34 6.5 QSPI控制器支持访问32MB方法 35 6.5.1 Bank地址寄存器(Bank address register) 35 6.5.2 扩展地址模式(Extended address mode) 35 6.5.3 使用新写命令(New commands) 35 6.6 QSPI FLASH选择 35 6.7 作为BOOT器件考虑 35 7 µC/OS系统启动指南 36 7.1 INTRODUCTION 36 7.1.1 Software Requirements 36 7.1.2 Hardware Requirements 36 7.2 HARDWARE DESIGN 37 7.2.1 Step 1. Invoke the Vivado IDE and Create a project 37 7.2.2 Step 2. Create an IP Integrator Design 39 7.2.3 Step 3. Add and setup the Zynq processor system IP block 39 7.2.4 Step 4. Customize the Zynq block for our design 41 7.2.5 Step 5. Add the soft peripherals 45 7.2.6 Step 6. Generate HDL Design Files 47 7.2.7 Step 7. Synthesis, Implement and Generate Bitstream 48 7.3 SOFTWARE DESIGN 49 7.3.1 Step 1. Installation of the µC/OS Repository 49 7.3.2 Step 2. Generate the µC/OS BSP 50 7.3.3 Step 3. Build and Debug the Demonstration Project 54 7.3.4 Step 4. Program the AXI Timer 0 with the ucos_axitimer Driver 55 7.3.5 Step 5. Program the AXI Timer 1 with the Xilinx tmrctr Driver 58 7.4 CONCLUSION 59 8 Linux系统启动指南 59
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值