当前位置: 首页 > news >正文

FPGA学习笔记——简单的乒乓缓存(RAM)

一、任务

按键按下,将ROM里面存储的数据进行乒乓缓存(我这里的数据是方波的数据),然后以串口的形式发送出去(串口可以看看我之前写的),以50MHz的速率输入,以50MHz的速率输出(这里没有涉及到速度---面积的换算)。


二、分析

首先,先要一个ROM IP核,将.mif文件.hex文件放进去,让它形成一个数据发送源,其次,还需要两个双端口的RAM将接收到的数据来进行乒乓缓存,这里就要用状态机来写(状态机写法更简单,逻辑清晰),

双端口RAM的状态可以有:

IDLE

RAM1

W2R1

W1R2

首先,RAM里面是没有数据的,当按键按下,ROM将不间断的发送数据,RAM1就开始写入数据,当RAM1的数据写满(地址达到最大),就跳入下一个状态,RAM1的读取RAM2的写入,当RAM1中的数据读完或者RAM2中的数据写满(地址达到最大),就跳回W2R1的状态,形成一个循环


三、需要用到的IP 核

单端口ROM配置

双端口RAM配置


四、Visio图


五、代码

key.v

module key(
input   wire    clk     ,
input   wire    rst_n   ,
input   wire    key     ,
output  reg     key_out
);
//消抖后的按键
parameter delay = 100_0000;//20ms
reg [20:0] cnt;always@(posedge clk)//延时消抖的过程
if(!rst_n)cnt<=0;
else if(key == 0)begin//1.按键按下 2.抖动过程 3.中间稳定if(cnt == delay - 1) cnt <= cnt;//300mselsecnt <= cnt + 1;//0--1--2  
end
else //1.抖动 2.没有按键cnt<=0;always@(posedge clk)//产生消抖信号:1clk的持续时间
if(!rst_n)key_out<=0;
else if(cnt == delay - 2)key_out<=1;
elsekey_out<=0;endmodule

rom_ctrl.v

module rom_ctrl (
input       wire                clk         ,
input       wire                rst_n       ,
input       wire                key_out     ,
output      wire      [7:0]     data_rom    ,
output      reg                 rom_wren            
);reg     [7:0]   address;
wire     [7:0]   q      ;reg     en;always @(posedge clk) beginif(!rst_n)en <= 0;else if (key_out)en <= ~en;elseen <= en;
endalways @(posedge clk) beginif(!rst_n)address <= 0;else if(en == 1)address <= address + 1;elseaddress <= address;
endalways @(posedge clk) beginif(!rst_n)rom_wren <= 0;else if ( key_out )rom_wren <= ~rom_wren;
endassign data_rom = q;rom	rom_inst (.aclr ( !rst_n ),.address ( address ),.clock ( clk ),.q ( q ));endmodule

ctrl.v

module ctrl (
input   wire            clk          ,
input   wire            rst_n        ,
input   wire    [7:0]   data_rom     ,//并行数据 ,其它模块用
input   wire            done_tx      ,    //字节传输完成
input   wire            rom_wren     ,
output  reg     [7:0]   data_tx      ,//并行输入 --- 变化
output  reg             start         //数据有效信号
);//ram1
reg 	[7:0]    data1      ;
reg     [7:0]    rdaddress1 ;
reg              rden1      ;
reg  	[7:0]    wraddress1 ;
reg 	         wren1      ;
wire	[7:0]    q1         ;//ram2
reg 	[7:0]    data2      ;
reg     [7:0]    rdaddress2 ;
reg              rden2      ;
reg  	[7:0]    wraddress2 ;
reg 	         wren2      ;
wire	[7:0]    q2         ;reg flag1;
reg flag2;parameter   NUM = 256;localparam  IDLE = 4'b0001,RAM1 = 4'b0010,W2R1 = 4'b0100,W1R2 = 4'b1000;reg [3:0] cur_state , next_state;//描述状态转移:现态
always @(posedge clk) beginif(!rst_n)cur_state <= IDLE;else cur_state <= next_state;
endalways @(*) beginif(!rst_n)next_state = IDLE;elsecase (cur_state)IDLE: beginnext_state = RAM1;endRAM1:beginif(wraddress1 == NUM - 1 )next_state = W2R1;elsenext_state = cur_state;endW2R1:beginif(wraddress2 == NUM - 1 && flag1 )next_state = W1R2;elsenext_state = cur_state;endW1R2: beginif(wraddress1 == NUM - 1 && flag2 )next_state = W2R1;elsenext_state = cur_state;enddefault: next_state = IDLE;endcase
end//ram1
always @(posedge clk) beginif(!rst_n) begindata1      <= 0;rdaddress1 <= 0;rden1      <= 0;wraddress1 <= 0;wren1      <= 0;flag1      <= 0;endelsecase (cur_state)IDLE:begin data1      <= 0;rdaddress1 <= 0;rden1      <= 0;wraddress1 <= 0;wren1      <= 0;flag1      <= 0;endRAM1:beginif(rom_wren) beginwraddress1 <= wraddress1 + 1;data1      <= data_rom;endwren1      <= rom_wren;flag1      <= 0;endW2R1:begindata1      <= 0;wren1      <= 0;wraddress1 <= 0;if(done_tx) beginrden1 <= 1;if(rdaddress1 == NUM - 1) beginrdaddress1 <= 0;flag1      <= 1;endelse beginrdaddress1 <= rdaddress1 + 1;flag1      <= 0;endendelserden1 <= 0;endW1R2: beginif(rom_wren) beginwraddress1 <= wraddress1 + 1;data1      <= data_rom;endwren1      <= rom_wren;flag1      <= 0;enddefault: begin data1      <= 0;rdaddress1 <= 0;rden1      <= 0;wraddress1 <= 0;wren1      <= 0;flag1      <= 0;endendcase
end//ram2
always @(posedge clk) beginif(!rst_n) begindata2      <= 0;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= 0;wren2      <= 0;flag2      <=0;endelsecase (cur_state)IDLE:begindata2      <= 0;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= 0;wren2      <= 0;flag2      <=0;endRAM1: ;W2R1: begindata2      <= data_rom;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= wraddress2 + 1;wren2      <= rom_wren;flag2      <=0;endW1R2: begindata2      <= 0;wren2      <= 0;wraddress2 <= 0;if(done_tx) beginrden2      <= 1;if(rdaddress2 == NUM - 1) beginrdaddress2 <= 0;flag2      <= 1;endelse beginrdaddress2 <= rdaddress2 + 1;flag2      <= 0;endendelse rden2      <= 0;enddefault: begindata2      <= 0;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= 0;wren2      <= 0;flag2      <=0;endendcase
end//start
always @(posedge clk) beginif(!rst_n) begindata_tx <= 0;start   <= 0;endelsecase (cur_state)IDLE:begindata_tx <= 0;start   <= 0;endRAM1:begindata_tx <= 0;if(wraddress1 == NUM - 1)start   <= 1;elsestart   <= 0;endW2R1:begindata_tx <= q1;if(rden1)start   <= 1;elsestart   <= 0;endW1R2: begindata_tx <= q2;if(rden2)start   <= 1;elsestart   <= 0;enddefault: begindata_tx <= 0;start   <= 0;endendcase
endram	ram_inst1 (.aclr ( !rst_n ),.clock ( clk ),.data ( data1 ),.rdaddress ( rdaddress1 ),.rden ( rden1 ),.wraddress ( wraddress1 ),.wren ( wren1 ),.q ( q1 ));ram	ram_inst2 (.aclr ( !rst_n ),.clock ( clk ),.data ( data2 ),.rdaddress ( rdaddress2 ),.rden ( rden2 ),.wraddress ( wraddress2 ),.wren ( wren2 ),.q ( q2 ));endmodule

tx.v

 module tx (input   wire            clk       ,input   wire            rst_n     ,input   wire    [7:0]   data_tx   ,//并行输入 --- 变化input   wire            start     ,//数据有效信号output  wire            tx        ,  //串行输出output  wire            done_tx     //字节传输完成);parameter   sysclk = 50_000_000  ,//系统时钟下:1sbps    = 115200      , //波特率delay  = sysclk / bps;//1bit工作周期reg  [7:0]   data_reg;reg  [12:0]  cnt;//周期计数reg  [3:0]   cnt_bit;//bit计数reg en_tx ;reg tx_reg;//发送数据寄存器//寄存数据always @(posedge clk) beginif(!rst_n)data_reg <= 0;else if(start)data_reg <= data_tx;elsedata_reg <= data_reg;end//产生使能信号always @(posedge clk) beginif(!rst_n)en_tx <= 0;else if (start)en_tx <= 1;else if ( cnt_bit == 9  && cnt == delay - 1)en_tx <= 0;elseen_tx <= en_tx;end//周期计数always @(posedge clk) beginif(!rst_n)cnt <= 0;else if (  en_tx ) beginif (cnt == delay - 1)cnt <= 0;else cnt <= cnt + 1;endelsecnt <= 0;end//bit 计数always @(posedge clk) beginif(!rst_n)cnt_bit <= 0;else if (en_tx == 1) begin //使能打开if( cnt == delay - 1 ) begin // 周期计数最大值if(cnt_bit == 9) // bit最大值cnt_bit <= 0;else cnt_bit <= cnt_bit + 1;end else cnt_bit <= cnt_bit;endelse //使能关闭cnt_bit <= 0;end//发送数据always @(posedge clk) beginif(!rst_n)tx_reg <= 1; //空闲else if( en_tx )beginif ( cnt_bit == 0 )tx_reg <= 0; //起始位 else if( cnt_bit > 0 && cnt_bit < 9 ) //数据位tx_reg <= data_reg[cnt_bit - 1]; //起始位 elsetx_reg <= 1; //停止位endelsetx_reg <= 1; //空闲endassign tx      = tx_reg;assign done_tx = (cnt_bit == 9 && cnt == delay - 1) ? 1 : 0;//长 or 短endmodule

top.v

module top (
input   wire    clk     ,
input   wire    rst_n   ,
input   wire    key     ,
output  wire    tx          
);
//rom
wire      [7:0]     data_rom;
wire                rom_wren;
//key
wire    key_out;
//ctrl//tx
wire    [7:0]   data_tx;
wire            start  ;
wire            done_tx;ctrl ctrl_u(
.     clk        (clk     )  ,
.     rst_n      (rst_n   )  ,
.     data_rom   (data_rom)  ,//并行数据 ,其它模块用
.     done_tx    (done_tx )  ,    //字节传输完成
.     rom_wren   (rom_wren)  ,
.     data_tx    (data_tx )  ,//并行输入 --- 变化
.     start      (start   )   //数据有效信号
);rom_ctrl rom_ctrl_u(
.     clk       (clk     )  ,
.     rst_n     (rst_n   )  ,
.     key_out   (key_out )  ,
.     data_rom  (data_rom)  ,
.     rom_wren  (rom_wren)          
);tx tx_u(
.   clk      (clk    ) ,
.   rst_n    (rst_n  ) ,
.   data_tx  (data_tx) ,//并行输入 --- 变化
.   start    (start  ) ,//数据有效信号
.   tx       (tx     ) ,  //串行输出
.   done_tx  (done_tx)   //字节传输完成
);key key_u(
.   clk    (clk    ) ,
.   rst_n  (rst_n  ) ,
.   key    (key    ) ,
.   key_out(key_out)
);endmodule


六、现象


以上就是用RAM来实现乒乓缓存。

http://www.dtcms.com/a/313894.html

相关文章:

  • docker容器命令
  • Dbeaver数据库的安装和使用(保姆级别)
  • 嵌入式硬件篇---OpenMV存储
  • 精品PPT | 企业数字化运营平台总体规划建设方案
  • LeetCode热题100——42. 接雨水
  • AI绘画-Stable Diffusion-WebUI的ControlNet用法
  • 设计模式(一)——抽象工厂模式
  • 蓝河操作系统(BlueOS)内核 (VIVO开源)
  • [spring-cloud: 负载均衡]-源码分析
  • Nginx服务做负载均衡网关
  • Rust ⽣成 .wasm 的极致瘦⾝之道
  • 旧物回收小程序:开启绿色生活新篇章
  • SpringBoot3.x入门到精通系列:3.2 整合 RabbitMQ 详解
  • Ethereum:智能合约开发者的“瑞士军刀”OpenZeppelin
  • 白杨SEO:百度搜索开放平台发布AI计划是什么?MCP网站红利来了?顺带说说其它
  • 剧本杀小程序系统开发:开启沉浸式推理社交新纪元
  • 力扣 hot100 Day65
  • 《Python 实用项目与工具制作指南》 · 前言
  • [自动化Adapt] GUI交互(窗口/元素) | 系统配置 | 非侵入式定制化
  • [特殊字符]️ 整个键盘控制无人机系统框架
  • Qt按键响应
  • 更智能的 RibbonBar Spread.NET 18.2Crack
  • QT:交叉编译mysql驱动库
  • 基于鼠标位置的相机缩放和平移命令的实现(原理+源码)
  • Prompt Engineering
  • 赛博威携手Dify,助力AI在企业的场景化落地
  • 【数据库】使用Sql Server创建索引优化查询速度,一般2万多数据后,通过非索引时间字段排序查询出现超时情况
  • Linux(centos)安全狗
  • Linux 用户与组管理全解析
  • 采购管理工具的实施方法论:三阶段框架与常见问题解决方案