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

1)st7796 40pin fpc接口介绍

image image


  • 我们选择spi 4w接口模式,因为im[2:0]要设置为3'b111
  • 用的是我自己做的FPGA扩展板。将扩展板的fpc接口列在excel表里,再将模组的excel表列在excel表里一一对应,然后用excel的公式自动生成引脚约束文件,这样免去了手工抄写的繁琐和易错。

image

2)先画时序图

推荐用excel画,非常的方便和漂亮。

  • 只写cmd的时序 image

  • 写cmd+data的时序 image

  • 仿真波形:以cmd=0x3a, data=0x05为例 image

2)代码

代码的层次结构 image

代码编写的风格,与另一篇文章《Verilog code: st7796 fmc接口--v2代码》完全相似。 采用状态机的写法后,感觉各种串行接口都可以用统一的方法写,很简单轻松了。

`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 spi_st7796(
    input clk,
    input rst,
    
    output csx,
    output dcx,
    output sck,
    output mosi,
    output rst_o, 
    output [2:0] im    
    );


parameter NDATA=320*480*2;
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'b111;  
    

reg pi_start_pulse;
reg [7:0] pi_cmd;
reg [7:0] pi_data0; 
reg [7:0] pi_data1; 
reg [7:0] pi_data2; 
reg [7:0] pi_data3; 
reg [15:0] pi_datan; 
reg [20: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<=8'h00;
    pi_data1<=8'h00;
    pi_data2<=8'h00;
    pi_data3<=8'h00;    
    pi_datan<=8'h00;        
    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<=8'h48; 
    pi_nbytes<=1;      
end
    5:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h3a; 
    pi_data0<=8'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

spi_top u_spi_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),
    .sck(sck),
    .mosi(mosi)
    );

gen_timer_seqs 
//    #( .FCLK(27_000)) 
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 
        pi_start_pulse<=1;
        pi_cmd<=8'h2c; 
        pi_data0<=color[15:8];
        pi_data1<=color[7:0]; 
        pi_data2<=color[15:8];
        pi_data3<=color[7:0];              
        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 spi_top(
    input clk,
    input rst_n,

    input pi_start_pulse,    
    input [7:0] pi_cmd,
    
    input [7:0] pi_data0,
    input [7:0] pi_data1,  
    input [7:0] pi_data2,
    input [7:0] pi_data3,      
    input [15:0] pi_datan,          
    input [20:0] pi_nbytes,        
    
    output csx,
    output dcx,
    output sck,
    output mosi
    );

reg [20:0] byte_cnt=0;
reg [7:0] pi_data;  

// 
spi 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),
  .sck(sck),
  .mosi(mosi),
  .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<4) begin
        case(byte_cnt)
            0:  pi_data <= pi_data0;
            1:  pi_data <= pi_data1;                          
            2:  pi_data <= pi_data2;  
            3:  pi_data <= pi_data3; 
        endcase
    end
    else begin
        if(byte_cnt%2==0)
            pi_data <= pi_datan[15:8];
        else
            pi_data <= pi_datan[7:0];  
    end     
                                
    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 spi(
    input clk,
    input rst_n,

    input pi_start_pulse,    
    input [7:0] pi_cmd,
    input [7:0] pi_data,          
    input [20:0] pi_nbytes, 
    
    output reg csx,
    output reg dcx,
    output reg sck,
    output reg mosi,
    output end_pulse
    );

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

reg [4: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==16)
    cnt0<=0;
 else if(state!=IDLE)
    cnt0<=cnt0+1;
    
 //end_pulse
assign end_pulse=(cnt0==16);

//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; 
    
//sck
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    sck<=0;
 else if(state!=IDLE && cnt0%2==1)
    sck<=1;
 else if(state!=IDLE && cnt0%2==0 && cnt0>0)
    sck<=0; 
    
//mosi
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    mosi<=0;
 else if(state==CMD && cnt0%2==0 && cnt0<=14)
     mosi<=pi_cmd[7-(cnt0>>1)];
 else if(state==DATA  && cnt0%2==0 && cnt0<=14)
     mosi<=pi_data[7-(cnt0>>1)]; 
    
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" 10;  //30MHz
//IO_LOC "clk" 11;  //5MHz
IO_LOC "clk" 4;    //27MHz
IO_LOC "rst" 88;

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


IO_LOC "rst_o" 79;
//IO_LOC "miso" 17;
IO_LOC "mosi" 20;

IO_LOC "sck" 72;
IO_LOC "dcx" 18;
IO_LOC "csx" 71;

4) 新相科技Z7-Nano引脚约束

############## clock define##################
create_clock -period 20.000 [get_ports clk]

set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports clk]
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports rst_n]

set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {im[2]}]
set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS33} [get_ports {im[1]}]
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {im[0]}]

set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports rst_o]
#set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports miso]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports mosi]

set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports sck]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports dcx]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports csx]

4)tang nano-20k与Zynq 7010综合对比

4.1) tang nano-20k

image image image

4.2) Zynq 7010

image image image

4.3) 分析

  • 使用的lut数量,nano-20k是zynq 7010的452/287=1.6倍。这个与xilinx给出的lut6和lut4的等效转换比例几乎是完全吻合!
  • 两者的最大延时都是15.2ns左右,等效最大工作频率是63MHz。两者一样。
  • 延时大的原因是,最长的组合逻辑链路有25级深度。这个路径是在timer_gen_seqs.v模块中。