ZYNQ之双核通讯原理以及程序设计

2023-11-01 05:30

本文主要是介绍ZYNQ之双核通讯原理以及程序设计,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.简介

zynq系列开发板有两个板载Cortex-A9处理器,两个ARM可以协同处理数据。
多核处理器硬件上的划分
  1.同构多核:系统中的多个处理器在结构上是相同的;
        优点是硬件和软件设计上较为简单,通用性高。
  2.异构多核:系统中的处理器结构上是不同的;
        优点是在某些特定场合,专用的硬件加速核可以提高性能。
ZYNQ中的两个Cortex-A9处理器+可编程逻辑器件FPGA组成了异构多核处理器。
多核处理器从软件运行方式上划分
  AMP(Asymmetric Muti-processing):非对称多处理
    多个内核相对独立的运行不同的任务,每个内核相互隔离,可以运行不同的操  作系统或者裸机程序。
  SMP(Symmetric Muti-processing):
    多个处理器运行一个操作系统,这个操作系统同等的管理多个内核。
  BMP(Bound Muti-processing):混合多模式
    BMP与SMP类似,但是开发者可以指定将某个任务仅在某个指定内核上执行。
在这里插入图片描述
AMP模式下要注意不要两个CPU一起访问同一个地址或者共享外设。

2.CPU之间通讯原理

2.1 通讯步骤

1.系统初始化
2.启动CPU1
3.和CPU1进行通讯
4.共享CPU外设

2.2 CPU资源

  CPU资源分为私有资源和公共资源。私有资源是每个CPU都有的资源,只能被各自的CPU访问,访问时无需注意冲突。公共资源为CPU之间共享的资源,访问时要注意访问冲突。
  私有资源: L1Cache、PPI(Private peripheral interrupts)、MMU(Memory management unit)。
  公共资源: L2Cache、DDR存储器、OCM(on chip memory)、ICD(Interrupt control distributor)、全局时钟和其他外等。

  OCM用来和CPU之间的通讯的,与DDR相比,OCM具有更高的性能和更低的延迟。用于小数据量(256KB一下)用OCM更好。
  避免同时访问的方法
  DDR:CPU0只能访问0x00100000至0x001FFFFF,CPU1只能访问0x00200000到0x002FFFFF(可人为更改)
  L2Cache:CPU0使用,CPU1不使用。
  ICD:中断来自PL,连接到CPU1。
  Timer(定时器):只有CPU1使用。
  OCM:OCM的某一地址进行标志。当标志为0时这个地址是某个CPU私有的;为1时,这个地址是另一个CPU私有的。或者软件产生中断的方式。

2.3 软件设计

软件设计分为三个阶段
1.First stage boot loader(FSBL):第一启动阶段
2.Bare-metal application for CPU0:裸机应用程序
3.Bare-metal application for CPU1:裸机应用程序
FSBL
  一直运行在CPU上面,是开发板上电之后启动先启动Boot rom,后启动FSBL,负责配置PL然后拷贝两个处理器的应用程序(ELF)加载到DDR中,然后开始运行第一个应用程序。
Bare-metal application Code
  两个CPU运行各自的裸机的程序,CPU负责初始化共享外设,并且负责启动CPU1.
CPU0 Application
  内存的起始地址为0x00100000。这个起始地址可以在链接脚本进行修改的。
  CPU0的配置步骤
  1.配置MMU来禁止cache缓存功能0xFFFF0000至0xFFFFFFFF来保证两个CPU访问OCM的一致性。地址映射不可修改。
  2.初始化ICD
  3.启动CPU1
  4.通过串口打印信息
  5.设置OCM的地址作为信号量
  6.等待地址里面的信号量被清除。
  Boot rom代码执行后,CPU1也会在OCM的0xFFFFFF00地址上执行一段代码。功能是检查地址0xFFFFFFF0的值是否为1来等待事件到来。
  CPU0启动CPU1是通过向地址0x00200000写入地址0xFFFFFFF0然后CPU0运行Set Event(SEV)命令启动CPU1。CPU1会读取0xFFFFFFF0里面的值0x00200000。然后跳转到该地址执行程序。
  CPU1的配置步骤

3 如何避免多个CPU同时访问OCM

  CPU0向OCM写入一个数据之后,给CPU1产生软件中断。让CPU1知道CPU0已经不再操作该地址。此时CPU1读取数据,读取完毕后产生一个中断通知CPU0。
  软件中断(SGIs):中断来自CPU内部,每个CPU可以中断自己或者另外的CPU或者一起中断,每个CPU有16个中断号,编号为0到15。向寄存器(ICDSGIR)写入中断号并且指定CPU。目标的CPU即可产生中断。
  OCM:PS的片上存储器,包括256KB的RAM和128KB的ROM(BootROM)。地址范围为0x00000000到0002FFFF的三个64KB加上0xFFFF_0000到0xFFFF_FFFF共256KB。

4 程序设计

4.1 程序任务

  CPU0接收串口数据并写入OCM中,然后利用软件中断触发CPU1;CPU1接收到中断后,根据从OCM中读出的数据控制呼吸灯的频率,并在控制结束后触发CPU0的中断,实现双核CPU通信的功能。

4.2 系统框图

在这里插入图片描述

4.3 软件操作

  SDK中新建好两个CPU的程序后,打开CPU0>>>src>>>

4.4 代码

4.4.1 CPU0_UART

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           cpu0_uart
// Last modified Date:  2019/6/8 17:25:36
// Last Version:        V1.0
// Descriptions:        CPU0应用程序
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/6/8 17:25:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//#include "xparameters.h"
#include "xscugic.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "stdio.h"//宏定义
#define INTC_DEVICE_ID	     XPAR_SCUGIC_SINGLE_DEVICE_ID //中断ID
#define SHARE_BASE           0xffff0000                   //共享OCM首地址
#define CPU1_COPY_ADDR       0xfffffff0                   //存放CPU1应用起始地址的地址
#define CPU1_START_ADDR      0x10000000                   //CPU1应用起始地址#define CPU1_ID              XSCUGIC_SPI_CPU1_MASK        //CPU1 ID
#define SOFT_INTR_ID_TO_CPU0 0                            //软件中断号 0 ,范围:0~15
#define SOFT_INTR_ID_TO_CPU1 1                            //软件中断号 1 ,范围:0~15//"SEV"指令唤醒CPU1并跳转至相应的程序
#define sev()                __asm__("sev")               //C语言内嵌汇编写法 send event指令//函数声明
void start_cpu1();
void cpu0_intr_init(XScuGic *intc_ptr);
void soft_intr_handler(void *CallbackRef);//全局变量
XScuGic Intc;                    //中断控制器驱动程序实例
int rec_freq_flag = 0;           //接收到呼吸灯频率设置的标志
int freq_gear;                   //频率档位//CPU0 main函数
int main()
{//S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0Xil_SetTlbAttributes(SHARE_BASE,0x14de2);    //禁用OCM的Cache属性//S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0Xil_SetTlbAttributes(CPU1_COPY_ADDR,0x14de2);//禁用0xfffffff0的Cache属性//启动CPU1start_cpu1();//CPU0中断初始化cpu0_intr_init(&Intc);while(1){if(rec_freq_flag == 0){xil_printf("This is CPU0,Please input the numbers 1~5 to change ""breath led frequency\r\n");scanf("%d",&freq_gear);if(freq_gear >= 1 && freq_gear <=5){xil_printf("You input number is %d\r\n",freq_gear);//向共享的地址中写入输入的数据Xil_Out8(SHARE_BASE,freq_gear);//给CPU1触发中断XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU1,CPU1_ID);rec_freq_flag = 1;}else{xil_printf("Error,The number range is 1~5\r\n");xil_printf("\r\n");}}}return 0 ;
}//启动CPU1,用于固化程序
void start_cpu1()
{//向 CPU1_COPY_ADDR(0Xffffffff0)地址写入 CPU1 的访问内存基地址Xil_Out32(CPU1_COPY_ADDR, CPU1_START_ADDR);dmb();  //等待内存写入完成(同步)sev();  //通过"SEV"指令唤醒CPU1并跳转至相应的程序
}//CPU0中断初始化
void cpu0_intr_init(XScuGic *intc_ptr)
{//初始化中断控制器XScuGic_Config *intc_cfg_ptr;intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,intc_cfg_ptr->CpuBaseAddress);//设置并打开中断异常处理功能Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);Xil_ExceptionEnable();XScuGic_Connect(intc_ptr, SOFT_INTR_ID_TO_CPU0,(Xil_ExceptionHandler)soft_intr_handler, (void *)intc_ptr);XScuGic_Enable(intc_ptr, SOFT_INTR_ID_TO_CPU0); //CPU0软件中断
}//软件中断函数
void soft_intr_handler(void *CallbackRef)
{xil_printf("This is CPU0,Soft Interrupt from CPU1\r\n");xil_printf("\r\n");rec_freq_flag = 0;
}

4.4.2 CPU1_LED

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           cpu1_led
// Last modified Date:  2019/6/8 17:25:36
// Last Version:        V1.0
// Descriptions:        CPU1应用程序
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/6/8 17:25:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//#include "xparameters.h"
#include "xscugic.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "stdio.h"
#include "breath_led_ip.h"//宏定义
#define INTC_DEVICE_ID	     XPAR_SCUGIC_SINGLE_DEVICE_ID //中断ID
#define SHARE_BASE  	     0xffff0000                   //共享OCM首地址#define CPU0_ID              XSCUGIC_SPI_CPU0_MASK        //CPU0 ID
#define SOFT_INTR_ID_TO_CPU0 0                            //软件中断号 0 ,范围:0~15
#define SOFT_INTR_ID_TO_CPU1 1                            //软件中断号 1 ,范围:0~15#define  LED_IP_BASEADDR     XPAR_BREATH_LED_IP_0_S0_AXI_BASEADDR //LED IP基地址
#define  LED_IP_REG0         BREATH_LED_IP_S0_AXI_SLV_REG0_OFFSET //LED IP寄存器地址0
#define  LED_IP_REG1         BREATH_LED_IP_S0_AXI_SLV_REG1_OFFSET //LED IP寄存器地址1//函数声明
void cpu1_intr_init(XScuGic *intc_ptr);
void soft_intr_handler(void *CallbackRef);//全局变量
XScuGic Intc;               //中断控制器驱动程序实例
int soft_intr_flag = 0;     //软件中断的标志
int freq_gear;              //频率档位//CPU1 main函数
int main()
{int freq_step = 0;//S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0Xil_SetTlbAttributes(SHARE_BASE,0x14de2);    //禁用OCM的Cache属性//CPU1中断初始化cpu1_intr_init(&Intc);//打开呼吸灯BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG0, 1);while(1){if(soft_intr_flag){freq_gear = Xil_In8(SHARE_BASE);     //从共享OCM中读出数据xil_printf("CUP1 Received data is %d\r\n",freq_gear) ;switch(freq_gear){case 1 : freq_step = 20;break;case 2 : freq_step = 50;break;case 3 : freq_step = 100;break;case 4 : freq_step = 200;break;case 5 : freq_step = 500;break;default : freq_step = 50;break;}//设置呼吸灯频率,最高位为1,设置有效BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR,LED_IP_REG1,(0x80000000|freq_step));//给给CPU0触发中断XScuGic_SoftwareIntr(&Intc,SOFT_INTR_ID_TO_CPU0,CPU0_ID);soft_intr_flag = 0;}}return 0 ;
}//CPU1中断初始化
void cpu1_intr_init(XScuGic *intc_ptr)
{//初始化中断控制器XScuGic_Config *intc_cfg_ptr;intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,intc_cfg_ptr->CpuBaseAddress);//设置并打开中断异常处理功能Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);Xil_ExceptionEnable();XScuGic_Connect(intc_ptr, SOFT_INTR_ID_TO_CPU1,(Xil_ExceptionHandler)soft_intr_handler, (void *)intc_ptr);XScuGic_Enable(intc_ptr, SOFT_INTR_ID_TO_CPU1); //CPU1软件中断
}//软件中断函数
void soft_intr_handler(void *CallbackRef)
{xil_printf("This is CUP1,Soft Interrupt from CPU0\r\n") ;soft_intr_flag = 1;
}

这篇关于ZYNQ之双核通讯原理以及程序设计的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/320816

相关文章

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

hdu4407容斥原理

题意: 有一个元素为 1~n 的数列{An},有2种操作(1000次): 1、求某段区间 [a,b] 中与 p 互质的数的和。 2、将数列中某个位置元素的值改变。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.Inpu

hdu4059容斥原理

求1-n中与n互质的数的4次方之和 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWrit

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类