项目:基于 ZYNQ 的 IMX2221 摄像头实时视频流采集传输
章节:写DMA
本章目的:添加写DMA,将Bayer2rgb模块出来的每帧1920 * 1080个像素存入内存中,中间使用一个fifo进行缓冲
本章需要一些前置知识
- AXI4总线的工作原理
https://blog.youkuaiyun.com/qq_44406549/article/details/125623786 - 如何生成DMA IP
https://blog.youkuaiyun.com/qq_44406549/article/details/125623900 - 如何编写属于自己的DMA
https://blog.youkuaiyun.com/qq_44406549/article/details/125624097
下面正式开始本章内容
1. 创建DMA IP 并且修改 burst len = 256 , axi data width = 64 ,base address = 0x2000000
这部分见上面的博客,就不再重复
2. DMA时序绘制
介绍几个关键的信号
- bayer2rgb_rst :这个是上一章中bayer2rgb模块的复位信号,只有当这个信号出现下降沿我们的系统才开始真正采集数据,所以这个信号的下降沿作为了工作开始的标志
- work_on_flag:工作开始信号,当接收到ayer2rgb_rst下降沿之后一直拉高
- detect_fv:作为检测一帧开始的标志,因为如果我们直接检测hv有效就写入内存,那么绝对会造成存入内存的并不是一帧图片,所以设置这个信号保证开始存入的第一个像素就是一帧开始的第一个像素
- axi_busy:axi busy信号 信号在burst_start == 1 && axi_busy == 0的情况下拉高,在axi_wlast == 1 && axi_wvalid == 1 && axi_wready == 1 的情况下拉低
- burst_start :开始突发信号,在axi_busy == 0 && rd_data_count >=254拉高,在axi_busy == 1 拉低,在图中是INIT_AXI_TXN信号,把它换成burst_start
- 其他自己写吧
2. ila抓的结果
3. 最终结果居然出现了奇奇怪怪的错误
fifo的读信号拉高了,并且读出来了数据,但是居然count读计数器还在增加,按理说读时钟我们给的200M,写时钟才74.25,写数据32bit,读数据64bit,怎么算同时读写都应该读计数器减少,有哪位知道告诉我一下
但是最后莫名其妙的又好了,我傻了,我啥也没干,就搞了一天,实在太累了出去健了个身,回来好了。欢迎大家讨论这个问题
4. 最后最后给出代码
//--------------------------------------------------------------//
//----------------------parameter define------------------------//
//--------------------------------------------------------------//
reg [7:0] burst_cnt;
reg work_on_flag;
reg detect_fv;
wire fifo_wr_en;
wire [31:0] fifo_wr_data;
wire [10:0] rd_data_count;
wire full,empty;
reg burst_start;
wire fifo_rd_en;
wire [63:0] fifo_rd_data;
reg axi_busy;
//--------------------------------------------------------------//
//----------------------parameter define------------------------//
//--------------------------------------------------------------//
//--------------------------------------------------------------//
//--------------------------logic RTL---------------------------//
//--------------------------------------------------------------//
always @(posedge pixel_clk) begin
if(M_AXI_ARESETN == 1'b0) begin
work_on_flag <= 1'b0;
end
else if (init_txn_pulse == 1'b1) begin
work_on_flag <= 1'b1;
end
end
always @(posedge pixel_clk) begin
if(M_AXI_ARESETN == 1'b0) begin
detect_fv <= 1'b0;
end
else if (work_on_flag == 1'b1 && fv == 1'b1) begin
detect_fv <= 1'b1;
end
end
assign fifo_wr_data = {8'd0,pixel_rgb};
assign fifo_wr_en = detect_fv & hv;
//fifo 2 clock domain switch
asfifo_w32x4096_r64x2048 frame_buffer (
.wr_clk(pixel_clk), // input wire wr_clk
.rd_clk(M_AXI_ACLK), // input wire rd_clk
.din(fifo_wr_data), // input wire [31 : 0] din
.wr_en(fifo_wr_en), // input wire wr_en
.rd_en(fifo_rd_en), // input wire rd_en
.dout(fifo_rd_data), // output wire [63 : 0] dout
.full(full), // output wire full
.empty(empty), // output wire empty
.rd_data_count(rd_data_count) // output wire [10 : 0] rd_data_count
);
//dma write channel
assign fifo_rd_en = axi_wvalid & M_AXI_WREADY;
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) begin
burst_start <= 1'b0;
end
else if (rd_data_count >='d254 && axi_busy == 1'b0) begin
burst_start <= 1'b1;
end
else begin
burst_start <= 1'b0;
end
end
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) begin
axi_awvalid <= 1'b0;
end
else if (axi_awvalid == 1'b1 && M_AXI_AWREADY == 1'b1) begin
axi_awvalid <= 1'b0;
end
else if (burst_start == 1'b1 && axi_busy == 1'b0) begin
axi_awvalid <= 1'b1;
end
end
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) begin
axi_awaddr <= 'd0;
end
else if (M_AXI_AWREADY == 1'b1 && axi_awvalid == 1'b1 && axi_awaddr == 'd8292352) begin
axi_awaddr <= 'd0;
end
else if (M_AXI_AWREADY == 1'b1 && axi_awvalid == 1'b1) begin
axi_awaddr <= axi_awaddr + 'd2048;
end
end
always @(posedge M_AXI_ACLK) begin
if (M_AXI_ARESETN == 0)
axi_busy <= 1'b0;
else if(axi_wlast == 1'b1 && axi_wvalid == 1'b1 && M_AXI_WREADY == 1'b1)
axi_busy <= 1'b0;
else if(burst_start == 1'b1 && axi_busy == 1'b0)
axi_busy <= 1'b1;
end
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) begin
axi_wvalid <= 1'b0;
end
else if (M_AXI_WREADY == 1'b1 && axi_wvalid == 1'b1 && burst_cnt == 'd255) begin //burst end
axi_wvalid <= 1'b0;
end
else if (M_AXI_AWREADY == 1'b1 && axi_awvalid == 1'b1) begin
axi_wvalid <= 1'b1;
end
end
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) begin
burst_cnt <='d0;
end
else if (M_AXI_WREADY == 1'b1 && axi_wvalid == 1'b1 && burst_cnt == 'd255) begin
burst_cnt <= 'd0;
end
else if (M_AXI_WREADY == 1'b1 && axi_wvalid == 1'b1) begin
burst_cnt <= burst_cnt + 1'b1;
end
end
always @* begin
if(M_AXI_WREADY == 1'b1 && axi_wvalid == 1'b1 && burst_cnt == 'd255) begin
axi_wlast <= 1'b1;
end
else begin
axi_wlast <= 1'b0;
end
end
always @* begin
axi_wdata = fifo_rd_data;
end
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) begin
axi_bready <= 1'b0;
end
else begin
axi_bready <= 1'b1;
end
end
wire [255:0] probe0;
assign probe0 = {
INIT_AXI_TXN,
work_on_flag,
detect_fv,
fv,hv,
axi_wdata,
axi_wvalid,
axi_awvalid,
M_AXI_AWREADY,
M_AXI_WREADY,
axi_awaddr,
burst_cnt,
full,
fifo_rd_en,
fifo_wr_en,
rd_data_count
};
ila_0 ila_inst (
.clk(M_AXI_ACLK), // input wire clk
.probe0(probe0) // input wire [255:0] probe0
);
// User logic ends
//--------------------------------------------------------------//
//--------------------------logic RTL---------------------------//
//--------------------------------------------------------------//