ZYNQ包括一个 FPGA 和两个 ARM,多个 ARM 核心相对独立的运行不同的任务,每个核心可能运行不同的操作系统或裸机程序,但是有一个主要核心,用来控制整个系统以及其他从核心的允许。因此我们可以在 CPU0 和 CPU1 中独立跑不同的应用程序,发挥双核的非对称性架构的优势和性能。

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

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

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

  ③ BMP(受约束多进程):与 SMP 类似,但开发者可以指定将某个任务仅在某个指定内核上执行默认情况下。

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

一、核间中断原理(软中断SGI)

  软中断的 ID 都是从0到15,并且都是上升沿触发,主要用于核间中断或者 CPU 自己中断自己。

  中断函数如下:

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

二、ARM启动过程

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

三、搭建软件 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 函数上方插入这段代码:

 #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
}

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

2.创建 app_cpu0 应用程序

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

②选择 helloworld 模板即可

③将 helloworld.c 改名为 mian.c,并且用如下代码替换掉内容

 #include <stdio.h>
#include "platform.h"
#include "xil_printf.h" #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000)) //无优化无符号长整形地址转成指针 int main()
{
COMM_VAL=; //Disable cache on OCM
Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
while()
{
print("Hello World cpu0 \n\r");
COMM_VAL =;
while(COMM_VAL == )
{
}
}
return ;
}

该指针指向的地址为片上存储的共享内存(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,并且用如下代码替换掉内容

 #include <stdio.h>
#include "platform.h"
#include "xil_printf.h" #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000))
int main()
{
//Disable cache on OCM
Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
while()
{
while(COMM_VAL == )
{
}
print("Hello World cpu1 \n\r");
sleep();
COMM_VAL=;
}
return ;
}

④打开 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 都一直执行,则串口会一直交替打印。

四、软中断的注册和使用

参考资料:

    [1]V3学院FPGA教程

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

ZYNQ笔记(5):软中断实现核间通信的更多相关文章

  1. 【DSP开发】硬件信号量在多核处理器核间通信中的应用

    硬件信号量在多核处理器核间通信中的应用 刘德保1,汪安民1,韩道文2 1.同方电子科技有限公司研究所,九江 332009:2.解放军电子工程学院 摘要: 在多核处理器的软件设计中,核间通信机制是关键所 ...

  2. Blazor入门笔记(6)-组件间通信

    1.环境 VS2019 16.5.1.NET Core SDK 3.1.200Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.简介 在使用B ...

  3. Windows环境下多线程编程原理与应用读书笔记(4)————线程间通信概述

    <一>线程间通信方法 全局变量方式:进程中的线程共享全局变量,可以通过全局变量进行线程间通信. 参数传递法:主线程创建子线程并让子线程为其服务,因此主线程和其他线程可以通过参数传递进行通信 ...

  4. Docker 与 K8S学习笔记(九)—— 容器间通信

    容器之间可通过IP.Docker DNS Server或joined三种方式进行通信,今天我们来详细学习一下. 一.IP通信 IP通信很简单,前一篇中已经有所涉及了,只要容器使用相同网络,那么就可以使 ...

  5. Angular4学习笔记(十)- 组件间通信

    分类 父子组件通信 非父子组件通信 实现 父子 父子组件通信一般使用@Input和@Output即可实现,参考Angular4学习笔记(六)- Input和Output 通过Subject 代码如下: ...

  6. 【读书笔记】iOS网络-应用间通信

    一,URL方案 URL方案有3个主要用途:根据设备上其他应用的存在与否调整逻辑,切换到其他应用以及响应打开你的应用的其他应用.你还可以通过URL方案从某个站点或是在基于Web的认证流程结束是打开应用. ...

  7. 【读书笔记】iOS-网络-应用间通信

    一,URL方案 URL方案有3个主要用途:根据设备上其他应用的存在与否调整逻辑,切换到其他应用以及响应打开你的应用的其他应用.你还可以通过URL方案从某个站点或是在基于Web的认证流程结束是打开应用. ...

  8. dm8127之核间通信syslink

    Last updated: June 23, 2010 Contents [hide] 1 About SysLink 1.1 SysLink Architecture 1.2 SysLink Usa ...

  9. ucos实时操作系统学习笔记——任务间通信(消息)

    ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...

随机推荐

  1. Gin-Go学习笔记六:Gin-Web框架 Api的编写

    Api编写 1>     Gin框架的Api返回的数据格式有json,xml,yaml这三种格式.其中yaml这种格式是一种特殊的数据格式.(本人暂时没有实现获取节点值得操作) 2>    ...

  2. Vue – 基础学习(4):事件修饰符

    Vue – 基础学习(3):事件修饰符

  3. vue父组件引用多个相同的子组件传值

    没有什么问题是for 解决不了的,我一直深信这句话,当然这句话也是我说的 父组件引用多个相同的子组件传值问题 (这种情况很少遇到) 1 <template> 2 <div> 3 ...

  4. SpringBoot2.0整合fastjson的正确姿势

            SpringBoot2.0如何集成fastjson?在网上查了一堆资料,但是各文章的说法不一,有些还是错的,可能只是简单测试一下就认为ok了,最后有没生效都不知道.恰逢公司项目需要将J ...

  5. pandas 之 groupby 聚合函数

    import numpy as np import pandas as pd 聚合函数 Aggregations refer to any data transformation that produ ...

  6. Linux(Centos7)安装Oracle11.2.0数据字典初始化,监听,网络,创建用户等部分配置

    #创建数据字典和pl/sql包 @/u01/app/oracle/product/11.2.0/db_1/rdbms/admin/catalog.sql; @/u01/app/oracle/produ ...

  7. linux上查看swf文件.靠谱

    在linux上查看swf文件,本来想用gnash 来看,可是有的电脑上看的时候只有声音,没有图像 所以用网页来查看,推荐谷歌 我们在和flash文件的同目录下新建一个文件名为:index.html 注 ...

  8. Go Programming Language

    [Go Programming Language] 1.go run %filename 可以直接编译并运行一个文件,期间不会产生临时文件.例如 main.go. go run main.go 2.P ...

  9. CEF 拦截打开超链接事件

    使用 CEF 加载指定页面后,如果你希望控制页面在打开超链接时根据自己预定义的一些行为来操作,比如在自己的 UI 框架中新建一个 Tab 页又或者阻止打开新的页面等.我们就需要通过 CEF 提供的两个 ...

  10. 201671010459 张旭辉 实验十四 团队项目评审&课程学习总结

    项目 内容 这个作业属于哪个课程 [教师博客主页链接] 这个作业的要求在哪里 [作业链接地址] 作业学习目标 (1)掌握软件项目评审会流程(2)反思总结课程学习内容 github仓库地址链接 [Git ...