Zedboard & Zynq 图像采集 视频开发 (三) AXI4总线读写DDR

时间:2024-03-15 10:42:22

上一篇讲到了通过Zynq内部FPGA采集ov7725摄像头的图像数据,并将RAW8视频数据通过双线性插值法恢复为RGB888视频格式,这一篇的内容就是将RBG888视频数据通过PS的HP端口传送到DDR3进行视频缓存,然后再读出,进行VGA视频显示

AMBA协议简介

AMBA 协议是用于连接和管理片上系统 (SoC) 中功能模块的开放标准和片上互连规范。
它有助于首次开发带有大量控制器和外设的多处理器设计。
AMBA 通过使用 AXI、AHB、APB 和 ATB 的规范对 SoC 模块的共同主干进行定义,这有助于设计的重复使用。
AMBA 4 是最新增添到 AMBA 系列中的规范,增加了三个新接口协议:AXI4 有助于最大化性能和能效;AXI4-Lite 和 AXI4-Stream 是 FPGA 中实现的理想选择。
AMBA 4 规范在 AMBA 3 规范的基础上另外新增了三个接口协议。
AXI4
AXI4 协议是对 AXI3 的更新,在用于多个主接口时,可提高互连的性能和利用率。它包括以下增强功能:
对于突发长度,最多支持 256 位
发送服务质量信号
支持多区域接口
AXI4-Lite
AXI4-Lite 是 AXI4 协议的子协议,适用于与组件中更简单且更小的控件寄存器式的接口通信。AXI4-Lite 接口的主要功能如下:
所有事务的突发长度均为 1
所有数据存取的大小均与数据总线的宽度相同
不支持独占访问
AXI4-Stream
AXI4-Stream 协议可用于从主接口到辅助接口的单向数据传输,可显著降低信号路由速率。该协议的主要功能如下:
使用同一组共享线支持单数据流和多数据流
在同一互连内支持多个数据宽度
FPGA 中实现的理想选择

ZYNQ SOC
Zynq内部 PL与PS数据交互,主要使用了AXI4 AXI4-Lite总线协议,AXI4主要进行PL,PS之间批量数据交互,AXI4-Lite总线主要用于控制协议以及小量数据交互。由于FPGA采集到的摄像头视频数据要传送到PS部分的DDR,数据量较大,则可以直接通过AXI4总线将数据传送到PS部分,Xilinx的开发工具提供DMA,VDMA等IP Core可以很方便的完成这类任务,而且功能完善,缺点是如果发生问题,调试不太方便,毕竟对于用户来说就是个黑盒子,本设计没有使用IP,而是写了一个简单的S2MM和MM2S的HDL

BLOCK DESIGN 

Zedboard & Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
PS部分用到了一个GP0口,一个HP0口,一个HP2口。GP口用于控制VDMA,HP口用于视频数据传输。看到这,也许有人会问,
1.为什么要用两个HP口,用一个不也行吗
用一个HP口确实可以,这里面只是为了区分清楚数据流向,所以用了两个HP口,一个只用于写,一个只用于读
2.为什么不用HP0和HP1,而是用HP0和HP2
还是那句话,用HP0和HP1确实也可以,但是在PS内部,HP0和HP1在通往DDR的路上是公用一个端口,HP2和HP3也是公用一个端口,所以也是为了区分清楚数据流向(或者可以说笔者有洁癖)所以才分开使用
3.为什么不直接通过HP端口读写,还要加入interconnect做什么
由于ps部分的HP口是AXI3协议,直接读写也没问题,但是为了规范,则通过interconnect将AXI3转换为AXI4
4.为什么使用axi_apb_bridge
axi_lite总线读写稍微有点儿小麻烦,所以转换成比较简单的apb总线

S2MM VDMA设计

block design中axi_interconnect_1 slave端口设置为WRITE ONLY 模块axi4_s2mm_video_dma通过这个端口对DDR进行写操作。
写操作流程图:
Zedboard & Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
写操作burst时序图:
Zedboard & Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
axi4_s2mm_video_dma模块就是按照时序图来实现的,下面对此模块进行一下讲述

模块端口如下:
Zedboard & Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
下面是参数部分:

[plain] view plaincopy
  1. parameter [31:0]  APB_BASE_ADDR  = 32'h70000000,  
  2. parameter [31:0]  DMA_DEST_ADDR0 = 32'h1c000000,  
  3. parameter [31:0]  DMA_DEST_ADDR1 = 32'h1c200000,  
  4. parameter [31:0]  DMA_DEST_ADDR2 = 32'h1c400000,  
  5. parameter [8:0]   C_DATA_WIDTH = 9'd32,  
  6. parameter [12:0]  STRIDE       = 13'd1920,  
  7. parameter [12:0]  WIDTH        = 13'd1920,  
  8. parameter [12:0]  HEIGHT       = 13'd1080  
APB_BASE_ADDR : apb slave地址
DMA_DEST_ADDR0 : 传送目标地址0
DMA_DEST_ADDR1 : 传送目标地址1
DMA_DEST_ADDR2 : 传送目标地址2

端口包括 AXI4总线信号,APB总线信号,video信号
APB总线的使用:通过简单的修改代码,可以让ARM控制VDMA进行一帧图像的传输,传输完成以后自动停止,并在IRQ_F2P_pin引脚产生一个中断信号,此信号可以连接到PS的中断控制器,PS在接收到中断以后,向中断寄存器写1就可清除中断标志。
但Zedboard ov7725工程中并没有使用单帧传输模式,而是连续传输,如
[plain] view plaincopy
  1. reg [1:0] DMA_WRITE_STATUS;  
  2. assign IRQ_F2P_pin = DMA_WRITE_STATUS[1];  
  3. // write dma busy status configuration  
  4. always @(posedge M_APB_PCLK_pin)  
  5. begin  
  6.    if (!M_APB_PRESETN_pin) begin  
  7.       DMA_WRITE_STATUS[0] <= 1'b0;  
  8.    end  
  9.    else if(dma_frame_write_end) begin  
  10.       DMA_WRITE_STATUS[0] <= 1'b0;  
  11.    end  
  12.    else if(M_APB_PSEL_pin && M_APB_PWRITE_pin && M_APB_PENABLE_pin) begin  
  13.       if (M_APB_PADDR_pin==APB_BASE_ADDR && M_APB_PWDATA_pin[0] && !DMA_WRITE_STATUS[0]) begin  
  14.          DMA_WRITE_STATUS[0] <= 1'b1;  
  15.       end  
  16.    end  
  17. end  


[plain] view plaincopy
  1. wire dma_write_start;  
  2. reg process_start_pre;  
  3. always @(posedge v_video_clk)     
  4. begin  
  5.     if(!axi_rstn)  
  6.     begin  
  7.         v_video_data_r <= 24'd0;  
  8.         v_timing_vsync_r <= 1'b0;  
  9.         v_timing_hsync_r <= 1'b0;  
  10.         v_timing_active_video_r <= 1'b0;  
  11.         process_start <= 1'b0;  
  12.         //process_start_pre <= 1'b0;  
  13.         process_start_pre <= 1'b1;  
  14.     end  
  15.     else  
  16.     begin  
  17.         v_video_data_r <= v_video_data_i;  
  18.         v_timing_vsync_r <= v_timing_vsync_i;  
  19.         v_timing_hsync_r <= v_timing_hsync_i;  
  20.         v_timing_active_video_r <= v_timing_active_video_i;  
  21.         if(dma_write_start)  
  22.             process_start_pre <= 1'b1;  
  23.         if((~v_timing_vsync_r) && v_timing_vsync_i && process_start_pre)begin  
  24.             process_start <= 1'b1;  
  25.             //process_start_pre <= 1'b0;  
  26.         end  
  27.         else if(dma_frame_write_end)  
  28.             process_start <= 1'b0;  
  29.     end  
  30. end  
[plain] view plaincopy
  1. cross_clk cross_clk1  
  2.    (  
  3.       .clkin   (axi_clk),  
  4.       .din     (frame_last),  
  5.       .clkout  (v_video_clk),  
  6.       .dout    (dma_frame_write_end)  
  7.    );  

[plain] view plaincopy
  1. cross_clk cross_clk2  
  2.    (  
  3.       .clkin   (M_APB_PCLK_pin),  
  4.       .din     (DMA_WRITE_STATUS[0]),  
  5.       .clkout  (v_video_clk),  
  6.       .dout    (dma_write_start)  
  7.    );  

如果想使用单帧模式,可以把上面代码中注释的部分process_start_pre信号稍加修改即可。

在VIDEO信号中,真正起作用的只有3个信号
v_timing_vsync_i 此信号的上升沿代表一帧数据开始,这个信号可以用来做AXI写操作开始信号
v_timing_active_video_i 视频数据有效信号,只有有效的视频信号才会被传输
v_video_data_i 24bit RGB888视频信号

在视频信号与AXI信号之间加入一个位宽32bit,深度128的fifo进行数据缓存,视频数据写fifo,AXI总线读fifo。在fifo的应用上面,有一点是需要注意的,那就是rd_en读使能信号,rd_en拉高,并且在读时钟的下一个上升沿fifo内的数据才会出现在dout信号线上。根据AXI协议规范,为了防止产生死锁,WVALID不能等待WREADY,而WREADY可以等待WVALID,这样便会在写操作的时候出现一个问题,就是WVALID拉高,但是此时WREADY不一定是拉高的,而WREADY又控制着fifo rd_en何时拉高,笔者的解决办法就是,在WVALID拉高以后,rd_en拉高一个时钟周期然后拉低,这样在下一个读时钟的上升沿,fifo内的数据就出现在dout信号线上了,然后等待着WREADY,具体实现可以看我的代码,信号stall就是做这个用处的。

还有一个需要注意的地方,由于这个是个人写的简单VDMA,burst长度是固定的为16,所以传输数据的长度必须是16的整数倍,而且传输位宽是32bit。

别的就不说了,就是用状态机来实现AXI时序罢了,直接上代码
[plain] view plaincopy
  1. /*-----------------------------------------------------------------------  
  2.   
  3. CONFIDENTIAL IN CONFIDENCE  
  4. This confidential and proprietary software may be only used as authorized  
  5. by a licensing agreement from EEPROM .  
  6. In the event of publication, the following notice is applicable:  
  7. Copyright (C) 2013-20xx EEPROM Corporation  
  8. The entire notice above must be reproduced on all authorized copies.  
  9. Author              :       EEPROM  
  10. Technology blogs    :       http://blog.csdn.net/zhangyu_eeprom  
  11. Email Address       :       [email protected]  
  12. Filename            :       axi4_s2mm_video_dma.v  
  13. Data                :       2014-05-20  
  14. Description         :       axi4_s2mm_video_dma.  
  15. Modification History    :  
  16. Data            By          Version         Change Description  
  17. =========================================================================  
  18. -------------------------------------------------------------------------  
  19.   
  20.         ------     ------    ------|   ------|      /-------\     
  21.        |          |          |     |   |     |     /         \      /-\     /-\  
  22.        |------    |------    |-----|   |-----|    /           \    /   \   /   \  
  23.        |          |          |         | \        \           /   /     \_/     \  
  24.        |------    |------    |         |  \        \         /   /               \  
  25.                              |         |   \        \-------/  
  26. -----------------------------------------------------------------------*/     
  27.   
  28.   
  29. module axi4_s2mm_video_dma #(  
  30.    parameter [31:0]  APB_BASE_ADDR  = 32'h70000000,  
  31.    parameter [31:0]  DMA_DEST_ADDR0 = 32'h1c000000,  
  32.    parameter [31:0]  DMA_DEST_ADDR1 = 32'h1c200000,  
  33.    parameter [31:0]  DMA_DEST_ADDR2 = 32'h1c400000,  
  34.    parameter [8:0]   C_DATA_WIDTH = 9'd32,  
  35.    parameter [12:0]  STRIDE       = 13'd1920,  
  36.    parameter [12:0]  WIDTH        = 13'd1920,  
  37.    parameter [12:0]  HEIGHT       = 13'd1080  
  38.    )  
  39.    (  
  40.    input             axi_clk,  
  41.    input             axi_rstn,  
  42.    output            IRQ_F2P_pin,  
  43.             
  44.    input             M_APB_PCLK_pin,  
  45.    input             M_APB_PRESETN_pin,  
  46.    input   [31:0]    M_APB_PADDR_pin,  
  47.    input             M_APB_PSEL_pin,  
  48.    input             M_APB_PENABLE_pin,  
  49.    input             M_APB_PWRITE_pin,  
  50.    input   [31:0]    M_APB_PWDATA_pin,  
  51.    output            M_APB_PREADY_pin,  
  52.    output [31:0]     M_APB_PRDATA_pin,  
  53.    output            M_APB_PSLVERR_pin,  
  54.      
  55.    input            v_video_clk,        
  56.    input            v_timing_hsync_i,  
  57.    input            v_timing_vsync_i,  
  58.    input            v_timing_hblank_i,  
  59.    input            v_timing_vblank_i,  
  60.    input            v_timing_active_video_i,  
  61.    input   [23:0]   v_video_data_i,  
  62.       
  63.    input             S_AXI_AWREADY_pin,  
  64.    input             S_AXI_BVALID_pin,  
  65.    input             S_AXI_WREADY_pin,  
  66.    input   [1:0]     S_AXI_BRESP_pin,  
  67.    input   [5:0]     S_AXI_BID_pin,  
  68.    output reg        S_AXI_AWVALID_pin,  
  69.    output            S_AXI_BREADY_pin,  
  70.    output            S_AXI_WLAST_pin,  
  71.    output reg        S_AXI_WVALID_pin,  
  72.    output [1:0]      S_AXI_AWBURST_pin,  
  73.    output [1:0]      S_AXI_AWLOCK_pin,  
  74.    output [2:0]      S_AXI_AWSIZE_pin,  
  75.    output [2:0]      S_AXI_AWPROT_pin,  
  76.    output reg [31:0] S_AXI_AWADDR_pin,  
  77.    output reg [C_DATA_WIDTH-1:0]     S_AXI_WDATA_pin,  
  78.    output [3:0]      S_AXI_AWCACHE_pin,  
  79.    output [3:0]      S_AXI_AWLEN_pin,  
  80.    output [3:0]      S_AXI_AWQOS_pin,  
  81.    output [7:0]      S_AXI_WSTRB_pin,  
  82.    output [5:0]      S_AXI_AWID_pin,  
  83.    output [5:0]      S_AXI_WID_pin  
  84.    );  
  85. /******************************************/     
  86. reg [23:0]   v_video_data_r;  
  87. reg          v_timing_vsync_r;  
  88. reg          v_timing_active_video_r;  
  89. reg          process_start; // first vsync rising  
  90. reg          [1:0]frame_num;  
  91. wire         line_last;  
  92. wire         frame_last;  
  93. reg          frame_last_r;  
  94. reg          [12:0]hcount;  
  95. reg          [12:0]vcount;  
  96. reg          [4:0]axi_write_num;  
  97. reg          axi_write_ok;  
  98. reg          axi_addr_ok;  
  99. reg          [31:0]prev_line_start;  
  100. wire         stall;  
  101. reg          [4:0]read_fifo_num;  
  102. reg          fifo_rd_ok;  
  103. wire         dma_frame_write_end;  
  104. wire         dma_line_write_end;  
  105. reg          v_timing_hsync_r;  
  106. reg          [12:0]write_fifo_num;  
  107. /************fifo**************/  
  108. reg   fifo_wr_en;  
  109. wire  fifo_rd_en;  
  110. wire  fifo_full;  
  111. wire  fifo_empty;  
  112. wire  fifo_valid;  
  113. wire  [9:0] fifo_rd_data_count;  
  114. wire  [9:0] fifo_wr_data_count;  
  115. wire  [31:0] fifo_dout;  
  116. /******************************/  
  117. /******************************/  
  118.   
  119. /*  
  120. * APB bus  
  121. */  
  122. reg [1:0] DMA_WRITE_STATUS;  
  123. assign IRQ_F2P_pin = DMA_WRITE_STATUS[1];  
  124. // write dma busy status configuration  
  125. always @(posedge M_APB_PCLK_pin)  
  126. begin  
  127.    if (!M_APB_PRESETN_pin) begin  
  128.       DMA_WRITE_STATUS[0] <= 1'b0;  
  129.    end  
  130.    else if(dma_frame_write_end) begin  
  131.       DMA_WRITE_STATUS[0] <= 1'b0;  
  132.    end  
  133.    else if(M_APB_PSEL_pin && M_APB_PWRITE_pin && M_APB_PENABLE_pin) begin  
  134.       if (M_APB_PADDR_pin==APB_BASE_ADDR && M_APB_PWDATA_pin[0] && !DMA_WRITE_STATUS[0]) begin  
  135.          DMA_WRITE_STATUS[0] <= 1'b1;  
  136.       end  
  137.    end  
  138. end  
  139. // write dma interrupt configuration, write '1' to clear interrupt  
  140. always @(posedge M_APB_PCLK_pin)  
  141. begin  
  142.    if (!M_APB_PRESETN_pin) begin  
  143.       DMA_WRITE_STATUS[1] <= 1'b0;  
  144.    end  
  145.    else if(dma_frame_write_end) begin  
  146.       DMA_WRITE_STATUS[1] <= 1'b1;  
  147.    end  
  148.    else if(M_APB_PSEL_pin && M_APB_PWRITE_pin && M_APB_PENABLE_pin) begin  
  149.       if (M_APB_PADDR_pin==APB_BASE_ADDR && M_APB_PWDATA_pin[1] && DMA_WRITE_STATUS[1]) begin  
  150.          DMA_WRITE_STATUS[1] <= 1'b0;  
  151.       end  
  152.    end  
  153. end  
  154. //------------------------------------------------------  
  155. // APB output  
  156. //------------------------------------------------------  
  157. assign M_APB_PRDATA_pin = {28'h0000,frame_num,DMA_WRITE_STATUS};  
  158. assign M_APB_PREADY_pin = 1'b1;  
  159. assign M_APB_PSLVERR_pin = 1'b0;  
  160.      
  161. /*******************************************/     
  162. wire dma_write_start;  
  163. reg process_start_pre;  
  164. always @(posedge v_video_clk)     
  165. begin  
  166.     if(!axi_rstn)  
  167.     begin  
  168.         v_video_data_r <= 24'd0;  
  169.         v_timing_vsync_r <= 1'b0;  
  170.         v_timing_hsync_r <= 1'b0;  
  171.         v_timing_active_video_r <= 1'b0;  
  172.         process_start <= 1'b0;  
  173.         //process_start_pre <= 1'b0;  
  174.         process_start_pre <= 1'b1;  
  175.     end  
  176.     else  
  177.     begin  
  178.         v_video_data_r <= v_video_data_i;  
  179.         v_timing_vsync_r <= v_timing_vsync_i;  
  180.         v_timing_hsync_r <= v_timing_hsync_i;  
  181.         v_timing_active_video_r <= v_timing_active_video_i;  
  182.         if(dma_write_start)  
  183.             process_start_pre <= 1'b1;  
  184.         if((~v_timing_vsync_r) && v_timing_vsync_i && process_start_pre)begin  
  185.             process_start <= 1'b1;  
  186.             //process_start_pre <= 1'b0;  
  187.         end  
  188.         else if(dma_frame_write_end)  
  189.             process_start <= 1'b0;  
  190.     end  
  191. end  
  192. cross_clk cross_clk1  
  193.    (  
  194.       .clkin   (axi_clk),  
  195.       .din     (frame_last),  
  196.       .clkout  (v_video_clk),  
  197.       .dout    (dma_frame_write_end)  
  198.    );  
  199. cross_clk cross_clk2  
  200.    (  
  201.       .clkin   (M_APB_PCLK_pin),  
  202.       .din     (DMA_WRITE_STATUS[0]),  
  203.       .clkout  (v_video_clk),  
  204.       .dout    (dma_write_start)  
  205.    );  
  206. always @(posedge v_video_clk) begin  
  207.     if(!axi_rstn)  
  208.         write_fifo_num   <= 13'h0;  
  209.     else if(fifo_wr_en && (write_fifo_num != (WIDTH - 1)))  
  210.         write_fifo_num   <= write_fifo_num + 1;  
  211.     else if(fifo_wr_en && (write_fifo_num == (WIDTH - 1)))  
  212.         write_fifo_num   <= 13'h0;  
  213. end  
  214. always @(posedge v_video_clk)  
  215. begin  
  216.     if(!axi_rstn)begin  
  217.         fifo_wr_en = 1'b0;  
  218.     end  
  219.     else begin  
  220.     if((fifo_wr_en == 1'b0) && process_start && v_timing_active_video_i && (write_fifo_num != (WIDTH - 1)))  
  221.         fifo_wr_en = 1'b1;  
  222.     else if(write_fifo_num == (WIDTH - 1))  
  223.         fifo_wr_en = 1'b0;  
  224.     else if(!process_start)  
  225.         fifo_wr_en = 1'b0;  
  226.     end  
  227. end  
  228.   
  229. fifo_axi32bit u_fifo_axi32bit (  
  230.   .wr_clk(v_video_clk),                 
  231.   .rd_clk(axi_clk),                   
  232.   .din({v_video_data_r,8'h00}),                 
  233.   .wr_en(fifo_wr_en),                   
  234.   .rd_en(fifo_rd_en),                   
  235.   .dout(fifo_dout),                     
  236.   .full(fifo_full),                     
  237.   .empty(fifo_empty),                   
  238.   .valid(fifo_valid),                   
  239.   .rd_data_count(fifo_rd_data_count),   
  240.   .wr_data_count(fifo_wr_data_count)    
  241. );  
  242.    //------------------------------------------------------  
  243.    // AXI bus  
  244.    //------------------------------------------------------  
  245. assign S_AXI_AWID_pin      = 6'b000000;  
  246. assign S_AXI_AWLEN_pin     = 4'hf;     //burst length: 16  
  247. assign S_AXI_AWSIZE_pin    = 3'b010;   //size: 4byte       
  248. assign S_AXI_AWBURST_pin   = 2'b01;    //incr              
  249. assign S_AXI_AWLOCK_pin    = 2'b00;  
  250. assign S_AXI_AWCACHE_pin   = 4'b0011; ////  
  251. assign S_AXI_AWPROT_pin    = 3'b000;  
  252. assign S_AXI_AWQOS_pin     = 4'b0000;  
  253. assign S_AXI_BREADY_pin    = 1'b1;  
  254. assign S_AXI_WSTRB_pin     = 8'b11111111;  
  255. assign S_AXI_WID_pin       = 0;     
  256.    
  257. parameter   IDLE        = 4'b0000;  
  258. parameter   CHECK_FIFO  = 4'b0001;  
  259. parameter   AXI_WRITE   = 4'b0011;  
  260. parameter   NEXT_WRITE  = 4'b0111;  
  261. parameter   NEXT_LINE   = 4'b1111;  
  262. parameter   NEXT_FRAME  = 4'b1110;  
  263. parameter   FINISH      = 4'b1100;  
  264.   
  265. reg [3:0]w_cs;  
  266. reg [3:0]w_ns;  
  267.   
  268.      
  269. always @(posedge axi_clk)  
  270. begin  
  271.     if(!axi_rstn)  
  272.     begin  
  273.         w_cs <= IDLE;  
  274.     end  
  275.     else  
  276.     begin  
  277.         w_cs <= w_ns;  
  278.     end  
  279. end  
  280.   
  281. always @(*) begin  
  282.     case(w_cs)  
  283.         IDLE: begin  
  284.             if(process_start)  
  285.                 w_ns  = CHECK_FIFO;  
  286.             else  
  287.                 w_ns  = w_cs;  
  288.         end  
  289.         CHECK_FIFO: begin  
  290.             if(fifo_rd_data_count >= 10'h10)  
  291.                 w_ns  = AXI_WRITE;  
  292.             else  
  293.                 w_ns  = w_cs;  
  294.         end  
  295.         AXI_WRITE: begin  
  296.             if(axi_addr_ok && axi_write_ok && ~line_last)  
  297.                 w_ns  = NEXT_WRITE;  
  298.             else if(axi_addr_ok && axi_write_ok && line_last && ~frame_last)  
  299.                 w_ns  = NEXT_LINE;  
  300.             else if(axi_addr_ok && axi_write_ok && line_last && frame_last)  
  301.                 w_ns  = NEXT_FRAME;  
  302.             else  
  303.                 w_ns  = w_cs;  
  304.         end  
  305.         NEXT_WRITE: begin  
  306.             w_ns  = CHECK_FIFO;  
  307.         end  
  308.         NEXT_LINE: begin  
  309.             w_ns  = CHECK_FIFO;  
  310.         end  
  311.         NEXT_FRAME: begin // pro  
  312.             if(frame_num < 32'h11)  
  313.                 w_ns  = CHECK_FIFO;  
  314.             else  
  315.                 w_ns  = FINISH;  
  316.         end  
  317.         FINISH: begin  
  318.             w_ns  = FINISH;  
  319.         end  
  320.         default: begin  
  321.             w_ns  = w_cs;  
  322.         end  
  323.     endcase  
  324. end  
  325.   
  326. always @(posedge axi_clk) begin  
  327.     if(!axi_rstn) begin  
  328.         read_fifo_num    <= 5'h0;  
  329.         fifo_rd_ok      <= 1'b0;  
  330.     end  
  331.     else if(w_ns != AXI_WRITE) begin  
  332.         read_fifo_num    <= 5'h0;  
  333.         fifo_rd_ok      <= 1'b0;  
  334.     end  
  335.     else if(fifo_rd_en && (read_fifo_num != 5'hf)) begin  
  336.         read_fifo_num    <= read_fifo_num + 1;  
  337.         fifo_rd_ok      <= 1'b0;  
  338.     end  
  339.     else if(fifo_rd_en && (read_fifo_num == 5'hf)) begin  
  340.         read_fifo_num    <= 5'h0;  
  341.         fifo_rd_ok      <= 1'b1;  
  342.     end  
  343. end  
  344. assign  fifo_rd_en      = (w_ns == AXI_WRITE && ~stall && !fifo_rd_ok)? 1'b1 : 1'b0;  
  345. assign  stall           = (w_cs == AXI_WRITE && ~axi_write_ok && S_AXI_WVALID_pin && ~S_AXI_WREADY_pin)? 1'b1 : 1'b0;  
  346.   
  347. always @(posedge axi_clk) begin  
  348.     if(!axi_rstn) begin  
  349.         S_AXI_AWVALID_pin <= 1'b0;  
  350.         axi_addr_ok <= 1'b0;  
  351.     end  
  352.     else if(w_ns == AXI_WRITE && w_cs != AXI_WRITE) begin  
  353.         S_AXI_AWVALID_pin <= 1'b1;  
  354.         axi_addr_ok <= 1'b0;  
  355.     end  
  356.     else if(S_AXI_AWREADY_pin) begin  
  357.         S_AXI_AWVALID_pin <= 1'b0;  
  358.         axi_addr_ok <= 1'b1;  
  359.     end  
  360. end  
  361.   
  362. always @(posedge axi_clk) begin  
  363.     if(!axi_rstn)  
  364.         S_AXI_WVALID_pin  <= 1'b0;  
  365.     else if((S_AXI_WREADY_pin & S_AXI_WVALID_pin) && (axi_write_num == 5'hf))  
  366.         S_AXI_WVALID_pin  <= 1'b0;  
  367.     else if(w_cs == AXI_WRITE && ~axi_write_ok)  
  368.         S_AXI_WVALID_pin  <= 1'b1;  
  369. end  
  370. always @(posedge axi_clk) begin  
  371.     if(!axi_rstn)  
  372.         S_AXI_WDATA_pin   <= 32'h0;  
  373.     else if(!stall)  
  374.         S_AXI_WDATA_pin   <= {fifo_dout[7:0],fifo_dout[15:8],fifo_dout[23:16],fifo_dout[31:24]};//{8'h33,8'h22,8'h11,8'h00};  
  375. end  
  376. wire [31:0] dma_tran_addr;  
  377. assign dma_tran_addr = (frame_num == 2'b00)? DMA_DEST_ADDR0 : (frame_num == 2'b01)? DMA_DEST_ADDR1 : DMA_DEST_ADDR2;  
  378. always @(posedge axi_clk) begin  
  379.     if(!axi_rstn)  
  380.         S_AXI_AWADDR_pin  <= 32'h0;  
  381.     else if(w_cs == IDLE && w_ns == CHECK_FIFO)  
  382.         S_AXI_AWADDR_pin  <= dma_tran_addr;  
  383.     else if(w_cs == NEXT_WRITE && w_ns == CHECK_FIFO)  
  384.         S_AXI_AWADDR_pin  <= S_AXI_AWADDR_pin + 8'h40; //16 * 1byte  
  385.     else if(w_cs == NEXT_LINE  && w_ns == CHECK_FIFO)  
  386.         S_AXI_AWADDR_pin  <= prev_line_start + STRIDE;  
  387.     else if(w_cs == NEXT_FRAME && w_ns == CHECK_FIFO)  
  388.         S_AXI_AWADDR_pin  <= dma_tran_addr;  
  389. end  
  390.   
  391. always @(posedge axi_clk) begin  
  392.     if(!axi_rstn)  
  393.         prev_line_start <= 32'h0;  
  394.     else if(w_cs == IDLE && w_ns == CHECK_FIFO)  
  395.         prev_line_start <= dma_tran_addr;  
  396.     else if(w_cs == NEXT_LINE  && w_ns == CHECK_FIFO)  
  397.         prev_line_start <= prev_line_start + STRIDE;  
  398.     else if(w_cs == NEXT_FRAME && w_ns == CHECK_FIFO)  
  399.         prev_line_start <= dma_tran_addr;  
  400. end  
  401.   
  402. always @(posedge axi_clk) begin  
  403.     if(!axi_rstn) begin  
  404.         axi_write_num    <= 5'h0;  
  405.         axi_write_ok    <= 1'b0;  
  406.     end  
  407.     else if(w_ns != AXI_WRITE) begin  
  408.         axi_write_num    <= 5'h0;  
  409.         axi_write_ok    <= 1'b0;  
  410.     end  
  411.     else if((S_AXI_WREADY_pin & S_AXI_WVALID_pin) && (axi_write_num != 5'hf)) begin  
  412.         axi_write_num    <= axi_write_num + 1;  
  413.         axi_write_ok    <= 1'b0;  
  414.     end  
  415.     else if((S_AXI_WREADY_pin & S_AXI_WVALID_pin) && (axi_write_num == 5'hf)) begin  
  416.         axi_write_num    <= 5'h0;  
  417.         axi_write_ok    <= 1'b1;  
  418.     end  
  419. end  
  420. always @(posedge axi_clk) begin  
  421.     if(!axi_rstn)  
  422.         frame_num    <= 2'b00;  
  423.     else if(process_start && frame_last && ~frame_last_r)  
  424.     begin  
  425.         if(frame_num != 2'b10)  
  426.             frame_num    <= frame_num + 1;  
  427.         else   
  428.             frame_num    <= 2'b00;  
  429.     end  
  430. end  
  431. always @(posedge axi_clk) begin  
  432.     if(!axi_rstn)  
  433.         hcount  <= 13'h0;  
  434.     else if(w_ns == NEXT_LINE)  
  435.         hcount  <= 13'h0;  
  436.     else if(w_ns == NEXT_FRAME)  
  437.         hcount  <= 13'h0;  
  438.     else if(w_ns == NEXT_WRITE)  
  439.         hcount  <= hcount + 16;  
  440. end  
  441.   
  442. always @(posedge axi_clk) begin  
  443.     if(!axi_rstn)  
  444.         vcount  <= 13'h0;  
  445.     else if(w_ns == NEXT_FRAME)  
  446.         vcount  <= 13'h0;  
  447.     else if(w_ns == NEXT_LINE)  
  448.         vcount  <= vcount + 1;  
  449. end  
  450.   
  451. always @(posedge axi_clk) begin  
  452.     if(!axi_rstn)  
  453.         frame_last_r    <= 1'b0;  
  454.     else  
  455.         frame_last_r    <= frame_last;  
  456. end  
  457. assign  line_last   = (hcount == (WIDTH - 16) )? 1'b1 : 1'b0;  
  458. assign  frame_last  = (vcount == (HEIGHT - 1) )? 1'b1 : 1'b0;  
  459.   
  460. assign  S_AXI_WLAST_pin   = (axi_write_num == 5'hf)? 1'b1 : 1'b0;  
  461.     
  462. endmodule  


MM2S VDMA设计

AXI读流程图:
Zedboard &amp; Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
读时序图:
Zedboard &amp; Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
AXI读数据就比较简单了,只要在AXI和video之间加入个fifo进行一下缓存就可以了,只要时序是对的,直接上代码
[plain] view plaincopy
  1. /*-----------------------------------------------------------------------  
  2.   
  3. CONFIDENTIAL IN CONFIDENCE  
  4. This confidential and proprietary software may be only used as authorized  
  5. by a licensing agreement from EEPROM .  
  6. In the event of publication, the following notice is applicable:  
  7. Copyright (C) 2013-20xx EEPROM Corporation  
  8. The entire notice above must be reproduced on all authorized copies.  
  9. Author              :       EEPROM  
  10. Technology blogs    :       http://blog.csdn.net/zhangyu_eeprom  
  11. Email Address       :       [email protected]  
  12. Filename            :       axi4_mm2s_video_dma.v  
  13. Data                :       2014-05-20  
  14. Description         :       axi4_mm2s_video_dma.  
  15. Modification History    :  
  16. Data            By          Version         Change Description  
  17. =========================================================================  
  18. -------------------------------------------------------------------------  
  19.   
  20.         ------     ------    ------|   ------|      /-------\     
  21.        |          |          |     |   |     |     /         \      /-\     /-\  
  22.        |------    |------    |-----|   |-----|    /           \    /   \   /   \  
  23.        |          |          |         | \        \           /   /     \_/     \  
  24.        |------    |------    |         |  \        \         /   /               \  
  25.                              |         |   \        \-------/  
  26. -----------------------------------------------------------------------*/     
  27.   
  28. module axi4_mm2s_video_dma #(  
  29.    parameter [31:0]  DMA_DEST_ADDR0 = 32'h1c000000,  
  30.    parameter [31:0]  DMA_DEST_ADDR1 = 32'h1c200000,  
  31.    parameter [31:0]  DMA_DEST_ADDR2 = 32'h1c400000,  
  32.    parameter [8:0]   C_DATA_WIDTH = 9'd32,  
  33.    parameter [12:0]  STRIDE       = 12'd1920,  
  34.    parameter [12:0]  WIDTH        = 12'd1920,  
  35.    parameter [12:0]  HEIGHT       = 12'd1080  
  36.    )  
  37.    (  
  38.    input             axi_clk,  
  39.    input             axi_rstn,  
  40.     
  41.    input            v_video_clk,        
  42.    input            v_timing_hsync_i,  
  43.    input            v_timing_vsync_i,  
  44.    input            v_timing_hblank_i,  
  45.    input            v_timing_vblank_i,  
  46.    input            v_timing_active_video_i,  
  47.      
  48.    output  reg       v_timing_hsync_o,  
  49.    output  reg       v_timing_vsync_o,  
  50.    output  reg       v_timing_hblank_o,  
  51.    output  reg       v_timing_vblank_o,  
  52.    output  reg       v_timing_active_video_o,       
  53.    output [23:0]     v_video_o,  
  54.             
  55.    input             S_AXI_ARREADY_pin,  
  56.    input             S_AXI_RLAST_pin,  
  57.    input             S_AXI_RVALID_pin,  
  58.    input   [1:0]     S_AXI_RRESP_pin,  
  59.    input   [C_DATA_WIDTH-1:0]    S_AXI_RDATA_pin,  
  60.    input   [5:0]     S_AXI_RID_pin,  
  61.    output            S_AXI_ARVALID_pin,   
  62.    output            S_AXI_RREADY_pin,  
  63.    output [1:0]      S_AXI_ARBURST_pin,  
  64.    output [1:0]      S_AXI_ARLOCK_pin,  
  65.    output [2:0]      S_AXI_ARSIZE_pin,  
  66.    output [2:0]      S_AXI_ARPROT_pin,  
  67.    output reg [31:0] S_AXI_ARADDR_pin,  
  68.    output [3:0]      S_AXI_ARCACHE_pin,  
  69.    output [3:0]      S_AXI_ARLEN_pin,  
  70.    output [3:0]      S_AXI_ARQOS_pin,  
  71.    output [5:0]      S_AXI_ARID_pin  
  72.    );  
  73. /******************************/  
  74. wire frame_last;  
  75. wire line_last;  
  76. reg process_start = 1'b0;  
  77. wire [9:0] space;  
  78. reg [31:0]prev_line_start;  
  79. reg [1:0]frame_num;  
  80. reg [12:0]hcount;  
  81. reg [12:0]vcount;  
  82. reg frame_last_r;  
  83. wire [31:0] dma_tran_addr;  
  84. wire dma_frame_read_end;  
  85.   
  86. reg v_timing_hsync_r;  
  87. reg v_timing_vsync_r;  
  88. reg v_timing_hblank_r;  
  89. reg v_timing_vblank_r;  
  90. reg v_timing_active_video_r;  
  91. reg v_timing_active_video_d1;  
  92. reg v_timing_active_video_d2;  
  93. /************fifo**************/  
  94. wire  fifo_wr_en;  
  95. reg   fifo_rd_en;  
  96. wire  fifo_full;  
  97. wire  fifo_empty;  
  98. wire  fifo_valid;  
  99. wire  [6:0] fifo_rd_data_count;  
  100. wire  [6:0] fifo_wr_data_count;  
  101. wire  [31:0] fifo_dout;  
  102. /******************************/    
  103. assign fifo_wr_en = S_AXI_RVALID_pin & S_AXI_RREADY_pin;  
  104. //assign fifo_rd_en = process_start & v_timing_active_video_r;  
  105. assign v_video_o = fifo_dout[31:8];  
  106. fifo_axi32bit u_fifo_axi32bit (  
  107.   .wr_clk(axi_clk),                   
  108.   .rd_clk(v_video_clk),                 
  109.   .din({S_AXI_RDATA_pin[7:0],S_AXI_RDATA_pin[15:8],S_AXI_RDATA_pin[23:16],S_AXI_RDATA_pin[31:24]}),                
  110.   .wr_en(fifo_wr_en),                   
  111.   .rd_en(fifo_rd_en),                   
  112.   .dout(fifo_dout),                     
  113.   .full(fifo_full),                     
  114.   .empty(fifo_empty),                   
  115.   .valid(fifo_valid),                   
  116.   .rd_data_count(fifo_rd_data_count),   
  117.   .wr_data_count(fifo_wr_data_count)    
  118. );     
  119.      
  120. always @(posedge v_video_clk)   
  121. begin  
  122.     v_timing_hsync_r        <= v_timing_hsync_i;         
  123.     v_timing_vsync_r        <= v_timing_vsync_i;         
  124.     v_timing_hblank_r       <= v_timing_hblank_i;        
  125.     v_timing_vblank_r       <= v_timing_vblank_i;        
  126.     v_timing_active_video_r <= v_timing_active_video_i;  
  127.       
  128.     v_timing_hsync_o        <= v_timing_hsync_r;         
  129.     v_timing_vsync_o        <= v_timing_vsync_r;         
  130.     v_timing_hblank_o       <= v_timing_hblank_r;        
  131.     v_timing_vblank_o       <= v_timing_vblank_r;        
  132.     v_timing_active_video_o <= v_timing_active_video_r;  
  133.       
  134.     v_timing_active_video_d1 <= v_timing_active_video_r;  
  135.     v_timing_active_video_d2 <= v_timing_active_video_d1;  
  136. end    
  137. reg [1:0] process_start_r;  
  138. always @(posedge v_video_clk)   
  139. begin  
  140.     if(!axi_rstn)begin  
  141.         process_start <= 1'b0;  
  142.     end  
  143.     else if(~v_timing_vsync_r && v_timing_vsync_i)  
  144.     begin  
  145.         process_start <= 1'b1;  
  146.     end  
  147.     else if(dma_frame_read_end)  
  148.         process_start <= 1'b0;  
  149. end     
  150. cross_clk cross_clk1  
  151.    (  
  152.       .clkin   (axi_clk),  
  153.       .din     (frame_last),  
  154.       .clkout  (v_video_clk),  
  155.       .dout    (dma_frame_read_end)  
  156.    );  
  157. reg pre;  
  158. reg [12:0] invalid_cnt;  
  159. reg [12:0] invalid_cnt_debug;  
  160. reg [12:0] fifo_read_num;  
  161.   
  162. always @(posedge v_video_clk)  
  163. begin  
  164.     if(!axi_rstn)  
  165.     begin  
  166.     end  
  167.   
  168.     else if(v_timing_active_video_r == 1'b0 || fifo_read_num == (WIDTH - 2))  
  169.     begin  
  170.         fifo_rd_en <= 1'b0;  
  171.     end  
  172.     else if(v_timing_active_video_r && fifo_read_num < (WIDTH - 2))  
  173.         fifo_rd_en <= 1'b1;  
  174. end  
  175. always @(posedge v_video_clk)  
  176. begin  
  177.     if(!axi_rstn)  
  178.     begin  
  179.         fifo_read_num <= 13'd0;  
  180.     end  
  181.     else if(v_timing_active_video_d2 && fifo_read_num != (WIDTH - 1))  
  182.         fifo_read_num <= fifo_read_num + 1;  
  183.     else if(!v_timing_active_video_d2 && fifo_read_num == (WIDTH - 1))  
  184.         fifo_read_num <= 13'd0;  
  185. end  
  186. //------------------------------------------------------  
  187. // AXI bus  
  188. //------------------------------------------------------  
  189. assign S_AXI_ARID_pin      = 6'b000000;  
  190. assign S_AXI_ARLEN_pin     = 4'hf;     //burst length: 16  
  191. assign S_AXI_ARSIZE_pin    = 3'b010;   //size: 4byte  
  192. assign S_AXI_ARBURST_pin   = 2'b01;    //incr  
  193. assign S_AXI_ARLOCK_pin    = 2'b00;  
  194. assign S_AXI_ARCACHE_pin   = 4'b0011; /////  
  195. assign S_AXI_ARPROT_pin    = 3'b000;  
  196. assign S_AXI_ARQOS_pin     = 4'b0000;  
  197.      
  198.      
  199. parameter   IDLE        = 4'b0000;  
  200. parameter   SEND_ADDR   = 4'b0001;  
  201. parameter   WAIT_DATA   = 4'b0011;  
  202. parameter   WAIT_FIFO   = 4'b0111;  
  203. parameter   NEXT_READ   = 4'b1111;  
  204. parameter   NEXT_LINE   = 4'b1110;  
  205. parameter   NEXT_FRAME  = 4'b1100;  
  206. reg [3:0]r_cs;  
  207. reg [3:0]r_ns;  
  208.   
  209. assign  space   = 127 - fifo_wr_data_count[6:0];  
  210. always @(posedge axi_clk)  
  211. begin  
  212.     if(!axi_rstn)  
  213.     begin  
  214.         r_cs <= IDLE;  
  215.     end  
  216.     else  
  217.     begin  
  218.         r_cs <= r_ns;  
  219.     end  
  220. end  
  221.   
  222. always @(*) begin  
  223.     case(r_cs)  
  224.         IDLE: begin  
  225.             if(process_start)  
  226.                 r_ns  = SEND_ADDR;  
  227.             else  
  228.                 r_ns  = r_cs;  
  229.         end  
  230.         SEND_ADDR: begin  
  231.             if(S_AXI_ARREADY_pin & S_AXI_ARVALID_pin)  
  232.                 r_ns  = WAIT_DATA;  
  233.             else  
  234.                 r_ns  = r_cs;  
  235.         end  
  236.         WAIT_DATA: begin  
  237.             if(S_AXI_RREADY_pin & S_AXI_RVALID_pin & S_AXI_RLAST_pin & (space < 10'h12))  
  238.                 r_ns  = WAIT_FIFO;  
  239.             else if(S_AXI_RREADY_pin & S_AXI_RVALID_pin & S_AXI_RLAST_pin & (~line_last))  
  240.                 r_ns  = NEXT_READ;  
  241.             else if(S_AXI_RREADY_pin & S_AXI_RVALID_pin & S_AXI_RLAST_pin & ( line_last) & (~frame_last))  
  242.                 r_ns  = NEXT_LINE;  
  243.             else if(S_AXI_RREADY_pin & S_AXI_RVALID_pin & S_AXI_RLAST_pin & ( line_last) & ( frame_last))  
  244.                 r_ns  = NEXT_FRAME;  
  245.             else  
  246.                 r_ns  = r_cs;  
  247.         end  
  248.         WAIT_FIFO: begin  
  249.             if((space >= 10'h11) & (~line_last))  
  250.                 r_ns  = NEXT_READ;  
  251.             else if((space >= 10'h11) & ( line_last) & (~frame_last))  
  252.                 r_ns  = NEXT_LINE;  
  253.             else if((space >= 10'h11) & ( line_last) & ( frame_last))  
  254.                 r_ns  = NEXT_FRAME;  
  255.             else  
  256.                 r_ns  = r_cs;  
  257.         end  
  258.         NEXT_READ: begin  
  259.             r_ns  = SEND_ADDR;  
  260.         end  
  261.         NEXT_LINE: begin  
  262.             r_ns  = SEND_ADDR;  
  263.         end  
  264.         NEXT_FRAME: begin  
  265.             r_ns  = IDLE;//SEND_ADDR  
  266.         end  
  267.         default: begin  
  268.             r_ns  = r_cs;  
  269.         end  
  270.     endcase  
  271. end  
  272. /************test***************/  
  273.   
  274. /***************************/  
  275. assign dma_tran_addr = (frame_num == 2'b00)? DMA_DEST_ADDR0 : (frame_num == 2'b01)? DMA_DEST_ADDR1 : DMA_DEST_ADDR2;  
  276.   
  277. always @(posedge axi_clk) begin  
  278.     if(!axi_rstn)  
  279.         prev_line_start <= 32'h0;  
  280.     else if(r_cs == IDLE && r_ns == SEND_ADDR)  
  281.         prev_line_start <= dma_tran_addr;  
  282.     else if(r_cs == NEXT_LINE && r_ns == SEND_ADDR)  
  283.         prev_line_start <= prev_line_start + STRIDE;  
  284.     else if(r_cs == NEXT_FRAME && r_ns == IDLE)//SEND_ADDR  
  285.         prev_line_start <= dma_tran_addr;  
  286. end  
  287.   
  288. always @(posedge axi_clk) begin  
  289.     if(!axi_rstn)  
  290.         S_AXI_ARADDR_pin  <= 32'h0;  
  291.     else if(r_cs == IDLE && r_ns == SEND_ADDR)  
  292.         S_AXI_ARADDR_pin  <= dma_tran_addr;  
  293.     else if(r_cs == NEXT_READ && r_ns == SEND_ADDR)  
  294.         S_AXI_ARADDR_pin  <= S_AXI_ARADDR_pin + 8'h40;  
  295.     else if(r_cs == NEXT_LINE && r_ns == SEND_ADDR)  
  296.         S_AXI_ARADDR_pin  <= prev_line_start + STRIDE;  
  297.     else if(r_cs == NEXT_FRAME && r_ns == IDLE)//SEND_ADDR  
  298.         S_AXI_ARADDR_pin  <= dma_tran_addr;  
  299. end  
  300.   
  301. assign  S_AXI_ARVALID_pin = (r_cs == SEND_ADDR)? 1'b1 : 1'b0;  
  302.   
  303. always @(posedge axi_clk) begin  
  304.     if(!axi_rstn)  
  305.         hcount  <= 13'h0;  
  306.     else if((r_cs == IDLE || r_cs == NEXT_LINE || r_cs == NEXT_FRAME) && (r_ns == SEND_ADDR))//SEND_ADDR  
  307.         hcount  <= 13'h0;  
  308.     else if(r_cs == NEXT_READ && r_ns == SEND_ADDR)  
  309.         hcount  <= hcount + 16;  
  310. end  
  311.   
  312. always @(posedge axi_clk) begin  
  313.     if(!axi_rstn)  
  314.         vcount  <= 13'h0;  
  315.     else if(r_cs == NEXT_FRAME && r_ns == IDLE)//SEND_ADDR  
  316.         vcount  <= 13'h0;  
  317.     else if(r_cs == NEXT_LINE && r_ns == SEND_ADDR)  
  318.         vcount  <= vcount + 1;  
  319. end  
  320. always @(posedge axi_clk) begin  
  321.     if(!axi_rstn)  
  322.     begin  
  323.         frame_num    <= 2'b00;  
  324.     end  
  325.     else if(/*process_start && */frame_last && ~frame_last_r)  
  326.     begin  
  327.         if(frame_num != 2'b10)  
  328.             frame_num    <= frame_num + 1;  
  329.         else   
  330.             frame_num    <= 2'b00;  
  331.     end  
  332. end  
  333. always @(posedge axi_clk) begin  
  334.     if(!axi_rstn)  
  335.         frame_last_r    <= 1'b0;  
  336.     else   
  337.         frame_last_r    <= frame_last;  
  338. end  
  339. assign  line_last   = (hcount == (WIDTH - 16) )? 1'b1 : 1'b0;  
  340. assign  frame_last  = (vcount == (HEIGHT - 1) )? 1'b1 : 1'b0;  
  341. assign  S_AXI_RREADY_pin = 1'b1;    
  342.   
  343.      
  344. endmodule  
当然,读过程也和写过程一样,burst长度是固定的16,所以读数据长度也要能被16整除才可以

注意:在做AXI总线读写的时候,一定要注意大小端的问题。

总结

DMA操作其实就是直接操作AXI总线进行DDR数据搬移,只要满足AXI总线协议就可以了,自己写DMA可以灵活定制功能,减小设计面积,更加可调式。本文中的设计只是很拙劣的设计,就是按照时序拼出来的,如果哪位能给提出些建议,或者有更好的方案,还望不吝赐教