FPGA——串口传图到RAM并TFT显示
一、设计思路
- RAM读问题
RAM为了使得性能更好加了输出寄存器,时钟上升沿读到地址后的三个时钟周期才会输出该地址的数据,这就会让读端的首地址读多次造成结果上的不准确
解决方法有两种:一、让DATA_VLD提前几拍,经过验证该方法会造成计数器与数据不匹配,由此带来的一系列问题不是很好解决。二、让TFT的控制信号(行同步信号,场同步信号,有效数据使能信号)延迟几排生效,归根结底是为了校正TFT的数据输出控制信号(hcount,vcount),TFT的大部分问题都与这两个信号有关。
二、串口接收模块
module my_uart_rx(
rst_n ,
clk ,
uart_rx ,
baud_set ,
data ,
rx_done
);
parameter DATA_W = 8; //接收数据位宽
parameter BAUD_W = 10; //波特率计数器位宽
parameter SYNC_W = 3; //边沿检测信号位宽
parameter SAMP_N = 16; //采样点个数,每个比特16个采样点
parameter SAMP_W = 4; //采样点位宽
parameter BYTE_W = 4; //比特计数器位宽
parameter BYTE_N = 9; //比特计数器个数,不需要对空闲位进行处理
parameter BAUDS_W = 3; //波特率设置器的位宽
input rst_n;
input clk;
input uart_rx;
input [BAUDS_W-1:0] baud_set;
output [DATA_W-1:0] data;
output rx_done;
reg [DATA_W-1:0] data;
reg rx_done;
reg [BAUD_W-1:0] cnt_baud;
wire add_cnt_baud;
wire end_cnt_baud;
reg [SAMP_W-1:0] cnt_sample;
wire add_cnt_sample;
wire end_cnt_sample;
reg [BYTE_W-1:0] cnt_byte;
wire add_cnt_byte;
wire end_cnt_byte;
reg [BAUD_W-1:0] baud;
reg [SYNC_W-1:0] uart_sync;
//寄存器数组,表示9个位宽为3的寄存器,用来存放采样点
reg [2:0] data_tmp[8:0];
wire nedge_flag;
reg add_flag;
//波特率计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_baud <= 0;
else if(add_cnt_baud)begin
if(end_cnt_baud)
cnt_baud <= 0;
else
cnt_baud <= cnt_baud + 1'b1;
end
end
assign add_cnt_baud = add_flag;
assign end_cnt_baud = add_cnt_baud && cnt_baud == baud - 1;
//采样点计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_sample <= 0;
else if(add_cnt_sample)begin
if(end_cnt_sample)
cnt_sample <= 0;
else
cnt_sample <= cnt_sample + 1'b1;
end
end
assign add_cnt_sample = end_cnt_baud;
assign end_cnt_sample = add_cnt_sample && cnt_sample == SAMP_N - 1;
//比特计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_byte <= 0;
else if(add_cnt_byte)begin
if(end_cnt_byte)
cnt_byte <= 0;
else
cnt_byte <= cnt_byte + 1'b1;
end
end
assign add_cnt_byte = end_cnt_sample;
assign end_cnt_byte = add_cnt_byte && cnt_byte == BYTE_N - 1;
//取1bit数据中间的7个点进行采样计算
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_tmp[0] <= 0;
data_tmp[1] <= 0;
data_tmp[2] <= 0;
data_tmp[3] <= 0;
data_tmp[4] <= 0;
data_tmp[5] <= 0;
data_tmp[6] <= 0;
data_tmp[7] <= 0;
data_tmp[8] <= 0;
end
else if(cnt_baud==((baud>>2) - 1) && add_cnt_baud)begin
case(cnt_sample)
5,6,7,8,9,10,11:data_tmp[cnt_byte] <= data_tmp[cnt_byte] + uart_rx;
default:data_tmp[cnt_byte] <= data_tmp[cnt_byte];
endcase
end
else if(end_cnt_byte)begin
data_tmp[0] <= 0;
data_tmp[1] <= 0;
data_tmp[2] <= 0;
data_tmp[3] <= 0;
data_tmp[4] <= 0;
data_tmp[5] <= 0;
data_tmp[6] <= 0;
data_tmp[7] <= 0;
data_tmp[8] <= 0;
end
end
//判断采样点0,1的个数如果一个比特位采到1的个数比0多,那么输出1,否则输出0
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data <= 0;
else if(end_cnt_sample && cnt_byte >= 1 && cnt_byte < 9)
data[cnt_byte-1] <= (data_tmp[cnt_byte] >= 4);
end
// 波特率选择器,16点采样
// (1/baud_rate)*50MHz/16
always @(*)begin
case(baud_set)
3'd0:baud = 5208;//600bps
3'd1:baud = 2604;//1200bps
3'd2:baud = 1302;//2400bps
3'd3:baud = 651 ;//4800bps
3'd4:baud = 325 ;//9600bps
3'd5:baud = 163 ;//19200bps
3'd6:baud = 81 ;//38400bps
3'd7:baud = 54 ;//57600bps
default:baud = 325;
endcase
end
//边沿检测
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
uart_sync <= 3'b111;
else
uart_sync <= {uart_sync[1:0],uart_rx};
end
assign nedge_flag = uart_sync[2:1]==2'b10;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
rx_done <= 0;
else if(end_cnt_byte)
rx_done <= 1;
else
rx_done <= 0;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
add_flag <= 0;
else if(nedge_flag)
add_flag <= 1;
else if(end_cnt_byte)
add_flag <= 0;
end
endmodule
三、串口8位转16位模块
module uart_rx_2bytes(
clk ,
rst_n ,
data_in ,
rx_done ,
data_out ,
turn_done,
cnt_addr
);
localparam DATA_IN_W = 8;
localparam DATA_OUT_W = 16;
localparam CNT_W = 2;
localparam CNT_N = 2;
localparam H_N = 256; //图像行像素个数
localparam V_N = 256; //图像场像素个数
localparam IMAGE_N = H_N*V_N; //图像像素个数
localparam CNTA_W = 16;
input clk;
input rst_n;
input [DATA_IN_W-1:0] data_in;
input rx_done;
output [DATA_OUT_W-1:0] data_out;
output turn_done;
output [CNTA_W-1:0] cnt_addr;
reg [DATA_OUT_W-1:0] data_out;
reg turn_done;
reg [CNT_W-1:0] cnt_2bytes;
wire add_cnt_2bytes;
wire end_cnt_2bytes;
reg [CNTA_W-1:0] cnt_addr;
wire add_cnt_addr;
wire end_cnt_addr;
//两字节数据计数
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_2bytes <= 0;
else if(add_cnt_2bytes)begin
if(end_cnt_2bytes)
cnt_2bytes <= 0;
else
cnt_2bytes <= cnt_2bytes + 1'b1;
end
end
assign add_cnt_2bytes = rx_done;
assign end_cnt_2bytes = add_cnt_2bytes && cnt_2bytes == CNT_N - 1;
//RAM写地址计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_addr <= 0;
else if(add_cnt_addr)begin
if(end_cnt_addr)
cnt_addr <= 0;
else
cnt_addr <= cnt_addr + 1'b1;
end
end
assign add_cnt_addr = end_cnt_2bytes;
assign end_cnt_addr = add_cnt_addr && cnt_addr == IMAGE_N - 1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data_out <= 0;
else if(rx_done)
data_out <= {data_out[7:0],data_in};
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
turn_done <= 0;
else if(end_cnt_2bytes)
turn_done <= 1;
else
turn_done <= 0;
end
endmodule
四、发送端仿真验证代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2021/01/31 20:46:23
// Design Name:
// Module Name: uart_2bytes_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_2bytes_tb();
reg rst_n;
reg clk;
reg clkb;
reg uart_rx;
reg enb;
reg flag;
reg [15:0] addrb;
wire [7:0] data;
wire rx_done;
wire turn_done;
wire [15:0] data_out;
wire [15:0] cnt_addr;
wire [15:0] doutb;
my_uart_rx my_uart_rx(
.rst_n (rst_n),
.clk (clk),
.uart_rx (uart_rx),
.baud_set (4'd4),
.data (data),
.rx_done (rx_done)
);
uart_rx_2bytes uart_rx_2bytes(
.clk (clk),
.rst_n (rst_n),
.data_in (data),
.rx_done (rx_done),
.data_out (data_out),
.turn_done (turn_done),
.cnt_addr (cnt_addr)
);
image_ram image_ram (
.clka(clk), // reg wire clka
.ena(1), // reg wire ena
.wea(turn_done), // reg wire [0 : 0] wea
.addra(cnt_addr), // reg wire [15 : 0] addra
.dina(data_out), // reg wire [15 : 0] dina
.clkb(clkb), // reg wire clkb
.enb(enb), // reg wire enb
.addrb(addrb), // reg wire [15 : 0] addrb
.doutb(doutb) // output wire [15 : 0] doutb
);
//时钟周期,单位ns,在这里修改时钟周期
parameter CYCLE = 20;
parameter CYCLEB = 30;
//复位时间,此时表示复位3个时钟周期的时间
parameter RST_TIME = 3;
//生成本地时钟50M
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
initial begin
clkb = 0;
forever
#(CYCLEB/2)
clkb=~clkb;
end
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE * RST_TIME);
rst_n = 1;
end
//输入信号din0赋值方式
initial begin
flag = 0;
uart_rx = 1'b1;
@(posedge rst_n);
#(8*CYCLE);
uart_tx(8'hAA);
uart_tx(8'h78);
uart_tx(8'h38);
uart_tx(8'h47);
#1000;
flag = 1;
end
initial begin
addrb = 0;
enb = 0;
@ (posedge flag);
enb = 1;
repeat(3)begin
#(CYCLEB)
addrb = addrb + 1'b1;
end
#1000;
$stop;
end
task uart_tx;
input [7:0] data_in;
begin
uart_rx = 1'b0;
#(5208*CYCLE);
uart_rx = data_in[0];
#(5208*CYCLE);
uart_rx = data_in[1];
#(5208*CYCLE);
uart_rx = data_in[2];
#(5208*CYCLE);
uart_rx = data_in[3];
#(5208*CYCLE);
uart_rx = data_in[4];
#(5208*CYCLE);
uart_rx = data_in[5];
#(5208*CYCLE);
uart_rx = data_in[6];
#(5208*CYCLE);
uart_rx = data_in[7];
#(5208*CYCLE);
uart_rx = 1'b1;
#(CYCLE);
end
endtask
endmodule
五、RAM读取到TFT模块
module ram_to_tft(
clk ,
rst_n ,
data_vld ,
data_in ,
vcount ,
hcount ,
read_addr ,
data_out
);
`include "tft_parameter.v"
localparam DATA_W = 16;
localparam CNT_HSYC_W = `CNT_HSYC_W;
localparam CNT_VSYC_W = `CNT_VSYC_W;
localparam ADDR_W = 16;
localparam H_N = 256; //图像行像素个数
localparam V_N = 256; //图像场像素个数
localparam IMAGE_N = H_N*V_N; //图像像素个数
localparam CNTA_W = 16;
input clk;
input rst_n;
input data_vld;
input [DATA_W-1:0] data_in;
input [CNT_VSYC_W-1:0] vcount;
input [CNT_HSYC_W-1:0] hcount;
output [ADDR_W-1:0] read_addr;
output [DATA_W-1:0] data_out;
wire [ADDR_W-1:0] read_addr;
wire [DATA_W-1:0] data_out;
reg [CNTA_W-1:0] cnt_addr;
wire add_cnt_addr;
wire end_cnt_addr;
//RAM读地址计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_addr <= 0;
else if(add_cnt_addr)begin
if(end_cnt_addr)
cnt_addr <= 0;
else
cnt_addr <= cnt_addr + 1'b1;
end
end
assign add_cnt_addr = (hcount >= 272 && hcount < 528) && (vcount >= 112 && vcount < 368) && data_vld;
assign end_cnt_addr = add_cnt_addr && cnt_addr == IMAGE_N - 1;
assign data_out = add_cnt_addr ? data_in : 0;
assign read_addr = cnt_addr;
endmodule
六、延迟三拍的TFT模块
module tft_ctr(
clk , //TTF驱动时钟
rst_n , //复位电路
data_in , //RGB三基色输入
data_out , //RGB三基色输出
hsyc , //行同步信号
vsyc , //场同步信号
data_vld,
hcount , //当前扫描点的h坐标
vcount , //当前扫描点的v坐标
blk //数据有效输出信号
);
`include "tft_parameter.v"
localparam H_SYNC_END = `H_SYNC_TIME;
//数据开始设置在数据左黑边过去之后,而不是时序图上的数据开始
localparam H_DATA_BEGIN = `H_SYNC_TIME + `H_BACK_PORCH + `H_LEFT_BORDER;
//数据结束设置在数据右黑边来到之前,而不是时序图上的数据结束
localparam H_DATA_END = `H_SYNC_TIME + `H_BACK_PORCH + `H_LEFT_BORDER + `H_DATA_TIME;
localparam H_SYNC_BEGIN = `H_SYNC_TIME + `H_BACK_PORCH + `H_LEFT_BORDER + `H_DATA_TIME + `H_RIGHT_BORDER + `H_FRONT_PORCH;
localparam V_SYNC_END = `V_SYNC_TIME;
//数据开始设置在数据左黑边过去之后,而不是时序图上的数据开始
localparam V_DATA_BEGIN = `V_SYNC_TIME + `V_BACK_PORCH + `V_TOP_BORDER;
//数据结束设置在数据右黑边来到之前,而不是时序图上的数据结束
localparam V_DATA_END = `V_SYNC_TIME + `V_BACK_PORCH + `V_TOP_BORDER + `V_DATA_TIME;
localparam V_SYNC_BEGIN = `V_SYNC_TIME + `V_BACK_PORCH + `V_TOP_BORDER + `V_DATA_TIME + `V_BOTTOM_BORDER + `V_FRONT_PORCH;
//输入输出
localparam DATA_W = 16;
//计数器
localparam CNT_HSYC_N = `H_TOTAL_TIME;
localparam CNT_HSYC_W = `CNT_HSYC_W;
localparam CNT_VSYC_N = `V_TOTAL_TIME;
localparam CNT_VSYC_W = `CNT_VSYC_W;
input clk;
input rst_n;
input [DATA_W-1:0] data_in;
output [DATA_W-1:0] data_out;
output hsyc;
output vsyc;
output blk;
output data_vld;
output [CNT_HSYC_W-1:0] hcount;
output [CNT_VSYC_W-1:0] vcount;
reg [DATA_W-1:0] data_out;
wire hsyc;
wire vsyc;
reg data_count_vld;
wire blk;
reg data_vld;
reg [CNT_HSYC_W-1:0] hcount;
reg [CNT_VSYC_W-1:0] vcount;
//计数器
reg [CNT_HSYC_W-1:0] cnt_hsyc;
wire add_cnt_hsyc;
wire end_cnt_hsyc;
reg [CNT_VSYC_W-1:0] cnt_vsyc;
wire add_cnt_vsyc;
wire end_cnt_vsyc;
reg [4-1:0] hsyc_tmp;
reg [4-1:0] vsyc_tmp;
reg [4-1:0] blk_tmp;
//行同步计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_hsyc <= 0;
else if(add_cnt_hsyc)begin
if(end_cnt_hsyc)
cnt_hsyc <= 0;
else
cnt_hsyc <= cnt_hsyc + 1'b1;
end
end
assign add_cnt_hsyc = 1;
assign end_cnt_hsyc = add_cnt_hsyc && cnt_hsyc == CNT_HSYC_N - 1;
//场同步计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_vsyc <= 0;
else if(add_cnt_vsyc)begin
if(end_cnt_vsyc)
cnt_vsyc <= 0;
else
cnt_vsyc <= cnt_vsyc + 1'b1;
end
end
assign add_cnt_vsyc = end_cnt_hsyc;
assign end_cnt_vsyc = add_cnt_vsyc && cnt_vsyc == CNT_VSYC_N - 1;
//输出比输入慢一拍,hcount,vcount要先于输出一拍产生数据
//行有效数据计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
hcount <= 0;
else if(data_count_vld)
hcount <= (cnt_hsyc - (H_DATA_BEGIN - 2));
else if(hcount == `H_DATA_TIME - 1)
hcount <= 0;
end
//场有效数据计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
vcount <= 0;
else if(data_count_vld)
vcount <= cnt_vsyc - V_DATA_BEGIN;
else if(vcount == `V_DATA_TIME - 1)
vcount <= 0;
end
//行同步信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
hsyc_tmp <= 0;
else if(cnt_hsyc == H_SYNC_END - 1 && add_cnt_hsyc)begin
hsyc_tmp[0] <= 1'b1;
hsyc_tmp[3:1] <= hsyc_tmp[2:0];
end
else if(cnt_hsyc == H_SYNC_BEGIN -1 && add_cnt_hsyc)begin
hsyc_tmp[0] <= 1'b0;
hsyc_tmp[3:1] <= hsyc_tmp[2:0];
end
end
assign hsyc = hsyc_tmp[2];
//场同步信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
vsyc_tmp <= 0;
else if(cnt_vsyc == V_SYNC_END - 1 && add_cnt_vsyc)begin
vsyc_tmp[0] <= 1'b1;
vsyc_tmp[3:1] <= vsyc_tmp[2:0];
end
else if(cnt_vsyc == V_SYNC_BEGIN - 1 && add_cnt_vsyc)begin
vsyc_tmp[0] <= 1'b0;
vsyc_tmp[3:1] <= vsyc_tmp[2:0];
end
end
assign vsyc = vsyc_tmp[2];
//数据传输标志位
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
blk_tmp <= 0;
else if(data_vld)begin
blk_tmp[0] <= 1'b1;
blk_tmp[3:1] <= blk_tmp[2:0];
end
else begin
blk_tmp[0] <= 1'b0;
blk_tmp[3:1] <= blk_tmp[2:0];
end
end
assign blk = blk_tmp[2];
//数据传输使能信号,比blk提前一拍,为了数据传输与blk同步
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data_vld <= 0;
else if(data_count_vld)
data_vld <= 1;
else
data_vld <= 0;
end
//有效数据指示信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data_count_vld <= 0;
else if((cnt_hsyc >= H_DATA_BEGIN - 3 && cnt_hsyc < H_DATA_END - 3) && (cnt_vsyc >= V_DATA_BEGIN && cnt_vsyc < V_DATA_END))
data_count_vld <= 1;
else
data_count_vld <= 0;
end
//数据传输
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data_out <= 0;
else if(data_vld)
data_out <= data_in;
else
data_out <= 0;
end
endmodule
七、接收端仿真验证代码
注:要先在RAM里设置一张图像数据
`timescale 1ns / 1ns
module ram_to_ftf_tb();
reg clk;
reg rst_n;
wire [15:0] addrb;
wire [15:0] doutb;
wire [10:0] hcount;
wire [9:0] vcount;
wire data_vld;
wire [15:0] data_out;
wire [15:0] dout;
wire hsyc;
wire vsyc;
image_ram image_ram (
.clkb(clk), // reg wire clkb
.enb(1), // reg wire enb
.addrb(addrb), // reg wire [15 : 0] addrb
.doutb(doutb) // output wire [15 : 0] doutb
);
ram_to_tft ram_to_tft(
.clk (clk),
.rst_n (rst_n),
.data_vld (data_vld),
.data_in (doutb),
.vcount (vcount),
.hcount (hcount),
.read_addr (addrb),
.data_out (data_out)
);
tft_ctr tft_ctr(
.clk (clk), //TTF驱动时钟
.rst_n (rst_n), //复位电路
.data_in (data_out), //RGB三基色输入
.data_out (dout), //RGB三基色输出
.hsyc (hsyc), //行同步信号
.vsyc (vsyc), //场同步信号
.data_vld (data_vld), //数据传完标志信号
.hcount (hcount), //当前扫描点的h坐标
.vcount (vcount), //当前扫描点的v坐标
.blk (blk) //数据有效输出信号
);
//时钟周期,单位ns,在这里修改时钟周期
parameter CYCLE = 20;
//复位时间,此时表示复位3个时钟周期的时间
parameter RST_TIME = 3;
//生成本地时钟50M
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE * RST_TIME);
rst_n = 1;
end
endmodule
八、接收端板级验证代码
`timescale 1ns / 1ns
module ram_to_tft_test(
clk ,
rst_n ,
dout ,
hsyc ,
vsyc ,
de ,
tftclk ,
bl
);
input clk;
input rst_n;
output [15:0] dout;
output hsyc;
output vsyc;
output de;
output bl;
output tftclk;
wire [15:0] dout;
wire hsyc;
wire vsyc;
wire de;
wire bl;
wire [15:0] addrb;
wire [15:0] doutb;
wire [10:0] hcount;
wire [9:0] vcount;
wire data_vld;
wire [15:0] data_out;
wire tftclk;
tft_clk tft_clk(
.clk_out1(tftclk),
.clk_in1(clk)
);
image_ram image_ram (
.clka(0), // reg wire clka
.ena(0), // reg wire ena
.wea(0), // reg wire [0 : 0] wea
.addra(0), // reg wire [15 : 0] addr
.dina(0), // reg wire [15 : 0] din
.clkb(tftclk), // reg wire clkb
.enb(1), // reg wire enb
.addrb(addrb), // reg wire [15 : 0] addrb
.doutb(doutb) // output wire [15 : 0] doutb
);
ram_to_tft ram_to_tft(
.clk (tftclk),
.rst_n (rst_n),
.data_vld (data_vld),
.data_in (doutb),
.vcount (vcount),
.hcount (hcount),
.read_addr (addrb),
.data_out (data_out)
);
tft_ctr tft_ctr(
.clk (tftclk), //TTF驱动时钟
.rst_n (rst_n), //复位电路
.data_in (data_out), //RGB三基色输入
.data_out (dout), //RGB三基色输出
.hsyc (hsyc), //行同步信号
.vsyc (vsyc), //场同步信号
.data_vld (data_vld), //数据传完标志信号
.hcount (hcount), //当前扫描点的h坐标
.vcount (vcount), //当前扫描点的v坐标
.blk (de) //数据有效输出信号
);
assign bl = 1;
endmodule
九、顶层文件代码
module tft_ram_uart_top(
clk ,
rst_n ,
uart_rx ,
dout ,
hsyc ,
vsyc ,
de ,
bl ,
tftclk
);
`include "tft_parameter.v"
localparam CNT_HSYC_W = `CNT_HSYC_W;
localparam CNT_VSYC_W = `CNT_VSYC_W;
input clk;
input rst_n;
input uart_rx;
output [15:0] dout;
output hsyc;
output vsyc;
output de;
output tftclk;
output bl;
wire [15:0] dout;
wire hsyc;
wire vsyc;
wire de;
wire tftclk;
wire bl;
//连线
wire [7:0] data;
wire rx_done;
wire turn_done;
wire [15:0] data_out;
wire [15:0] cnt_addr;
wire [15:0] addrb;
wire [15:0] doutb;
wire data_vld;
wire [CNT_VSYC_W-1:0] vcount;
wire [CNT_HSYC_W-1:0] hcount;
wire [15:0] ram_data_out;
assign bl = 1;
my_uart_rx my_uart_rx(
.rst_n (rst_n),
.clk (clk),
.uart_rx (uart_rx),
.baud_set (3'd6),
.data (data),
.rx_done (rx_done)
);
uart_rx_2bytes uart_rx_2bytes(
.clk (clk),
.rst_n (rst_n),
.data_in (data),
.rx_done (rx_done),
.data_out (data_out),
.turn_done(turn_done),
.cnt_addr (cnt_addr)
);
tft_clk tft_clk(
.clk_out1(tftclk),
.clk_in1(clk)
);
image_ram image_ram (
.clka(clk), // reg wire clka
.ena(1), // reg wire ena
.wea(turn_done), // reg wire [0 : 0] wea
.addra(cnt_addr), // reg wire [15 : 0] addra
.dina(data_out), // reg wire [15 : 0] dina
.clkb(tftclk), // reg wire clkb
.enb(1), // reg wire enb
.addrb(addrb), // reg wire [15 : 0] addrb
.doutb(doutb) // output wire [15 : 0] doutb
);
ram_to_tft ram_to_tft(
.clk (tftclk),
.rst_n (rst_n),
.data_vld (data_vld),
.data_in (doutb),
.vcount (vcount),
.hcount (hcount),
.read_addr (addrb),
.data_out (ram_data_out)
);
tft_ctr tft_ctr(
.clk (tftclk), //TTF驱动时钟
.rst_n (rst_n), //复位电路
.data_in (ram_data_out), //RGB三基色输入
.data_out (dout), //RGB三基色输出
.hsyc (hsyc), //行同步信号
.vsyc (vsyc), //场同步信号
.data_vld (data_vld), //数据传完标志信号
.hcount (hcount), //当前扫描点的h坐标
.vcount (vcount), //当前扫描点的v坐标
.blk (de) //数据有效输出信号
);
endmodule
十、条件编译参数文件
`define resolution_800x480;
`ifdef resolution_800x480
`define H_RIGHT_BORDER 12'd0
`define H_FRONT_PORCH 12'd40
`define H_SYNC_TIME 12'd128
`define H_BACK_PORCH 12'd88
`define H_LEFT_BORDER 12'd0
`define H_DATA_TIME 12'd800
`define H_TOTAL_TIME 12'd1056
`define V_BOTTOM_BORDER 12'd8
`define V_FRONT_PORCH 12'd2
`define V_SYNC_TIME 12'd2
`define V_BACK_PORCH 12'd25
`define V_TOP_BORDER 12'd8
`define V_DATA_TIME 12'd480
`define V_TOTAL_TIME 12'd525
`define CNT_HSYC_W 11
`define CNT_VSYC_W 10
// `elsif
`endif
十一、效果展示