软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述
在前面的方案中,首先测试数据是ARM的PS端写入到PS DDR中,之后,PS控制FDMA的帧缓存,实现帧缓存地址切换,显示测试图形。
主要都是讲解PL数据如何共享给PS,本方案的目标在于演示如何把PS部分的数据写到PS DDR后,共享给PL,本文通过PS写测试图像数据到DDR,然后通知PL的FDMA读取内存中的测试数据,通过显示器显示,测试图形。
本文实验目的: 1:掌握uifdma_dbuf的地址空间分配方法 2:掌握PL侧的uifdma_dbuf从PS DDR读取数据的方法 3:通过AXI-GPIO实现对uifdma_dbuf的帧缓存控制 2系统框图
3硬件电路分析硬件接口和子卡模块请阅读“附录1” 配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。 4搭建SOC系统工程
4.1PL图形化编程
以上代码中,PS写入到DDR数据后,通过AXI-GPIO控制uifdma_dbuf读通道的帧计数器,实现内存 地址的切换,uifma_dbuf在本方案中,以视频模式工作,v_tc ip提供了视频时序,数据根据视频时序要求,不断从AXI-GPIO设置好的缓存号中读取出来,通过HDMI屏幕显示。 本方案和“06读取SD卡图片方案(VDMA)”原理一样,都是从SD卡中读取测试图片,并把 数据写入到DDR中。通过PL读取数据,显示图片到显示器。 但是使用uifdma_dbuf,具有更加高效,简洁的优势,此外本方案更加重视展示通过uifdma_dbuf如何和PSDDR共享数据。 下面具体看下关键几个IP的参数设置 1:uifdma_dbuf设置由于输出数据是视频数据流形式,所以需要使能视频传输功能,这里也只使用到了读通道,所以写通道也不需要使能。 一般对于视频流方案,设置3帧缓存就够用。RBaseaddr缓存的基地址只要设置合适的值即可,这里设置0x08000000 = 128MB,这样保留了低128MB给应用程序使用。 由于一幅图片的大小为1280*720*4= 3600Bytes 因此RDsizebits设置每个缓存的大小,2^23次方=8MBYTE够用。 在SDK中的地址空间分配对应如下: #define BUF_BASE_SIZE 0x08000000
#define BUF_RANG_SIZE 0x800000
#define BUF1_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*0;
#define BUF2_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*1;
#define BUF3_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*2;
2:uiFDMA设置Fdma的数据位宽可以设置128这样效率最高。
3:AXI Interconnect设置设置FIFO可以增加数据的吞吐能力
4.2设置地址分配需要注意uifdma_dbuf的axi-lite接口地址,这个地址我们会在SDK 代码中用到读寄存器。
4.3添加PIN约束1:选中PROJECT MANAGERà Add SourcesàAdd or create constraints,添加XDC约束文件。
2:打开提供例程,复制约束文件中的管脚约束到XDC文件,或者查看原理图,自行添加管脚约束,并保存。 以下是添加配套工程路径下已经提供的pin脚文件。配套工程的pin脚约束文件在uisrc/04_pin路径 4.4编译并导出平台文件1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。 2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。 3:生成Bit文件。 4:导出到硬件: FileàExport HardwareàInclude bitstream 5:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
5搭建Vitis-sdk工程创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 5.1创建SDK Platform工程
勾选对于FAT格式文件系统的支持
5.2创建sd_img_read测试工程
6程序分析
6.1sd_img_test.c主程序
#include"xil_exception.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "sys_intr.h"
#include "pl_intr.h"
#include "sleep.h"
#include "xsdps.h"
#include "ff.h"
#include "xgpio.h"
#include "bmp.h"
extern XScuGic Intc;
#define VIDEO_OUT_HSIZE 1280*4
#define VIDEO_OUT_STRIDE 1280*4
#define VIDEO_OUT_VSIZE 720
#define IMG_SIZE VIDEO_OUT_HSIZE*VIDEO_OUT_VSIZE
#define BUF_BASE_SIZE 0x08000000
#define BUF_RANG_SIZE 0x800000
#define BUF1_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*0;
#define BUF2_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*1;
#define BUF3_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*2;
extern volatile fdma_buf_get *fdma_bufn;
extern volatile int fdman;
volatile int fdma_buf_set_read;
u8 *UIFDMA_DBUF[IMG_SIZE] __attribute__ ((__aligned__(32)));
XGpio uifdma_dbuf_ctr;
static FATFS SD_Dev; // File System instance
char *SD_Path = "0:/"; // string pointer to the logical drive number
//Initialize SD
int SD_init()
{
FRESULT result;
//-----------------------mount dev-----------------------------------------------
result = f_mount(&SD_Dev,SD_Path, 0);
if (result != 0) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
void init_intr_sys(void)
{
Init_Intr_System(&Intc); // initial DMA interrupt system
pl_intr_init(&Intc);
Setup_Intr_Exception(&Intc);
}
int main()
{
//关闭数据cache
Xil_DCacheDisable();
// 设置读取uifdma_dbuf 写通道的帧计数器,让指针指向fdman变量地址
fdma_bufn = &fdman;
// 设置内存地址
UIFDMA_DBUF[0] = (u8*)BUF1_ADDR;
UIFDMA_DBUF[1] = (u8*)BUF2_ADDR;
UIFDMA_DBUF[2] = (u8*)BUF3_ADDR;
//初始化内存
memset(UIFDMA_DBUF[0], 0x00, IMG_SIZE);
memset(UIFDMA_DBUF[1], 0x00, IMG_SIZE);
memset(UIFDMA_DBUF[2], 0x00, IMG_SIZE);
//初始化GPIO,该GPIO用于控制缓存地址切换
XGpio_Initialize(&uifdma_dbuf_ctr, XPAR_UIFDMA_BUF_CTR_DEVICE_ID);
XGpio_SetDataDirection(&uifdma_dbuf_ctr, 1, 0x0);
XGpio_DiscreteWrite(&uifdma_dbuf_ctr, 1, 0x0);
//初始化TF卡
SD_init();
//读取图片数据到内存中
bmp_read((u8 *)"0001.bmp", UIFDMA_DBUF[0],VIDEO_OUT_STRIDE);
bmp_read((u8 *)"0002.bmp", UIFDMA_DBUF[1],VIDEO_OUT_STRIDE);
bmp_read((u8 *)"0003.bmp", UIFDMA_DBUF[2],VIDEO_OUT_STRIDE);
//确保数据都刷入内存中
Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[0], IMG_SIZE);
Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[1], IMG_SIZE);
Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[2], IMG_SIZE);
xil_printf("UIFDMA DMA Generic Video start! \r\n");
//read image from sd to ddr buffer
//设置中断
init_intr_sys();
while(1)
{
//延迟一帧设置uifdma_dbuf的缓存
fdma_buf_set_read = (fdma_bufn->rd_buf+1)%3;
//set uifdma_dbuf read buffer point
XGpio_DiscreteWrite(&uifdma_dbuf_ctr, 1, fdma_buf_set_read);
sleep(1);
}
|
以上主函数中,通过阅读注释即可一直到代码的功能,关键部分在while循环中,通过AXI-GPIO控制uifdma_dbuf 读通道的帧指针切换,读取PS的DDR图像数据。 另外需要注意,当发送数据到DDR的时候,必须用Xil_DCacheFlushRange()函数把cache中的数据都能写入到PS DDR中,否则读取会错误。 同理如果是PL写数据到PS,从PS中拿数据那么就需要使用Xil_DCacheInvalidateRange,确保PL的数据全部写入到了PS DDR。 6.2pl_intr.c主程序
#indlude "pl_intr.h"
#define FDMA_DBUF_BASE_ADDR 0x43C00000
volatile fdma_buf_get *fdma_bufn;
u32 fdman;
void PS_RX_intr_Handler(void *param)
{
fdman = (Xil_In32((UINTPTR)FDMA_DBUF_BASE_ADDR));
fdma_bufn = &fdman;
}
|
每次uifdma_dbuf中断后,读取缓存地址,由于读缓存保存在高数据位,因此通过以下结构体可以更快速度访问rd_buf的帧号。 typedef struct fdma_buf_get
{
u16 wr_buf;
u16 rd_buf;
}fdma_buf_get;
|
如果有不清楚的,可以看下uifdma_dbuf FPGA中的源码: always @(*)
if(axi_awaddr[3:2] == 2'd0)
reg_data_out[31 : 0] <= {8'd0,fdma_rbuf_irq,8'd0,fdma_wbuf_irq};
else
reg_data_out <= reg_data_out;
// Output register or memory read data
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rdata <= 0;
end
else
begin
// When there is a valid read address (S_AXI_ARVALID) with
// acceptance of read address by the slave (axi_arready),
// output the read dada
if (slv_reg_rden) begin
axi_rdata <= reg_data_out; // register read data
end
end
end
always @(posedge S_AXI_ACLK) fdma_wirq_r <= fdma_wirq;
always @(posedge S_AXI_ACLK)begin
if( S_AXI_ARESETN == 1'b0)
fdma_wbuf_irq <= 0;
else if(fdma_wirq_r == 1'b0 & fdma_wirq == 1'b1)
fdma_wbuf_irq <= fdma_wbuf;
end
always @(posedge S_AXI_ACLK) fdma_rirq_r <= fdma_rirq;
always @(posedge S_AXI_ACLK)begin
if( S_AXI_ARESETN == 1'b0)
fdma_rbuf_irq <= 0;
else if(fdma_rirq_r == 1'b0 & fdma_rirq == 1'b1)
fdma_rbuf_irq <= fdma_rbuf;
end
|
7液晶屏LVDS方案演示
7.1硬件准备复制路径soc_prj/uisrc/06_doc/testimage路径下的测试图片到SD卡,并且插入到开发中。
7.2实验结果
|