fpga项目: st7796 spi接口‐‐v2代码 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
1)st7796 40pin fpc接口介绍
- 我们选择spi 4w接口模式,因为im[2:0]要设置为3'b111
- 用的是我自己做的FPGA扩展板。将扩展板的fpc接口列在excel表里,再将模组的excel表列在excel表里一一对应,然后用excel的公式自动生成引脚约束文件,这样免去了手工抄写的繁琐和易错。
2)先画时序图
推荐用excel画,非常的方便和漂亮。
-
只写cmd的时序
-
写cmd+data的时序
-
仿真波形:以cmd=0x3a, data=0x05为例
2)代码
代码的层次结构
代码编写的风格,与另一篇文章《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
4.2) Zynq 7010
4.3) 分析
- 使用的lut数量,nano-20k是zynq 7010的452/287=1.6倍。这个与xilinx给出的lut6和lut4的等效转换比例几乎是完全吻合!
- 两者的最大延时都是15.2ns左右,等效最大工作频率是63MHz。两者一样。
- 延时大的原因是,最长的组合逻辑链路有25级深度。这个路径是在timer_gen_seqs.v模块中。