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

十一、效果展示



posted @ 2021-02-01 21:46  AdriftCore  阅读(377)  评论(0编辑  收藏  举报