点击链接:SPI接口详细介绍
简单来说四根线:
SCK : Serial Clock 串行时钟
MOSI : Master Output, Slave Input 主发从收信号
MISO : Master Input, Slave Output 主收从发信号
SS/CS : Slave Select 片选信号
SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。常规只占用四根线,节约了芯片管脚,PCB的布局省空间。现在越来越多的芯片集成了这种通信协议,常见的有EEPROM、FLASH、AD转换器等。
传输速度:支持高速(100MHz以上),一般看传感器的硬件手册的要求,根据要求设置SCK的长度就可以了
module SPI_ADC(
input clk, //100M
input rst_n,
input Sig_start, //模块开始工作信号
input [7:0] WR_ADDR,
input [7:0] WR_DATA,
output wr_finish, //写入完成信号
output ADC_CS_n,
output ADC_SCK,
output ADC_SDI
);
reg Sig_start_r;
always@ (posedge clk)
begin
Sig_start_r <= Sig_start;
end
reg rCSn =1;
reg rSCK =1;
reg rSDI =0;
reg wr_finish_r= 0;
reg [4:0] state = 0;
reg [9:0] count;
reg [15:0]rDATA=0;
parameter Ts = 5'd10;
parameter Tds = 5'd10;
parameter Tdh = 5'd10;
parameter Th = 5'd10;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
rCSn <=1;
rSCK <=0;
rSDI <=0;
wr_finish_r <=0;
state <=0;
count <=0;
rDATA <=0;
end
else
begin
case(state)
0:begin
rCSn <=1;
rSCK <=0;
rSDI <=0;
wr_finish_r <=0;
count <=0;
if(~Sig_start_r&&Sig_start)
begin
state <= 5'd1;
end
end
1:begin //发送IIC开始信号
rDATA ={WR_ADDR,WR_DATA};//发送数据
if(count ==0 )
rCSn <=1'b1;
else if(count == 10)
rCSn <=1'b0;
if(count == 0)
rSCK <=1'b0;
else if(count == 20)
rSCK <=1'b0;
if(count == 30)
begin
count <=0;
state <=5'd2;
end
else
begin
count <= count + 1'b1;
end
end
2:begin
rSDI <= rDATA[15];
if(count == 5)
begin
state <= 5'd3;
count <= 0;
end
else
begin
count <= count +1'b1;
end
end
3,4,5,6,7,8,9,10,11,12,13,14,15,16,17:begin //BIT 15 - 1
if(count ==0)
begin
rSCK <=1'b1;
end
else if(count == 10)
begin
rSCK <=1'b0;
rSDI <= rDATA[17-state];
end
if(count == 20)
begin
state <= state +1'b1;
count <= 0;
end
else
begin
count <= count +1'b1;
end
end
18:begin
if(count ==0)
begin
rSCK <=1'b1;
end
else if(count ==10)
begin
rCSn <=1'b1;
end
if(count == 15)
begin
state <= 5'd19;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
19:begin //完成
wr_finish_r<= 1'b1;
state <=5'd0;
end
default:begin
state <=5'd0;
end
endcase
end
end
assign ADC_CS_n =rCSn;
assign ADC_SCK =rSCK;
assign ADC_SDI =rSDI;
assign wr_finish =wr_finish_r;
endmodule
module SPI_SDIO(
input clk, //100M
input rst_n,
input RSig_start, //模块开始工作
input [7:0] WR_ADDR,
output r_finish, //完成回读
output ADC_CS_n,
output ADC_SCK,
output ADC_SDI,
input ADC_SDIO,
output reg [7:0] A //回读数据
);
reg RSig_start_r;
always@ (posedge clk)
begin
RSig_start_r <= RSig_start;
end
reg rCSn =1;
reg rSCK =1;
reg rSDI =0;
reg r_finish_r= 0;
reg [4:0] state = 0;
reg [9:0] count;
reg [7:0]rDATA=0;
parameter Ts = 5'd10;
parameter Tds = 5'd10;
parameter Tdh = 5'd10;
parameter Th = 5'd10;
parameter TDO = 5'd20;
reg [7:0] A_reg = 0;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
rCSn <=1;
rSCK <=0;
rSDI <=0;
r_finish_r <=0;
state <=0;
count <=0;
rDATA <=0;
A_reg <=0;
end
else
begin
case(state)
0:begin
rCSn <=1;
rSCK <=0;
rSDI <=0;
r_finish_r <=0;
count <=0;
A_reg <=0;
if(~RSig_start_r&&RSig_start)
begin
state <= 5'd1;
end
end
1:begin //发送IIC开始信号
rDATA =WR_ADDR;//发送数据
if(count ==0 )
rCSn <=1'b1;
else if(count == 10)
rCSn <=1'b0;
if(count == 0)
rSCK <=1'b0;
else if(count == 20)
rSCK <=1'b0;
if(count == 30)
begin
count <=0;
state <=5'd2;
end
else
begin
count <= count + 1'b1;
end
end
2:begin
rSDI <= 1'b1;
if(count == 5)
begin
state <= 5'd3;
count <= 0;
end
else
begin
count <= count +1'b1;
end
end
3,4,5,6,7,8,9:begin //BIT 15 - 1
if(count ==0)
begin
rSCK <=1'b1;
end
else if(count == 10)
begin
rSCK <=1'b0;
rSDI <= rDATA[9-state];
end
if(count == 20)
begin
state <= state +1'b1;
count <= 0;
end
else
begin
count <= count +1'b1;
end
end
10:begin
if(count ==0)
begin
rSCK <=1'b1;
end
else if(count == 10)
begin
rSCK <=1'b0;
end
if(count == 30)
begin
state <= state +1'b1;
count <= 0;
end
else
begin
count <= count +1'b1;
end
end
11,12,13,14,15,16,17:begin
if(count ==0)
begin
rSCK <=1'b1;
A_reg[18-state] <= ADC_SDIO;
end
else if(count == 10)
begin
rSCK <=1'b0;
end
if(count == 30)
begin
state <= state +1'b1;
count <= 0;
end
else
begin
count <= count +1'b1;
end
end
18:begin
if(count ==0)
begin
rSCK <=1'b1;
A_reg[0] <=ADC_SDIO;
end
else if(count ==10)
begin
rCSn <=1'b1;
end
if(count == 15)
begin
state <= 5'd19;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
19:begin //完成
r_finish_r<= 1'b1;
state <=5'd0;
A <= A_reg;
end
default:begin
state <=5'd0;
end
endcase
end
end
assign ADC_CS_n =rCSn;
assign ADC_SCK =rSCK;
assign ADC_SDI =rSDI;
assign r_finish =r_finish_r;
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/06/26 10:30:19
// Design Name:
// Module Name: SPI_ini
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module SPI_ini(
input clk,
input rst_n,
output ADC_CS_n,
output ADC_SCK,
output ADC_SDI,
input ADC_SDIO,
output Done_ini
);
/************************** 配置ADC ************************/
/****************************************
模块功能:SPI配置
采样时钟:ADC_ENCLK 10M Th=50ns Tl = 50ns fs= 10M
备注:采用两个状态机状态机编写配置ADC文件
配置任务:1.全速率配置 2.10M采样速率 3. OFFSET BINARY
协议: 写数据均为 2Bit\
Ts min 5ns 设定100ns
tdS CS to SCK Setup Time min 5ns 设定100ns
ths HSCK to CS Setup Time min 5ns 设定100ns
Th min 5ns 设定100ns
tSCK SCK Period min 40ns 设定00ns
1.A0 复位寄存器(地址00H) BIT7 = 1 软件复位
2.A1 电源寄存器(地址01H) BIT1-0 = 00 正常工作 BIT1-0 = 00 两路都睡眠
3.A2 时间寄存器 (地址02H) BIT3 = 0 不翻转时钟记性以保证上升沿抓数据 BIT2-1 = 00 没有时钟相位延迟 BIT0 = 0 ,不开启时钟稳定电路
4.A3 输出模式寄存器(地址03H) BIT6-4 011 不适用LVDS BIT3 = 0 BIT2 = 0 不启用数字输出禁止 BIT1-0 =00 Full-Rate CMOS Output Mode
5.A4 数据格式寄存器 (地址05H) BIT5-3 = 000 输出数据测试关闭 BIT2 = 0 交替极性位关闭(开启后需要在FPGA中解码) BIT1 = 0 随机数字输出关闭 BIT0 = 0 Offset Binary Data Format
*****************************************/
//复位等待
reg ADC_config = 0;
reg [8:0] count_ADC_config = 0;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
ADC_config <= 0;
count_ADC_config <=0;
end
else
begin
if(count_ADC_config < 9'd200)
begin
count_ADC_config <= count_ADC_config + 1'b1;
ADC_config <=0;
end
else
begin
ADC_config <=1'b1;
end
end
end
//配置寄存器转换状态机
parameter ADDR_A0 =8'h00;
parameter ADDR_A1 =8'h01;
parameter ADDR_A2 =8'h02;
parameter ADDR_A3 =8'h03;
parameter ADDR_A4 =8'h04;
parameter DATA_A0 =8'b10000000;
parameter DATA_A1 =8'b00000000;
// parameter DATA_A1 =8'b00000011; 睡眠模式,时间为2ms默认情况下
parameter DATA_A2 =8'b00000000;
parameter DATA_A3 =8'b00110000;
parameter DATA_A4 =8'b00000000;
// parameter DATA_A0 =8'b10000000;
// parameter DATA_A1 =8'b00000000;
// parameter DATA_A2 =8'b00001000; //时钟翻转
// parameter DATA_A3 =8'b00110000;
// parameter DATA_A4 =8'b00011000; //输出都为1
//parameter A0 =8'b10000000;
//parameter A1 =8'b00000000;
//parameter A2 =8'b00000000;
//parameter A3 =8'b00110000;
//parameter A4 =8'b00000000;
reg [2:0] State_convert=0;
reg Sig_start=0;
wire wr_finish;
reg [7:0] WR_ADDR=0;
reg [7:0] WR_DATA=0;
reg [4:0] count=0;
reg Done_ini_r =0 ;
reg RSig_start = 0;
(*mark_debug = "true"*) (* KEEP = "TRUE" *) wire r_finish;
(*mark_debug = "true"*) (* KEEP = "TRUE" *) wire [7:0] A;
always @ (posedge clk or negedge rst_n )
begin
if(~rst_n)
begin
State_convert<=0;
Sig_start <=0;
WR_ADDR <=0;
WR_DATA <=0;
count <=0;
Done_ini_r <=0;
RSig_start <= 0;
end
else
begin
case(State_convert)
3'd0:begin
Sig_start <=0;
if(ADC_config)
begin
State_convert <= 3'd1;
end
end
3'd1:begin
Sig_start <= 1'b1;
WR_ADDR <= ADDR_A0;
WR_DATA <= DATA_A0;
if(wr_finish)
begin
Sig_start <=0;
State_convert <= 3'd2;
end
end
3'd2:begin
if(count ==5'd10)
begin
Sig_start <= 1'b1;
WR_ADDR <= ADDR_A1;
WR_DATA <= DATA_A1;
end
if(wr_finish)
begin
Sig_start <=0;
State_convert <= 3'd3;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
3'd3:begin
if(count ==5'd10)
begin
Sig_start <= 1'b1;
WR_ADDR <= ADDR_A2;
WR_DATA <= DATA_A2;
end
if(wr_finish)
begin
Sig_start <=0;
State_convert <= 3'd4;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
3'd4:begin
if(count ==5'd10)
begin
Sig_start <= 1'b1;
WR_ADDR <= ADDR_A3;
WR_DATA <= DATA_A3;
end
if(wr_finish)
begin
Sig_start <=0;
State_convert <= 3'd5;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
3'd5:begin
if(count ==5'd10)
begin
Sig_start <= 1'b1;
WR_ADDR <= ADDR_A4;
WR_DATA <= DATA_A4;
end
if(wr_finish)
begin
Sig_start <=0;
State_convert <= 3'd6;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
3'd6:begin
if(count ==5'd10)
begin
RSig_start <= 1'b1;
WR_ADDR <= ADDR_A3;
end
if(r_finish)
begin
RSig_start <=0;
State_convert <= 3'd7;
count <= 0;
end
else
begin
count <= count + 1'b1;
end
end
3'd7:begin
State_convert <= 3'd7;
if(count == 10)
Done_ini_r <= 1'b1;
else
count <= count +1'b1;
end
endcase
end
end
assign Done_ini = Done_ini_r ;
wire ADC_CS_n_0;
wire ADC_CS_n_1;
wire ADC_SCK_0;
wire ADC_SCK_1;
wire ADC_SDI_0;
wire ADC_SDI_1;
SPI_ADC S1(
. clk(clk), //100M
. rst_n(rst_n),
. Sig_start(Sig_start),
. WR_ADDR(WR_ADDR),
. WR_DATA(WR_DATA),
. wr_finish(wr_finish),
. ADC_CS_n(ADC_CS_n_0),
. ADC_SCK(ADC_SCK_0),
. ADC_SDI(ADC_SDI_0)
);
SPI_SDIO S2(
. clk(clk) , //100M
. rst_n(rst_n),
. RSig_start(RSig_start),
. WR_ADDR(WR_ADDR),
. r_finish(r_finish),
. ADC_CS_n(ADC_CS_n_1),
. ADC_SCK(ADC_SCK_1),
. ADC_SDI(ADC_SDI_1),
. ADC_SDIO(ADC_SDIO),
. A( A)
);
assign ADC_CS_n = RSig_start?ADC_CS_n_1:ADC_CS_n_0;
assign ADC_SCK = RSig_start?ADC_SCK_1:ADC_SCK_0;
assign ADC_SDI = RSig_start?ADC_SDI_1:ADC_SDI_0;
endmodule