fpga项目: st7796 mcu接口‐‐v2版代码 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
1)画时序图
- 推荐用excel表,比visio或者timegen都要简单,好用,灵活。
- 单元格:高度设为20,宽度设为2。
2)代码
改进点:
- 先画时序图,严格按照时序图写
- 采用了状态机的方法。感觉用状态机还是简单和正规一点。
- 采用了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;