zl程序教程

您现在的位置是:首页 >  后端

当前栏目

重温FPGA开发34

开发 FPGA 34 重温
2023-09-14 09:09:12 时间

RAM的应用介绍

Random Access Memory

ROM 只读不写
RAM 即可读 又可写

使用RAM存储一张图片的数据,并在TFT显示屏上显示出来。
可以使用串口传输数据到RAM中,更改RAM的内容,以修改显示的内容。

single port ram: 只有一个地址端口,同一时刻只能读或者写
simple dual port ram:有两个地址端口,一个地址对应读,一个对应写
true dual port ram:有两个地址端口,每个端口都能读或者写

RAM容量的计算
7A35T:由50个block RAM,每个RAM可以配置为2k18位的模式,250=100k个16/18 位的存储器单元

每个像素有16位
800x480 = 384000个16位数据

RAM是一种可以写的ROM

在这里插入图片描述

RAM_tb.v

`timescale 1ns/1ps

module RAM_tb();
	reg clka;
	reg ena;
	reg wea;
	reg [15:0]addra;
	reg [15:0]dina;
	reg clkb;
	reg enb;
	reg [15:0]addrb;
	wire [15:0]doutb;

RAM RAM(
	.clka(clka),
	.ena(ena),
	.wea(wea),
	.addra(addra),
	.dina(dina),
	.clkb(clkb),
	.enb(enb),
	.addrb(addrb),
	.doutb(doutb)    // output wire[15:0] doutb
	);
	
	// 先写满 再读出来
	initial clka = 1;
	always #10 clka = ~clka;

	intital clkb = 1;
	always #15 clkb = ~clkb;

	initial begin
		ena = 0;
		wea = 0;
		addra = 0;
		addrb = 0;
		dina = 0;
		enb = 0;
		#201;
		repeat(65536) begin
			ena = 1;
			wea = 1;
			#20;
			dina = dina + 1;
			addra = addra + 1;
		end
		ena = 0;
		wea = 0;
		#20000;
		addrb = 65535;
		#200;
		repeat(65536) begin
			enb = 1;
			#20;
			addrb = addrb - 1;
		end
		#2000;
		$stop
	end
endmodule

存储器的使用,在开始读写或者结束读写的位置非常容易出现数据错误或者遗失

串口接收的数据一次接收一个字节 8位
所以串口每接收2个字节的数据组成一个像素的值
ram 的位宽是16位

img_rx_wr.v

module img_rx_wr(
	Clk,
	Reset,
	rx_data,
	rx_done,
	ram_wren,
	ram_wraddr,
	ram_wrdata
	);

	input Clk;
	input Reset;
	input [7:0]rx_data;
	input rx_done;
	output ram_wren;
	output [15:0]ram_wraddr;
	output [15:0]ram_wrdata;

	reg [16:0] data_cnt;  // 统计串口接受的数据个数计数器
	
	always@(posedge Clk or negedge Reset)
	if(!Reset)
		data_cnt <= 0;
	else if(rx_done)
		data_cnt <= data_cnt + 1'd1;

	// 两个8位数据 进行拼接
	reg [15:0] rx_data_tmp;
	

	always@(posedge Clk or negedge Reset)
	if(!Reset)
		rx_data_tmp <= 0;
	else if(rx_done)
		rx_data_tmp <= {rx_data_tmp[7:0], rx_data};

	always@(posedge Clk or negedge Reset)
	if(!Reset)
		ram_wren <= 0;
	else if(rx_done && data_cnt[0])
		ram_wren <= 1'd1;
	else
		ram_wren <= 0;
	
	always@(posedge Clk or negedge Reset)
	if(!Reset)
		ram_wraddr <= 0;
	else if(rx_done && data_cnt[0])
		ram_wraddr <= data_cnt[16:1];
		
	// 写入的数据 	// 这里最好改成组合逻辑,因为寄存器会有延迟
	always@(posedge Clk or negedge Reset)
	if(!Reset)
		ram_wraddr <= 0;
	else if(rx_done && data_cnt[0])
		ram_wrdata <= rx_data_tmp;
			
	
	

endmodule
	

testbench.v

`timescale 1ns/1ps

module img_rx_wr_tb();

	reg Clk;
	reg Reset;
	reg [7:0]rx_data;
	reg rx_done;
	wire ram_wren;
	wire [15:0]ram_wraddr;
	wire [15:0]ram_wrdata;

	img_rx_wr img_rx_wr(
	Clk,
	Reset,
	rx_data,
	rx_done,
	ram_wren,
	ram_wraddr,
	ram_wrdata,
	);

	initial Clk = 1;
	always#10 Clk = ~Clk;

	initial begin
		Reset = 0;
		rx_data = 0;
		rx_done = 0;
		#201;
		Reset = 1;
		#2000;
		rx_data = 255;
		repeat(131072)	begin
			rx_done = 1;
			#20;
			rx_done = 0;
			#200;
			rx_data = rx_data - 1;
		end
		#20000;
		
		repeat(131072)	begin
			rx_done = 1;
			#20;
			rx_done = 0;
			#200;
			rx_data = rx_data - 1;
		end
		#20000;	
	

endmodule