Skip to content

fpga项目: st7796 mcu接口

minichao9901 edited this page Dec 8, 2023 · 1 revision

1)st7796 40pin fpc接口介绍

image image


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

image

效果如下:
image

2)先写一个简单的mcu接口,测试一下mcu接口的简单写操作

`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 rst_o,
    output csx,
    output dcx,
    output wrx,
    output rdx,
    output [15:0] po_data     
    );

parameter FCLK=27_000_000;
parameter DLY_10MS=FCLK*0.01; 

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

wire event1,event2,event3;

assign rst_n=~rst; 
assign rst_o=~rst;  
assign event1=(timer==DLY_10MS*1)? 1:0;
assign event2=(timer==DLY_10MS*2)? 1:0;
assign event3=(timer==DLY_10MS*3)? 1:0;

reg pi_flag;
reg pi_is_cmd;
reg [15:0] pi_data; 
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    pi_flag<=0;
    pi_is_cmd<=0;
    pi_data<=16'h0000;
end
else if(event1) begin
    pi_flag<=1;
    pi_is_cmd<=1;
    pi_data<=16'h0011;
end
else if(event2) begin
    pi_flag<=1;
    pi_is_cmd<=1;
    pi_data<=16'h0029;
end
else
    pi_flag<=0;


fmc u_fmc(
    .clk(clk),
    .rst_n(rst_n),
    .pi_wr_en(1),
    .pi_is_cmd(pi_is_cmd),
    .nbytes(1),
    .pi_flag(pi_flag),
    .pi_data(pi_data),
    
    .csx(csx),
    .dcx(dcx),
    .wrx(wrx),
    .rdx(rdx),
    .po_data(po_data)
    );
        
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/05 10:24:44
// Design Name: 
// Module Name: fmc
// 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_wr_en,
    input pi_is_cmd,
    input nbytes,    
    input pi_flag,
    input [15:0] pi_data,
    
    output reg csx,
    output reg dcx,
    output reg wrx,
    output reg rdx,
    output reg [15:0] po_data 
    );

parameter CNT1=7;
parameter CNT2=3;
parameter CNT3=7;
parameter CNT4=3;

reg [3:0] state;
reg [7:0] delay_cnt;


always @(posedge clk or negedge rst_n) begin
if(rst_n==0) begin
    csx<=1;
    dcx<=0;
    wrx<=1;
    rdx<=1;
    po_data<=16'd0;  
    delay_cnt<=0;
    state<=0; 
end
else begin
    delay_cnt<=delay_cnt+1;
    case(state)
        0: if (pi_flag) begin 
                delay_cnt<=0;    
                state<=1;
            end
        1: begin
            task1();          
            if(delay_cnt==CNT1) begin           
                state<=2;
                delay_cnt<=0;
            end
        end
        2: begin
            task2();
            if(delay_cnt==CNT2) begin
                state<=3;
                delay_cnt<=0;
            end
        end
        3: begin
            task3();
            if(delay_cnt==CNT3) begin
                state<=4;
                delay_cnt<=0;
            end
        end
         4: begin
            task4();
            if(delay_cnt==CNT4) begin
                state<=0;
                delay_cnt<=0;
            end
        end       
    endcase
end
end

task task1;
    if(delay_cnt==0) begin
        csx<=0;
        wrx<=0;
        dcx<=pi_is_cmd? 0:1;
     end
endtask

task task2;
    if(delay_cnt==0) begin
        po_data<={8'd0,pi_data[7:0]};
     end     
endtask

task task3;
    if(delay_cnt==0) begin
        wrx<=(pi_wr_en)? 1:0;
     end     
endtask

task task4;
    if(delay_cnt==0) begin
        csx<=1;
        wrx<=1;
     end   
endtask    
    
endmodule

3) 接下来,进行完整的刷频测试代码编写

  • 输入时钟27MHz
  • 2个定时器搞定:
  • A) 1个定时器搞定底层的fmc接口,将cs/dcx/wrx等拉高/拉低动作进行分解,每个时钟执行一个动作,这样把事情简单化。
  • B) 1个定时器搞定顶层的指令发送。每隔一段时间,产生一个event信号,用这个event信号去调用fmc接口,执行指令发送命令。
  • fmc接口设计的比较简单粗暴,为了考虑4种不同情形,输入数据进行了多个输入,以简化时序:
  • 只发送指令, 例如11/29指令
  • 发送指令+1个数据,例如3A/36指令
  • 发送指令+4个数据,例如2A/2B指令
  • 发送指令+N个数据(N>4),例如2C指令
  • 整个代码包括3个文件,层次结构如下:
  • 其中fmc.v是8080接口驱动
  • gen_timer_seqs.v是产生时序脉冲的代码,用于将操作序列化(每10ms产生一个脉冲)
  • fmc_st7796.v是初始化和刷屏代码,整合了以上2个代码。
    image
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/05 10:24:44
// Design Name: 
// Module Name: fmc
// 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_wr_en,
    input [7:0] pi_cmd,

    input pi_start_pulse,
    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 reg csx,
    output reg dcx,
    output reg wrx,
    output reg rdx,
    output reg [15:0] po_data
    );


reg [20:0] delay_cnt;


always @(posedge clk or negedge rst_n) begin
if(rst_n==0) begin
    dcx<=0;
    rdx<=1;
    po_data<=16'd0;  
    delay_cnt<=0;
end
else if(pi_start_pulse)
    delay_cnt<=0;
else if(delay_cnt==20'hfffff)
    delay_cnt<=20'hfffff;
else begin
    delay_cnt<=delay_cnt+1;

    if(delay_cnt==1) begin
        dcx<=0;
    end

    else if(delay_cnt==2) begin
        po_data<={8'd0,pi_cmd};
    end

    else if(delay_cnt%3==1  && delay_cnt>=3) begin
        dcx<=1;
    end 
    
    else if(delay_cnt%3==2 && delay_cnt>=3) begin
        if(delay_cnt<6)
            po_data<=pi_data0;
        else if(delay_cnt<9)
             po_data<=pi_data1;           
        else if(delay_cnt<12)
             po_data<=pi_data2;  
        else if(delay_cnt<15)
             po_data<=pi_data3; 
        else
             po_data<=pi_datan;                  
    end 

 end
 end
 
 
 //wrx
 always @(posedge clk or negedge rst_n) begin
if(rst_n==0) begin
    wrx<=1;
end
else begin
    if(delay_cnt==1) begin
        wrx<=0;
    end

    else if(delay_cnt%3==0 && delay_cnt>=3 && delay_cnt<4+3*pi_nbytes) begin
        wrx<=1;
    end

    else if(delay_cnt%3==1  && delay_cnt>=3 && delay_cnt<4+3*pi_nbytes) begin
        wrx<=0;
    end    
     
 end
 end
 
 
//csx 
always @(posedge clk or negedge rst_n) begin
if(rst_n==0) begin
    csx<=1;
end
else begin
    if(delay_cnt==1) begin
        csx<=0;
    end
    
    else if(delay_cnt==4+3*pi_nbytes) begin
        csx<=1;
    end   
 end
 end 
 
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
`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 rdx,
    output [19: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
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=RED;
    pi_data1<=RED; 
    pi_data2<=RED;
    pi_data3<=RED;              
    pi_datan<=RED;
    pi_nbytes<=NDATA;     
end
    8+NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=GREEN;
    pi_data1<=GREEN; 
    pi_data2<=GREEN;
    pi_data3<=GREEN;              
    pi_datan<=GREEN;
    pi_nbytes<=NDATA;     
end
    8+2*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=BLUE;
    pi_data1<=BLUE; 
    pi_data2<=BLUE;
    pi_data3<=BLUE;              
    pi_datan<=BLUE;
    pi_nbytes<=NDATA;     
end
    8+3*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=ORANGE;
    pi_data1<=ORANGE; 
    pi_data2<=ORANGE;
    pi_data3<=ORANGE;              
    pi_datan<=ORANGE;
    pi_nbytes<=NDATA;     
end
    8+4*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=CYAN;
    pi_data1<=CYAN; 
    pi_data2<=CYAN;
    pi_data3<=CYAN;              
    pi_datan<=CYAN;
    pi_nbytes<=NDATA;     
end
    8+5*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=PURPPLE;
    pi_data1<=PURPPLE; 
    pi_data2<=PURPPLE;
    pi_data3<=PURPPLE;              
    pi_datan<=PURPPLE;
    pi_nbytes<=NDATA;     
end
    8+6*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=BLACK;
    pi_data1<=BLACK; 
    pi_data2<=BLACK;
    pi_data3<=BLACK;              
    pi_datan<=BLACK;
    pi_nbytes<=NDATA;     
end
    8+7*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=WHITE;
    pi_data1<=WHITE; 
    pi_data2<=WHITE;
    pi_data3<=WHITE;              
    pi_datan<=WHITE;
    pi_nbytes<=NDATA;     
end
    8+8*NDLY:  begin
    pi_start_pulse<=1;
    pi_cmd<=8'h2c; 
    pi_data0<=GRAY;
    pi_data1<=GRAY; 
    pi_data2<=GRAY;
    pi_data3<=GRAY;              
    pi_datan<=GRAY;
    pi_nbytes<=NDATA;     
end
    default:
    pi_start_pulse<=0;
endcase


fmc u_fmc(
    .clk(clk),
    .rst_n(rst_n),
    .pi_wr_en(1),
    .pi_cmd(pi_cmd),
    .pi_nbytes(pi_nbytes),
    .pi_start_pulse(pi_start_pulse),
    .pi_data0(pi_data0),
    .pi_data1(pi_data1),
    .pi_data2(pi_data2),
    .pi_data3(pi_data3),    
    .pi_datan(pi_datan),        
    
    .csx(csx),
    .dcx(dcx),
    .wrx(wrx),
    .rdx(rdx),
    .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)
);

        
endmodule

4)引脚约束文件

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;
Clone this wiki locally