fpga项目: st7796 mcu接口 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
1)st7796 40pin fpc接口介绍
- 我们选择mcu 16bits接口模式,因为im[2:0]要设置为3'b010
- 用的是我自己做的FPGA扩展板。将扩展板的fpc接口列在excel表里,再将模组的excel表列在excel表里一一对应,然后用excel的公式自动生成引脚约束文件,这样免去了手工抄写的繁琐和易错。
效果如下:
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个代码。
`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;