【JokerのZYNQ7020】AMP。

2024-01-27 07:40
文章标签 amp zynq7020 joker

本文主要是介绍【JokerのZYNQ7020】AMP。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

软件环境:vivado 2017.4        硬件平台:XC7Z020


首先吧,说说这篇文章标题AMP是个啥。这个AMP(非对称多处理)是相对于SMP(对称多处理)来说的,耍ZYNQ的朋友们都很清楚,PS这边是个双核A9,而之前的大多数SDK程序,除非特别指定,一般会默认只跑在核0上,而今天这个AMP程序,是核0和核1一起跑,类似于真正的两个进程同时进行,但彼此之间还有软中断相互触发,有一片共享的数据区域,也体现了与之前SDK中跑的程序的不同。再直白一点的形容两个的差别,SMP是在两个核上跑一个系统,资源两个核共享,核怎么调度由系统来完成,而AMP更像是在两个核上跑两个系统,每个核应该怎么做,资源应该怎么规划,全由自己来决定,有着更大的自由度的同时,对规划的要求也更高。今天的AMP程序是基于之前1080p图像显示那个程序上面改出来的,所以PL这边的结构与之前一模一样。

而今天这个程序与之前程序的主要差别或者说主要想实现的是,从SD卡中读图这件事仅由核0完成,4张图像读取完毕后,核1显示1图2秒,然后将2图数据放入共享内存,触发软中断,让核1读取共享内存中的2图内容,然后显示出来,核1显示2秒完毕后同样产生软中断,通知核0,然后于此相同完成图3图4在核0核1的交替显示。 所以这篇的重点也就自然而然的有两个,一个是如何让核0和核1一起跑,另一个是如何利用软中断彼此触发。先开手册UG585 P229。

可以看到,总共有16个软中断可以利用,我这里只用到了两个,另外需要说明的一点是,软中断不但可以核之间相互触发,核本身也可以利用软中断触发自己。话不多说,开搞,先从核1的说起,核1不像核0要从卡里读图,所以BSP这边并不要什么额外的库的支持。只是创建程序的时候需要注意一下。

 下拉框中,一定要选择应用是跑在核1上的,切记切记!左侧就是核1程序结构,依次来说一下。

main.c

#include <stdio.h>
#include "xparameters.h"
#include "xsdps.h"
#include "xil_printf.h"
#include "sleep.h"#include "share_memory.h"
#include "soft_interrupt.h"#define SHARED_BASE_ADDR	0x30000000#define H_STRIDE            1920
#define H_ACTIVE            1920
#define V_ACTIVE            1080
#define VIDEO_LENGTH  (H_STRIDE*V_ACTIVE)#define VDMA_BASEADDR   XPAR_AXI_VDMA_0_BASEADDR
#define VIDEO_BASEADDR0 0x05000000
#define Buffer_Size 1920*1080*3XScuGic Intc; //GICu8 share_memory_data[Buffer_Size]  __attribute__ ((aligned(32)));
volatile u8 software_interrupt_flag = 0;void Xil_DCacheFlush(void);void Show_BMP_Picture( const unsigned char * addr, u32 size_x, u32 size_y)
{u32 x=0;u32 y=0;u32 r,g,b;for(y=0;y<size_y;y++){for(x=0;x<size_x;x++){r = *(addr++);g = *(addr++);b = *(addr++);Xil_Out32((VIDEO_BASEADDR0+((y*size_x)+size_x-x)*4),((r<<16)|(g<<8)|(b<<0)));}}Xil_DCacheFlush();
}void VDMA_init()
{int i;for(i=0;i<VIDEO_LENGTH;i++){Xil_Out32(VIDEO_BASEADDR0+i*4,0);}Xil_DCacheFlush();Xil_Out32((VDMA_BASEADDR + 0x000), 0x3);Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0);Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0);Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0);Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4));Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4));Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);
}int main()
{u8 *share_region = (u8 *)SHARED_BASE_ADDR;VDMA_init();Init_Intr_System(&Intc);Init_Intr_Software(&Intc, Software_Interrupt_Hanedler, Cpu0_To_Cpu1_Interrupt, 1);Setup_Intr_Exception(&Intc);while(1){if(software_interrupt_flag){export_data(share_memory_data, share_region,Buffer_Size);Show_BMP_Picture(share_memory_data,1920,1080);sleep(2);Software_Interrupt_Generate(&Intc, Cpu1_To_Cpu0_Interrupt, XSCUGIC_SPI_CPU0_MASK);software_interrupt_flag = 0;}}return 0;
}

SHARED_BASE_ADDR划分的内存共享区域,这里先不谈,一会儿结合地址划分再说。software_interrupt_flag软中断触发标志,当接收到软中断时置1。主函数中,首先进行中断初始化,Init_Intr_Software是在soft_interrupt.c中定义的,下面说。循环内部,通过不断检测软中断触发标志,一旦接收到软中断,就说明核0已经把图片内容放进共享内存区域,此时,核1从共享内存区域中导出数据,并显示2秒,而后产生触发核0的软中断,回馈给核0,最后清除软中断。

share_memory.c

#include "share_memory.h"void export_data(u8 *buffer,  u8 *p,  u32 length)
{Xil_DCacheInvalidateRange((INTPTR)p, length);memcpy(buffer, p, length);
}void import_data(u8 *src_buffer, u8 *dst_buffer, u32 length)
{memcpy(dst_buffer, src_buffer, length);Xil_DCacheFlushRange((INTPTR)src_buffer, length);Xil_DCacheFlushRange((INTPTR)dst_buffer, length);
}

share_memory中,主要是共享内存中的数据拷贝和缓冲区的刷新,一定要进行缓冲区刷新,不然数据有可能会出错,原因下面会说。

share_memory.h

#ifndef SHARE_MEMORY_H_
#define SHARE_MEMORY_H_#include "xil_types.h"
#include "xil_cache.h"
#include "string.h"void export_data(u8 *buffer,  u8 *p,  u32 length);
void import_data(u8 *src_buffer, u8 *dst_buffer, u32 length);#endif

soft_interrupt.c

#include "soft_interrupt.h"extern u8 software_interrupt_flag;void Software_Interrupt_Hanedler(void *Callback)
{xil_printf("receive soft-interrupt!\r\n");software_interrupt_flag = 1;
}void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
{Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,(void *)IntcInstancePtr);Xil_ExceptionEnable();
}int Init_Intr_System(XScuGic * IntcInstancePtr)
{int Status;XScuGic_Config *IntcConfig;IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);if (NULL == IntcConfig) {return XST_FAILURE;}Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS) {return XST_FAILURE;}return XST_SUCCESS;
}void Init_Intr_Software(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHanedler, u16 SoftwareIntrId, u8 CpuId)
{int Status;XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xB0, 0x2);Status = XScuGic_Connect(GicInstancePtr, SoftwareIntrId,(Xil_InterruptHandler)IntrHanedler, NULL);if (Status != XST_SUCCESS) {xil_printf("Cpu%d: software interrupt %d set fail!\r\n", XPAR_CPU_ID, SoftwareIntrId);return;}XScuGic_InterruptMaptoCpu(GicInstancePtr, CpuId, SoftwareIntrId);XScuGic_Enable(GicInstancePtr, SoftwareIntrId);}void Software_Interrupt_Generate(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId)
{int Status;Status = XScuGic_SoftwareIntr(GicInstancePtr, SoftwareIntrId, CpuId);if (Status != XST_SUCCESS) {xil_printf("Cpu%d: software interrupt %d generate fail!\r\n", XPAR_CPU_ID, SoftwareIntrId);return;}
}

soft_interrupt.h

#ifndef SOFT_INTRRUPT_H_
#define SOFT_INTRRUPT_H_#include "xil_cache.h"
#include <stdio.h>
#include "xil_types.h"
#include "Xscugic.h"
#include "Xil_exception.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xdebug.h"#define Cpu0_To_Cpu1_Interrupt   0x01
#define Cpu1_To_Cpu0_Interrupt   0x02
#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_IDvoid Software_Interrupt_Hanedler(void *Callback);
void Init_Intr_Software(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHanedler, u16 SoftwareIntrId, u8 CpuId);
void Software_Interrupt_Generate(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId);
int Init_Intr_System(XScuGic * IntcInstancePtr);
void setup_Intr_Exception(XScuGic * IntcInstancePtr);#endif

软中断这里首先是中断服务函数Software_Interrupt_Hanedler,这个根据自身实际设计需求来填充,我因为主函数是轮询的,所以这里只产生标志就足够了。而后在Init_Intr_Software中利用XScuGic_SetPriorityTriggerType给对应中断设置优先级和触发方式,利用XScuGic_Connect将中断与中断服务函数绑定,这里由于使用的是AMP模式,2个CPU,所以需要利用XScuGic_InterruptMaptoCpu明确的告知,当前设置的中断,是与哪一个CPU进行映射绑定的,最后,利用XScuGic_Enable使能。

至此,核1的程序基本就这样了,由于核0的程序是在上一篇1080p图像显示基础上改过来的,所以BSP中依旧需要使能对于内存卡的支持,share_memory与soft_interrupt与核1程序是一样的,所以这里只说主函数怎么改的。

main.c

#include <stdio.h>
#include "xparameters.h"
#include "xsdps.h"
#include "xil_printf.h"
#include "ff.h"
#include "bmp.h"
#include "sleep.h"#include "share_memory.h"
#include "soft_interrupt.h"#define BUFFER_BASE_ADDR	0x30000000
#define SHARED_BASE_ADDR	0x32000000#define H_STRIDE            1920
#define H_ACTIVE            1920
#define V_ACTIVE            1080
#define VIDEO_LENGTH  (H_STRIDE*V_ACTIVE)#define VDMA_BASEADDR   XPAR_AXI_VDMA_0_BASEADDR
#define VIDEO_BASEADDR0 0x05000000
#define Buffer_Size 1920*1080*3XScuGic Intc;
static FATFS SD_Card_Dev;
char *SD_Card_Path = "0:/";u8 *data_buffer;u8 Original_Buf1[Buffer_Size] __attribute__ ((aligned(32)));
u8 Original_Buf2[Buffer_Size] __attribute__ ((aligned(32)));
u8 Original_Buf3[Buffer_Size] __attribute__ ((aligned(32)));
u8 Original_Buf4[Buffer_Size] __attribute__ ((aligned(32)));u8 Show_Buf1[Buffer_Size] __attribute__ ((aligned(32)));
u8 Show_Buf2[Buffer_Size] __attribute__ ((aligned(32)));
u8 Show_Buf3[Buffer_Size] __attribute__ ((aligned(32)));
u8 Show_Buf4[Buffer_Size] __attribute__ ((aligned(32)));volatile u8 software_interrupt_flag = 0;void Xil_DCacheFlush(void);void Show_BMP_Picture( const unsigned char * addr, u32 size_x, u32 size_y)
{u32 x=0;u32 y=0;u32 r,g,b;for(y=0;y<size_y;y++){for(x=0;x<size_x;x++){r = *(addr++);g = *(addr++);b = *(addr++);Xil_Out32((VIDEO_BASEADDR0+((y*size_x)+size_x-x)*4),((r<<16)|(g<<8)|(b<<0)));}}Xil_DCacheFlush();
}void VDMA_init()
{int i;for(i=0;i<VIDEO_LENGTH;i++){Xil_Out32(VIDEO_BASEADDR0+i*4,0);}Xil_DCacheFlush();Xil_Out32((VDMA_BASEADDR + 0x000), 0x3);Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0);Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0);Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0);Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4));Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4));Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);
}int SD_init()
{FRESULT result;result = f_mount(&SD_Card_Dev,SD_Card_Path, 0);if (result != 0) {return XST_FAILURE;}return XST_SUCCESS;
}int main()
{data_buffer = (u8 *)BUFFER_BASE_ADDR;VDMA_init();SD_init();Init_Intr_System(&Intc);Init_Intr_Software(&Intc, Software_Interrupt_Hanedler, Cpu1_To_Cpu0_Interrupt, 0);Setup_Intr_Exception(&Intc);BMP_Picture_Processor((u8 *)"1.bmp" , Original_Buf1 ,Buffer_Size);BMP_Picture_Processor((u8 *)"2.bmp" , Original_Buf2 ,Buffer_Size);BMP_Picture_Processor((u8 *)"3.bmp" , Original_Buf3 ,Buffer_Size);BMP_Picture_Processor((u8 *)"4.bmp" , Original_Buf4 ,Buffer_Size);u32 i;for(i = 0;i < Buffer_Size ;i++ ){Show_Buf1[i] = Original_Buf1[Buffer_Size-i-1];Show_Buf2[i] = Original_Buf2[Buffer_Size-i-1];Show_Buf3[i] = Original_Buf3[Buffer_Size-i-1];Show_Buf4[i] = Original_Buf4[Buffer_Size-i-1];}while(1){Show_BMP_Picture(Show_Buf1,1920,1080);sleep(2);import_data(Show_Buf2, data_buffer, Buffer_Size);Software_Interrupt_Generate(&Intc, Cpu0_To_Cpu1_Interrupt, XSCUGIC_SPI_CPU1_MASK);while(!software_interrupt_flag);software_interrupt_flag = 0;Show_BMP_Picture(Show_Buf3,1920,1080);sleep(2);import_data(Show_Buf4, data_buffer, Buffer_Size);Software_Interrupt_Generate(&Intc, Cpu0_To_Cpu1_Interrupt, XSCUGIC_SPI_CPU1_MASK);while(!software_interrupt_flag);software_interrupt_flag = 0;}return 0;
}

 可以看到,除了图像交叉显示之外,其实也没啥变化,while(1)里,就跟最开始说的一样,图1先显示2秒,然后将从卡里读到的图2的数据放到数据共享区域,产生软中断触发核1读取显示,然后自己一直等核1给自己的显示结束的软中断,接收到以后,说明核1显示结束,然后自己再进行图3的显示,显示2秒后,图4的操作与前一致,循环进行核0和核1的图像显示。


程序其实很简单,接下来说的才是重中之重了,就是调AMP的时候需要注意的事项。

1.软中断的注册,映射,和产生函数,XScuGic_Connect、XScuGic_InterruptMaptoCpu、XScuGic_SoftwareIntr。还有中断服务函数,由于都是自己定义的,所以想要中断做什么,和中断的方式,一定要有个整体的规划。

2.内存地址分配,这个非常重要,我强烈的建议,最好把核0、核1和内存共享的区域,三者之间独立开!!!以下分别是我核0、核1和共享内存之间的划分。

 

 

3.Xil_DCacheFlushRange内存强行刷新。如果在调此类AMP应用时候,发现花屏、中断能触发但是数据不对等等问题的时候,首先考虑的应该是cache一致性问题造成的,我在调这AMP程序时候,发现图像能交叉显示出来,但是显示时候总有一块是花屏的,不是上面就是下面,就类似下面这个示例图一样。

 查了以后发现zynq的512k的L2 cache是两个核共享的,详细内容可以看ug585手册第3章,这里就不截了。这里只说这种问题怎么解决,一方面是在进行数据写入共享内存后,进行Xil_DCacheFlushRange,让写入内存的数把缓存也刷了,另一方面干脆在核1的BSP中添加-DUSE_AMP=1的编译选项。

至于这个DUSE_AMP选项影响的是哪里,看下CACHE这边你就明白了,这里只是拿Xil_DCacheFlushRange来举例而已,还有很多约束L2 Cache的地方,感兴趣的可以自己打开来看。

4.debug的时候,注意要把两个核全都勾上。看图。

5.至于两个核怎么一起跑,一起选中,然后run就好了呀。

 

这篇关于【JokerのZYNQ7020】AMP。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Linux - 压缩amp;amp;解压缩命令详解

linux zip命令 1.zip命令  zip -r myfile.zip ./* 将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件.  zip -r myfile.zip ./*将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzip unzip -o -d /home/sunny

PHP引用(amp;)使用详解【转】

官方文档: 1.引用是什么:http://www.php.net/manual/zh/language.references.whatare.php 2.引用做什么: http://www.php.net/manual/zh/language.references.whatdo.php 3.引用传递: http://www.php.net/manual/zh/language.refer

windows C++ 并行编程-C++ AMP 图形(二)

文中的"显存"还没有找到合适的中文翻译,它的英文名称是texture, 在应用开发者来看,texture是一个名词,在物理上指的是 GPU显存中一段连续的空间。 读取显存对象 可以使用 texture::operator[]、texture::operator() 运算符或 texture::get 方法从 texture 对象中读取。 两个运算符将返回一个值,而不是引用。 因此,你不能使用

Cygwinnbsp;amp;nbsp;Gitnbsp;中文支持

原文地址:Cygwin & Git 中文支持 作者:CICO李依洁 1.在下面的文件末尾添加一行。 C:cygwinhomecico.bash_profile export LESSCHARSET=latin1 ps:控制源代码(例如java文件)在Cygwin界面输出时,不做特殊处理(不要用UTF-8的规则将字节拼成字,utf-8用三个字节解释汉字,GBK用两个字节)。 2.打

HashTable amp;amp; HashMap

HashTable && HashMap HashTable:散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙。时间复杂度为O(1)。 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进

JAVA中Action层,nbsp;Service层amp;n…

modle层就是对应的数据库表的实体类。Dao层是使用了Mybatis连接数据库、操作数据库(增删改查)。Service层:引用对应的Dao数据库操作,在这里可以编写自己需要的代码(比如简单的判断)。Action层:引用对应的Service层,在这里结合Struts的配置文件,跳转到指定的页面,当然也能接受页面传递的请求数据,也可以做些计算处理。以上的Mybatis,Struts,都需要注入到

复旦微FMQL20SM全国产ARM+FPGA核心板,替代xilinx ZYNQ7020系列

FMQL20SM核心板一款全国产工业核心板。基于复旦微FMQL20S400M四核ARM Cortex-A7(PS端) + FPGA可编程逻辑资源(PL端)异构多核SoC处理器设计的全国产工业核心板,PS端主频高达1GHz。 核心板简介 FMQL20SM核心板是一款全国产工业核心板。基于复旦微FMQL20S400M四核ARM Cortex-A7(PS端) + FPGA可编程逻辑资源(PL

linux下打开tomcat时报错ERROR:amp;nb…

完整报错如下: ERROR: transport error 202: gethostbyname: unknown host  ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510) JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transpo

python matlotlib amp; 提取字符串中的中文

(1)python matlotlib 当连续做多张图时出现之前做的折线图均出现在最新的一张图上 此时需要加一条语句: plt.figure() 该句可以准备新的图板。。。 # 可视化mpl.rcParams['font.sans-serif'] = ['SimHei']mpl.rcParams['axes.unicode_minus'] = Falseplt.figure()#

什么是Google AMP

谷歌AMP应用于WordPress网站:AMP是什么 我们可能已经发现,在智能手机上阅读一些网页内容有的时候加载很快,但有的时候加载很慢,甚至是无穷无尽等待的。幸运的是,谷歌提供了自己的解决方案,那就是在2016年2月底推出的加速移动页面(AMP)项目,谷歌希望加快手机网页的加载时间,从而提高移动用户的阅读舒适度。 什么是谷歌AMP,直观的说法就是加速移动页,是由谷歌提供的一个开源项目