fpga项目: st7796 mcu接口‐‐v2版代码 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

1)画时序图

  • 推荐用excel表,比visio或者timegen都要简单,好用,灵活。
  • 单元格:高度设为20,宽度设为2。

2)代码

image

改进点:

  • 先画时序图,严格按照时序图写
  • 采用了状态机的方法。感觉用状态机还是简单和正规一点。
  • 采用了request的方法,底层传输完一个byte后产生一个request信号,然后上层收到request后,再填充一个byte。
  • 刷图部分,大片相同的代码,用task来代替,简化了很多
`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/05 11:47:24
// Design Name: 
// Module Name: fmc_st7796
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module fmc_st7796(
    input clk,
    input rst,
    
    output csx,
    output dcx,
    output wrx,
    output [15:0] po_data,
    output rst_o, 
    output [2:0] im    
    );


parameter NDATA=320*480;
parameter XSTART=0, XEND=319;
parameter YSTART=0, YEND=479;
parameter NDLY=30;

parameter  RED     =   16'hF800,
            ORANGE  =   16'hFC00,
            YELLOW  =   16'hFFE0,
            GREEN   =   16'h07E0,
            CYAN    =   16'h07FF,
            BLUE    =   16'h001F,
            PURPPLE =   16'hF81F,
            BLACK   =   16'h0000,
            WHITE   =   16'hFFFF,
            GRAY    =   16'hD69A;


assign rst_n=~rst;
assign rst_o=rst_n; 
assign im=3'b010;  
    

reg pi_start_pulse;
reg [7:0] pi_cmd;
reg [15:0] pi_data0; 
reg [15:0] pi_data1; 
reg [15:0] pi_data2; 
reg [15:0] pi_data3; 
reg [15:0] pi_datan; 
reg [19:0] pi_nbytes;
wire [9:0] event_o;

always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    pi_start_pulse<=0;
    pi_cmd<=8'h00;
    pi_data0<=16'h0000;
    pi_data1<=16'h0000;
    pi_data2<=16'h0000;
    pi_data3<=16'h0000;    
    pi_datan<=16'h0000;        
    pi_nbytes<=0;
end
else case(event_o)
    2:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h11; 
    pi_nbytes<=0;       
end
    3:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h29; 
    pi_nbytes<=0;      
end
    4:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h36; 
    pi_data0<=16'h48; 
    pi_nbytes<=1;      
end
    5:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h3a; 
    pi_data0<=16'h05;
    pi_nbytes<=1;     
end
    6:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2a; 
    pi_data0<=XSTART/256;
    pi_data1<=XSTART%256;    
    pi_data2<=XEND/256;
    pi_data3<=XEND%256;       
    pi_nbytes<=4;     
end
    7:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2b; 
    pi_data0<=YSTART/256;
    pi_data1<=YSTART%256;    
    pi_data2<=YEND/256;
    pi_data3<=YEND%256;  
    pi_nbytes<=4;      
end
    8:  begin
    xfer_color(RED);    
end
    8+NDLY:  begin
    xfer_color(GREEN);           
end
    8+2*NDLY:  begin
    xfer_color(BLUE);                 
end
    8+3*NDLY:  begin 
    xfer_color(ORANGE);          
end
    8+4*NDLY:  begin 
    xfer_color(CYAN);        
end
    8+5*NDLY:  begin
    xfer_color(PURPPLE);           
end
    8+6*NDLY:  begin
    xfer_color(BLACK);           
end
    8+7*NDLY:  begin
    xfer_color(WHITE);            
end
    8+8*NDLY:  begin
    xfer_color(GRAY);          
end
    default:
    pi_start_pulse<=0;
endcase

fmc_top u_fmc_top(
    .clk(clk),
    .rst_n(rst_n),
    
    .pi_start_pulse(pi_start_pulse),    
    .pi_cmd(pi_cmd),

    .pi_data0(pi_data0),
    .pi_data1(pi_data1),
    .pi_data2(pi_data2),
    .pi_data3(pi_data3),    
    .pi_datan(pi_datan),        
     .pi_nbytes(pi_nbytes),
        
    .csx(csx),
    .dcx(dcx),
    .wrx(wrx),
    .po_data(po_data)
    );

gen_timer_seqs 
//    #( .FCLK(27_00)) 
u_gen_timer_seqs(
    .clk(clk),
    .rst_n(rst_n),
    .event_max_value(8+9*NDLY),
    
    .event_o(event_o)
);

task xfer_color(
    input [15:0] color
    );
    begin    //注意语句段,不要少了begin...end,否则报错
        pi_start_pulse<=1;
        pi_cmd<=8'h2c; 
        pi_data0<=color;
        pi_data1<=color; 
        pi_data2<=color;
        pi_data3<=color;              
        pi_datan<=color;
        pi_nbytes<=NDATA; 
    end  
endtask    
        
endmodule

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/07 12:12:41
// Design Name: 
// Module Name: fmc_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module fmc_top(
    input clk,
    input rst_n,

    input pi_start_pulse,    
    input [7:0] pi_cmd,
    
    input [15:0] pi_data0,
    input [15:0] pi_data1,  
    input [15:0] pi_data2,
    input [15:0] pi_data3,      
    input [15:0] pi_datan,          
    input [19:0] pi_nbytes,        
    
    output csx,
    output dcx,
    output wrx,
    output [15:0] po_data
    );

reg [19:0] byte_cnt=0;
reg [15:0] pi_data;  

//
fmc dut (
  .clk(clk), 
  .rst_n(rst_n),
  .pi_start_pulse(pi_start_pulse),
  .pi_cmd(pi_cmd),
  .pi_data(pi_data), 
  .pi_nbytes(pi_nbytes),
                   
  .csx(csx), 
  .dcx(dcx),
  .wrx(wrx),
  .po_data(po_data),
  .end_pulse(end_pulse)
);
      
//
always@(posedge clk or negedge rst_n) begin
if(rst_n==0) begin
    pi_data<=0;
    byte_cnt<=0;
end
else if(pi_start_pulse)
    byte_cnt<=0;
else if(end_pulse) begin
    if(byte_cnt==0)
         pi_data <= pi_data0;  
    if(byte_cnt==1)
         pi_data <= pi_data1;  
    if(byte_cnt==2)
         pi_data <= pi_data2;  
    if(byte_cnt==3)
         pi_data <= pi_data3;           
     if(byte_cnt>3)
         pi_data <= pi_datan;
                                
    byte_cnt <= byte_cnt + 1;    
  end  
end
		
endmodule


`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/07 09:36:57
// Design Name: 
// Module Name: fmc_new
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module fmc(
    input clk,
    input rst_n,

    input pi_start_pulse,    
    input [7:0] pi_cmd,
    input [15:0] pi_data,          
    input [19:0] pi_nbytes,    
    
    output reg csx,
    output reg dcx,
    output reg wrx,
//    output reg rdx,
    output reg [15:0] po_data,
    output end_pulse
    );

parameter IDLE=3'b001;
parameter CMD=3'b010;
parameter DATA=3'b100;

reg [1:0] cnt0;
reg [19:0] cnt_bytes;
reg [2:0] state;


//cnt0
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    cnt0<=0;
 else if(pi_start_pulse)
    cnt0<=0;
 else if(cnt0==2)
    cnt0<=0;
 else if(state!=IDLE)
    cnt0<=cnt0+1;
    
 //end_pulse
assign end_pulse=(cnt0==2);

//cnt_bytes
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    cnt_bytes<=0;
else if(pi_start_pulse)
    cnt_bytes<=pi_nbytes;
else if(end_pulse && state==DATA)
    cnt_bytes<=cnt_bytes-1;

//state
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    state<=IDLE;
else case(state)
        IDLE: if(pi_start_pulse)
                state<=CMD;
        CMD:  if(cnt_bytes==0 && end_pulse)
                    state<=IDLE;
              else if(cnt_bytes>0 && end_pulse)                
                    state<=DATA;
        DATA: if(cnt_bytes==1 && end_pulse)
                state<=IDLE;
        default: state<=state;
    endcase

//dcx
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    dcx<=0;
 else if(pi_start_pulse)
    dcx<=0;
 else if(state==CMD && end_pulse)
    dcx<=1;
 
 //csx
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    csx<=1;
 else if(pi_start_pulse)
    csx<=0;
  else if(cnt_bytes==0 && end_pulse && state==CMD)
    csx<=1;    
 else if(cnt_bytes==1 && end_pulse && state==DATA)
    csx<=1; 
    
//wrx
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    wrx<=1;
 else if(pi_start_pulse)
    wrx<=0;
 else if(state!=IDLE && cnt0==1)
    wrx<=1;
 else if(pi_nbytes>=1 && state==CMD && cnt0==2)  //这个条件比较复杂:如果数据量>=1,那么CMD模式总是要下拉
    wrx<=0;
 else if(pi_nbytes>1 && state==DATA && cnt_bytes>1 && cnt0==2)  //这个条件比较复杂:如果数据量>=2,那么DATA模式最后一个不要下拉
    wrx<=0; 
    
//po_data
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    po_data<=16'h00;
 else if(state==CMD && cnt0==0)
     po_data<={8'h0,pi_cmd};  
 else if(state==DATA && cnt0==0)
     po_data<=pi_data;     
    
endmodule

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/06 09:48:51
// Design Name: 
// Module Name: timer_gen_seqs
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module gen_timer_seqs(
    input clk,
    input rst_n,
    input [9:0] event_max_value,
    
    output [9:0] event_o
);

parameter FCLK=27_000_000;
parameter DLY_10MS=FCLK/100; 

reg [25:0] timer;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    timer<=0;
else
    timer<=timer+1;

reg timer_flag;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    timer_flag<=0;
else if(timer%DLY_10MS==0)
    timer_flag<=1;
else
    timer_flag<=0;
    
reg [9:0] event_t;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    event_t<=0;
else if(event_t==event_max_value)
    event_t<=0;
else if(timer_flag)
    event_t<=event_t+1;

assign event_o=timer_flag? event_t: 10'd0;  //generate counter-value pulse

endmodule

3)tang nano 20k引脚约束文件

IO_LOC "clk" 4;
IO_LOC "rst" 88;

IO_LOC "im[2]" 73;
IO_LOC "im[1]" 74;
IO_LOC "im[0]" 75;

IO_LOC "po_data[15]" 15;
IO_LOC "po_data[14]" 41;
IO_LOC "po_data[13]" 16;
IO_LOC "po_data[12]" 56;
IO_LOC "po_data[11]" 27;
IO_LOC "po_data[10]" 54;
IO_LOC "po_data[9]" 28;
IO_LOC "po_data[8]" 51;
IO_LOC "po_data[7]" 25;
IO_LOC "po_data[6]" 48;
IO_LOC "po_data[5]" 26;
IO_LOC "po_data[4]" 55;
IO_LOC "po_data[3]" 29;
IO_LOC "po_data[2]" 49;
IO_LOC "po_data[1]" 30;
IO_LOC "po_data[0]" 86;

IO_LOC "rst_o" 79;


//IO_LOC "rdx" 19;
IO_LOC "wrx" 72;
IO_LOC "dcx" 18;
IO_LOC "csx" 71;