ZYNQ基于DMA的串口传图
小梅哥的这个ZYNQ开发板上的DDR3位于PS侧,PL侧想要使用DDR3作为缓存的话,得通过HP接口来与PS侧的DDR3控制进行通信。
本次实验在小梅哥OV5640工程的基础上,通过修改VDMA的S2MM端的模块而来的。
将VMDA的帧缓存区设为1,关闭帧同步的功能后,其实和DMA差不多。
一、需要自定义的ip核
这里列出的为自己写的IP核。小梅哥的工程里还用到了其它的自定义的IP核,这里就不列出了。
1、串口接收图像数据模块
该模块调用了之前写的串口8位接收模块,详情可点击查看。
此外,本模块还调用16位宽、深度为1024的带数据计数的普通FIFO核
该模块主要的思想就是将接收到的两个8位的数据拼接位1个16位的数据并存入FIFO中,
当存入的数据达到LINE_LENGTH(800)的时候,在收到从接口的准备信号时一次性写入VMDA中,再通过VMDA将数据写到DDR3中。
此外该模块在应用的时候要封装成带AXI4_Stream 接口的IP核,具体封装过程可网上找教程。
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: GDUT // Engineer: Lclone // // Create Date: 2023/02/07 20:38:34 // Design Name: // Module Name: Img_Rx // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module Img_Rx # (parameter RX_BAUD = 115200, parameter CLK_FQC = 50_000_000, parameter LINE_LENGTH = 800) ( input Uart_Rx, //--------------------------- input m_clk, input m_axis_aresetn, output [15:0] m_axis_tdata, output reg m_axis_tlast, input m_axis_tready, output reg m_axis_tvalid ); wire [7:0] Uart_Data; wire Rx_done; reg Rx_done_r; reg Rx_done_cnt; reg [15:0] Uart_Data_16; wire [9:0] fifo_data_count; reg [9:0] out_data_count; reg m_axis_tvalid_r; always @(posedge m_clk) Rx_done_r <= Rx_done; always @(posedge m_clk) m_axis_tvalid <= m_axis_tvalid_r; always @(posedge m_clk or negedge m_axis_aresetn) begin if(m_axis_aresetn == 0) Uart_Data_16 <= 0; else if(Rx_done == 1) Uart_Data_16 <= {Uart_Data_16[7:0],Uart_Data}; end always @(posedge m_clk or negedge m_axis_aresetn) begin if(m_axis_aresetn == 0) Rx_done_cnt <= 0; else if(Rx_done == 1) Rx_done_cnt <= Rx_done_cnt + 1'b1; else Rx_done_cnt <= Rx_done_cnt; end always @(posedge m_clk or negedge m_axis_aresetn) begin if(m_axis_aresetn == 0) m_axis_tvalid_r <= 0; else if(m_axis_tready == 1 & fifo_data_count >= LINE_LENGTH) m_axis_tvalid_r <= 1'b1; else if(fifo_data_count <= 1) m_axis_tvalid_r <= 0; else m_axis_tvalid_r <= m_axis_tvalid_r; end always @(posedge m_clk or negedge m_axis_aresetn) begin if(m_axis_aresetn == 0) out_data_count <= 0; else if(out_data_count == LINE_LENGTH - 1) out_data_count <= 0; else if(m_axis_tvalid_r & m_axis_tready) out_data_count <= out_data_count + 1'b1; else out_data_count <= out_data_count; end always @(posedge m_clk or negedge m_axis_aresetn) begin if(m_axis_aresetn == 0) m_axis_tlast <= 0; else if(out_data_count == LINE_LENGTH - 1) m_axis_tlast <= 1; else m_axis_tlast <= 0; end uart_byte_rx # ( .RX_BAUD (RX_BAUD), .CLK_FQC (CLK_FQC)) uart_byte_rx_inst ( .Clk (m_clk), .Rst_n (m_axis_aresetn), .Uart_rx (Uart_Rx), .Data (Uart_Data), .Rx_done (Rx_done) ); fifo_generator_0 fifo_generator_0_inst ( .clk(m_clk), // input wire clk .srst(~m_axis_aresetn), // input wire srst .din(Uart_Data_16), // input wire [15 : 0] din .wr_en(~Rx_done_cnt & Rx_done_r), // input wire wr_en .rd_en(m_axis_tvalid_r & m_axis_tready), // input wire rd_en .dout(m_axis_tdata), // output wire [15 : 0] dout .full(), // output wire full .empty(), // output wire empty .data_count(fifo_data_count) // output wire [9 : 0] data_count ); endmodule
2、模块仿真
(1)仿真激励
`timescale 1ns / 1ps module rx_img_test(); reg clk_50m; initial clk_50m <= 1; always #10 clk_50m <= ~clk_50m; reg rst_n; initial begin rst_n <= 0; #200 rst_n <= 1; end wire [15:0] m_axis_tdata; wire m_axis_tlast; wire m_axis_tready; wire m_axis_tvalid; wire [15:0] out_axis_tdata; wire out_axis_tlast; wire out_axis_tready; wire out_axis_tvalid; reg Uart_Rx; reg [ 7:0] Uart_Data; Img_Rx #( .RX_BAUD(2_000_000), .CLK_FQC(100_000_000), .LINE_LENGTH(16) ) Img_Rx_inst ( .Uart_Rx(Uart_Rx), // input wire Uart_Rx .m_clk(clk_50m), // input wire m_clk .m_axis_aresetn(rst_n), // input wire m_axis_aresetn .m_axis_tdata(m_axis_tdata), // output wire [15 : 0] m_axis_tdata .m_axis_tlast(m_axis_tlast), // output wire m_axis_tlast .m_axis_tready(m_axis_tready), // input wire m_axis_tready .m_axis_tvalid(m_axis_tvalid) // output wire m_axis_tvalid ); axis_data_fifo_0 axis_data_fifo_0_inst ( .s_axis_aresetn(rst_n), // input wire s_axis_aresetn .s_axis_aclk(clk_50m), // input wire s_axis_aclk .s_axis_tvalid(m_axis_tvalid), // input wire s_axis_tvalid .s_axis_tready(m_axis_tready), // output wire s_axis_tready .s_axis_tdata(m_axis_tdata), // input wire [15 : 0] s_axis_tdata .s_axis_tlast(m_axis_tlast), // input wire s_axis_tlast .m_axis_tvalid(out_axis_tvalid), // output wire m_axis_tvalid .m_axis_tready(out_axis_tready), // input wire m_axis_tready .m_axis_tdata(out_axis_tdata), // output wire [15 : 0] m_axis_tdata .m_axis_tlast(out_axis_tlast) // output wire m_axis_tlast ); initial begin Uart_Rx <= 1; Uart_Data <= 0; #200 repeat (256) begin data_deliver(Uart_Data); Uart_Data = Uart_Data + 1; end $stop; end task data_deliver; input [7:0] test_data; begin Uart_Rx <= 1'b0; #1000 Uart_Rx <= test_data[0]; #1000 Uart_Rx <= test_data[1]; #1000 Uart_Rx <= test_data[2]; #1000 Uart_Rx <= test_data[3]; #1000 Uart_Rx <= test_data[4]; #1000 Uart_Rx <= test_data[5]; #1000 Uart_Rx <= test_data[6]; #1000 Uart_Rx <= test_data[7]; #1000 Uart_Rx <= 1'b1; #1000; end endtask assign out_axis_tready = 1; endmodule
(2)仿真结果
可见该模块能够正确地将16个两字节的数据正确的输出,并在最后一个数据的位置基于一个tlast信号。
二、工程修改
打开小梅哥的ACZ7020的OV5640_LCD工程,然后将红框部分的模块删除,加入自定义的串口接收图像数据模块。
并修改下列IP核的参数
将频率修改为如下:
将帧缓存区设为1
Fsync Options选择None,关掉帧同步功能
在约束文件中,加入串口的管脚约束
在SDK中,将OV5640的初始化函数删除,将PS_IIC和OV5640库删除
同时也将PS_IIC和OV5640库的路径删除掉
然后就可以下载程序到开发板上了
三、上板验证
将程序下载进开发板,然后打开img2lcd软件,读取一个800*480大小的BMP文件,并按如下设置:
然后在输出的文件中进行修改
删除首行
删除末尾符号
使用软件的查找替换功能,将所有的0X删掉,并将","换为空格符,然后使用行操作里面的行合并去除掉每一行末尾的回车符。最后就得到传输的图像数据:
打开友善串口调试助手,将图像数据复制进去,打开串口端口,设置好波特率,然后发送,确保TX发送了768000个字节,否则图像会错位;确保底下绿色的字显示的波特率为115200,否则数据无法正确传输。
传输数据后,发现图像能够正确显示在LCD上
实验成功。
本随笔还有许多小细节没有给出,如果遇到问题,可以评论询问。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理