码迷,mamicode.com
首页 > 其他好文 > 详细

MiS603开发板 第九章 IP-CORE BRAM

时间:2015-09-13 14:34:39      阅读:337      评论:0      收藏:0      [点我收藏+]

标签:

作者:MiS603开发团队

日期:20150911

公司:南京米联电子科技有限公司

论坛:www.osrc.cn

网址:www.milinker.com

网店:http://osrc.taobao.com

EAT博客:http://blog.chinaaet.com/whilebreak

博客园:http://www.cnblogs.com/milinker/

技术分享

MiS603开发板 第九章 IP-CORE BRAM

上一章节笔者讲解了FIFO的简单使用,那么FPGA的Block RAM(BRAM) 也是FPGA珍贵和重要的存储单元。本章将讲解BRAM的使用,和前面讲解FIFO使用类似,本章通过UART经过PC将数据发送给BRAM,BRAM缓存后再通过UART返回给电脑,让读者有一个全局的认识。当具体项目的时候,可以根据项目要求灵活运用。

技术分享

9.1 添加BRAM IP CORE

Step1:新建工程BRAM_TEST

技术分享

Step2:添加BRAM IP CORE

技术分享

Step3:选择框选的接口类型,Native 主要是逻辑代码控制简单,AXI4稍微复杂一点。

技术分享

Step4:选择简单双端口RAM

技术分享

Step5:设置BRAM写地址空间为8bit X 32 depth

技术分享

Step6:单击NEXT

技术分享

Step8:单击NEXT

技术分享

Step9:单击Generate产生IP CORE

技术分享

Step10:添加IP CORE 并且添加 UART串口驱动

9.2程序分析

技术分享

module BRAM_TEST(

input CLK_50MHZ_i,

input rst_n_i,

input uart_rx_i,

output uart_tx_o

    );

wire IsRxdDone,UartIsFull;

wire [7:0] BRAM_din;

wire [7:0] BRAM_dout;

wire BRAM_wr_en;

reg  UartIsSta;

parameter READ_BRAM0=0;

parameter READ_BRAM1=1;

parameter BRAM_BASE0 = 0;

parameter BRAM_BASE1 = 16;

reg BASE_FLAG;//基地址标准

//写地址累加

reg [4:0] bram_addra_r;

always @(posedge CLK_50MHZ_i)begin

if(~rst_n_i)begin

bram_addra_r <= 5‘d0;

BASE_FLAG <= 1‘b0;

end

else if(IsRxdDone)begin

bram_addra_r <= bram_addra_r + 1‘b1;//地址累加

end

else if(bram_addra_r==5‘d16)begin

bram_addra_r <= 5‘d0;

BASE_FLAG   <= ~BASE_FLAG;

end

end

//读地址累加

reg [4:0] bram_addrb_r;

always @(posedge CLK_50MHZ_i)begin

if(~rst_n_i)begin

bram_addrb_r <= 5‘d0;

end

else if(UartIsSta)begin

bram_addrb_r <= bram_addrb_r + 1‘b1;//地址累加

end

else if(bram_addrb_r==5‘d16)begin

bram_addrb_r <= 5‘d0;

end

end

wire [4:0] bram_addra;

wire [4:0] bram_addrb;

//写BRAM地址+基地址

assign bram_addra = BASE_FLAG ? (bram_addra_r + BRAM_BASE1) : (bram_addra_r + BRAM_BASE0);//产生写地址

//读BRAM地址+基地址

assign bram_addrb = BASE_FLAG ? (bram_addrb_r + BRAM_BASE0) : (bram_addrb_r + BRAM_BASE1);//产生读写地址

reg f_s;

always @(posedge CLK_50MHZ_i)begin

if(~rst_n_i)begin

f_s <= 1‘b0;

end

else begin

case(f_s)

READ_BRAM0:begin //写完一次 准备读

if(bram_addra_r==5‘d16)

f_s <= READ_BRAM1;

end

READ_BRAM1:begin //读完一次 返回

if(bram_addrb_r==5‘d16)begin//读的速度需要大于或者等于写的速度,由于是串口读写速度一样,要求每次发送16bytes数据中间有一个时间停顿

f_s <= READ_BRAM0;

end

end

endcase

end

end

always @(posedge CLK_50MHZ_i)begin

if(~rst_n_i)begin

UartIsSta <= 1‘b0;

end

else begin

if(f_s==READ_BRAM1&&(~UartIsFull))

UartIsSta <= ~UartIsSta;

else UartIsSta <= 1‘b0;

end

end

assign BRAM_wr_en = IsRxdDone;//使能写

//BRAM 读写模块

BRAM BRAM_0 (

  .clka(~CLK_50MHZ_i),  // input clka

  .wea(BRAM_wr_en),  // input [0 : 0] wea

  .addra(bram_addra),  // input [4 : 0] addra

  .dina(BRAM_din),  // input [7 : 0] dina

  .clkb(~CLK_50MHZ_i),  // input clkb

  .addrb(bram_addrb),   // input [4 : 0] addrb

  .doutb(BRAM_dout)  // output [7 : 0] doutb

);

UartRxd  U1 (.Clk_i(CLK_50MHZ_i),.RevD(BRAM_din),.IsDone(IsRxdDone),.Rxd_i(uart_rx_i));//recieve

UartTxd  U2 (.Clk_i(CLK_50MHZ_i),.IsSta(UartIsSta),.IsFull(UartIsFull),.SendD(BRAM_dout),.Txd_o(uart_tx_o)); //send

endmodule

以上程序的关键就是如何实现BRAM地址空间的切换。

技术分享

笔者把一个连续的BRAM 地址空间氛围两部分,第一部分是以BASE0为起始地址,一个是以BASE1为起始地址。为了实现缓存16 bytes 的数据,地址空间总计32 bytes深度,第一部分16 bytes,第二部分也是16 bytes。假设串口发送过来的数据首先保存到基地址为BASE0的内存部分。当这部分地址接收完成后,就可以从此空间读取数据。为了保障数据的流畅性,当从BASE0读取数据的时候,BASE1可以接收新的数据。这样就实现了一个二级缓存,实现了缓存一组数据,这个应用在视频处理方面非常实用。

程序上,写地址空间的增量bram_addra_r在每次串口接收到新数据收增加1,读地址空间增量bram_addrb_r在每次读取一个数据后,地址空间增加1。然后通过加上基地址的偏移量,实现计算出内存对应空间的读写地址。通过BASE_FLAG标志,实现读写地址空间的切换。实际上,笔者这里就是采用了一种叫做“乒乓”的处理方式,当对写地址空间写的时候,对读的地址空间读。址空间实现“乒乓”处理,这样在处理数据流方面,非常有用。

关于串口模块的收发,直接调用笔者写好的程序,不在详细介绍。

9.3测试结果

技术分享

波特率设置到38400,每次发送16 bytes的数据,立刻返回16bytes的数据。

9.4 小结

本章实现了简单双口RAM 实现数据流的“乒乓”缓存方式,通过串口实现了数据流输出,和输出的验证。

MiS603开发板 第九章 IP-CORE BRAM

标签:

原文地址:http://www.cnblogs.com/milinker/p/4804845.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!