ZYNQ笔记(5):软中断实现核间通讯

  ZYNQ包括一个 FPGA 和两个 ARM,多个 ARM 核心相对独立的运行不一样的任务,每一个核心可能运行不一样的操做系统或裸机程序,可是有一个主要核心,用来控制整个系统以及其余从核心的容许。所以咱们能够在 CPU0 和 CPU1 中独立跑不一样的应用程序,发挥双核的非对称性架构的优点和性能。架构

   从软件的角度来看,多核处理器的运行模式主要有三种:app

  ① AMP(非对称多进程):多个核心相对独立的运行不一样的任务,每一个核心可能运行不一样的操做系统或裸机程序,可是有一个主要核心,用来控制整个系统以及其它从核心的运行。函数

  ② SMP(对称多进程):一个操做系统同等的管理各个内核,例如 PC 机。性能

  ③ BMP(受约束多进程):与 SMP 相似,但开发者能够指定将某个任务仅在某个指定内核上执行默认状况下。优化

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

1、核间中断原理(软中断SGI)操作系统

  软中断的 ID 都是从0到15,而且都是上升沿触发,主要用于核间中断或者 CPU 本身中断本身。设计

  中断函数以下:3d

XScuGic_SoftwareIntr(&InterruptController,   //指向GIC指针 INTC_CPU0, //须要中断的CPU ID
                     XSCUGIC_SPI_CPU0_MASK);   //使能该CPU会接受中断

 

2、ARM启动过程指针

1.ARM 里有个 ROM,存储了一段程序,ROM起来后从 SD 卡读取数据 2.启动 FSBL(First Boot Loader)第一启动项(有模板) 3.加载 bit(FPGA配置程序),同时加载 elf(ARM应用程序),若是是操做系统则 elf 替换成 uBoot

 

3、搭建软件 CPU0 和 CPU1 非对称环境

1.建立 amp_fsbl 用于生成烧写镜像的时候加载 core0 和 core1的代码。

①启动 Vivado,建立 ZYNQ,勾选  SD卡 和 UART 便可,并加载 SDK 开发环境

②进到 SDK ,点击 File --- New --- Application Project,命名为 amp_fsbl 并选择 CPU0

③选择 FSBL,finish

④修改 main.c 函数来启动 core1,须要两个步骤,首先把 CPU1 应用程序地址写入到 0xfffffff0地址中,这是启动 CPU1 命令的地址,而后执行 sev 指令加载 CPU1 应用程序。具体参考 UG585 的启动代码章节。

在 main.c 函数的 main 函数上方插入这段代码:

 1 #define sev() __asm__("sev")
 2 #define CPU1STARTADR 0xFFFFFFF0
 3 #define CPU1STARTMEM 0x2000000
 4 
 5 void StartCpu1(void)  6 {  7     #if 1
 8     fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r");  9  Xil_Out32(CPU1STARTADR, CPU1STARTMEM); 10     dmb(); //waits until write has finished
11     fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r"); 12  sev(); 13     #endif
14 }

在 main.c 函数的 load镜像位置加入代码: StartCpu1(); 

2.建立 app_cpu0 应用程序

①从新建立一个新的 File --- New --- Application Project,命名为 app_cpu0,这时选择的是 CPU0

②选择 helloworld 模板便可

③将 helloworld.c 更名为 mian.c,而且用以下代码替换掉内容

 1 #include <stdio.h>
 2 #include "platform.h"
 3 #include "xil_printf.h"
 4 
 5 #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000)) //无优化无符号长整形地址转成指针
 6 
 7 int main()  8 {  9     COMM_VAL=0; 10 
11     //Disable cache on OCM
12     Xil_SetTlbAttributes(0xFFFF0000,0x14de2); 13     while(1) 14  { 15         print("Hello World cpu0 \n\r"); 16         COMM_VAL =1; 17         while(COMM_VAL == 1) 18  { 19  } 20  } 21     return 0; 22 }

该指针指向的地址为片上存储的共享内存(OCM)。能够指定这里面的任意一个地址。定义的指针变量以下所示: #define COMM_VAL (*(volatile unsigned long *)(0x00020000)) 该变量CPU0和CPU1均可以在里面读写数据,能够达到CPU0和CPU1的数据交互。OCM的地址以下图所示。

④打开 Scr 目录中的文件 lscript.ld,点击下方的 Source 作以下修改:CPU0 的代码空间改成 1E00000

CPU1运行程序的地址改成fsbl里面指定的起始地址。后面为长度,有一点须要注意:CPU0的起始地址加上CPU0的长度以后不能超过CPU1的起始地址。也就是两个CPU占用的DDR的地址不能重叠。若程序很大,则CPU0须要的LENGTH就大,所以CPU1的起始地址数值就大。DDR地址范围以下所示:

3.建立 app_cpu1 应用程序

①从新建立一个新的 File --- New --- Application Project,命名为 app_cpu1,这时选择的是 CPU1

②选择 helloworld 模板便可

③将 helloworld.c 更名为 mian.c,而且用以下代码替换掉内容

 1 #include <stdio.h>
 2 #include "platform.h"
 3 #include "xil_printf.h"
 4 
 5 #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000))
 6 int main()  7 {  8     //Disable cache on OCM
 9     Xil_SetTlbAttributes(0xFFFF0000,0x14de2); 10     while(1) 11  { 12         while(COMM_VAL == 0) 13  { 14  } 15     print("Hello World cpu1 \n\r"); 16     sleep(2); 17     COMM_VAL=0; 18  } 19     return 0; 20 }

④打开 Scr 目录中的文件 lscript.ld 点击下方的 Source 作以下修改起始地址改成 0x2000000 长度 0x1F00000

4.增长编译选项(设置 CPU1 的BSP setting 为 AMP 模式)

app_cpu1_bps --- 右键 --- Board Suport Package Setting,点击 driver --- ps7_cortexa9_0,添加指令

5.让双核跑起来

①点击 app_cpu0 --- 右键 --- Debug As --- Debug Configurations...

② 点击选项卡的 Application,勾选 0 和 1,而后点击 Debug,yes

③默认停到第一行,链接好串口,选择APU --- ARM --- #0,单步慢慢走能够看到有信息打印出,#2也是同样的。若是让 #0 和 #1 都一直执行,则串口会一直交替打印。

 

4、软中断的注册和使用

 

参考资料:

    [1]V3学院FPGA教程

    [2]何宾, 张艳辉. Xilinx Zynq-7000嵌入式系统设计与实现[M]. 电子工业出版社, 2016.

相关文章
相关标签/搜索