赞
踩
教程来源于b站博主“新新新lcer”
视频网站:
https://www.bilibili.com/video/BV1jg411q7jL/?spm_id_from=333.788&vd_source=328251d5d01c23910b84996af150c5bd
主从通讯模式
1.一主一从
2.一主多从
其中:
SCK(Serial Clock):时钟信号线,由主机产生,决定通信速率
MOSI (Master Output Slave Input):主机发送数据 or从机接收数据的线
MISO (Master Input Slave Output):主机接收数据 or从机发送数据的线
CS (Chip Select):片选信号,低电平表示选中,
根据时钟极性和时钟相位,决定了存在四种工作模式
常用工作模式为:CPOL=1,CPHA=1
实现FPGA和ADC128S022数据互通
FPGA:发送采样通道地址给ADC128S022
ADC128S022:把相应通道的数据发送回来给FPGA
1.ADC128S022介绍
引脚图:
其中:
CS:片选信号,低电平有效
SCLK:时钟信号,允许频率范围:0.8MHz~3.2MHz
DIN:控制寄存器 (8bit),第5.4.3bit为输入通道选择bit
DOUT:输出端口
DIN数据结构图:
时序图:
2.模块设计
`timescale 1ns / 1ps
module SPI_tb(
);
parameter T = 20;
parameter DATA_TRANSMIT_WIDTH = 5'd8;
parameter DATA_RECEIVE_WIDTH = 5'd12;
parameter SYS_FRE = 50_000_000;
parameter SPI_FRE = 1_000_000;
parameter DIV_FRE_FACTOR = SYS_FRE/SPI_FRE/2;
reg sys_clk;
reg sys_rst_n;
reg spi_start;
reg spi_miso;
reg [2:0] addr;
wire [DATA_RECEIVE_WIDTH-1:0] data_receive;
wire spi_cs;
wire spi_sck;
wire spi_mosi;
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b1;
#(T*3)
sys_rst_n = 1'b0;
#(T*3)
sys_rst_n = 1'b1;
end
always #10 sys_clk = ~sys_clk;
initial begin
spi_start = 1'b0;
#(6*T)
#(2*T*DIV_FRE_FACTOR)
spi_start = 1'b1;
#(300*T*DIV_FRE_FACTOR)
spi_start = 1'b0;
end
initial begin
addr <= 3'b100;
#(50*T*DIV_FRE_FACTOR)
addr <= 3'b100;
#(50*T*DIV_FRE_FACTOR)
addr <= 3'b101;
#(50*T*DIV_FRE_FACTOR)
addr <= 3'b110;
#(50*T*DIV_FRE_FACTOR)
addr <= 3'b111;
end
reg [DATA_RECEIVE_WIDTH-1:0] spi_miso_data;
initial begin
spi_miso = 1'b0;
spi_miso_data <= 12'b1000_0000_1111;
#(20.25*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[11]; // 11bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[10];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[9];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[8];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[7];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[6];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[5];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[4];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[3];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[2]; // 2 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[1]; // 1 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[0]; // 0 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = 1'b0;
spi_miso_data <= 12'b1000_0000_1111;
#(16*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[11];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[10];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[9];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[8];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[7];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[6];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[5];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[4];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[3];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[2]; // 2 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[1]; // 1 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[0]; // 0 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = 1'b0;
spi_miso_data <= 12'b1000_0011_1111;
#(16*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[11];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[10];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[9];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[8];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[7];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[6];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[5];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[4];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[3];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[2]; // 2 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[1]; // 1 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[0]; // 0 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = 1'b0;
spi_miso_data <= 12'b1000_1111_1111;
#(16*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[11];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[10];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[9];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[8];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[7];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[6];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[5];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[4];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[3];
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[2]; // 2 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[1]; // 1 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = spi_miso_data[0]; // 0 bit
#(4*T*DIV_FRE_FACTOR) spi_miso = 1'b0;
end
SPI #(
.data_transmit_width (DATA_TRANSMIT_WIDTH),
.data_receie_width (DATA_RECEIVE_WIDTH),
.sys_fre (SYS_FRE),
.spi_fre (SPI_FRE)
) u_SPI (
.clk (sys_clk),
.rst (sys_rst_n),
.spi_start (spi_start),
.spi_miso (spi_miso),
.addr (addr),
.data_receive (data_receive),
.spi_cs (spi_cs),
.spi_clk (spi_sck),
.spi_mosi (spi_mosi)
);
endmodule
`timescale 1ns / 1ps
module SPI #(
parameter data_transmit_width = 5'd8,
parameter data_receie_width = 5'd12,
parameter sys_fre = 50000000,
parameter spi_fre = 1000000
)
(
input clk,
input rst,
input spi_start,
input [2:0] addr,
input spi_miso,
output reg spi_clk,
output reg spi_mosi,
output spi_cs,
output wire [data_receie_width-1:0] data_receive
);
parameter div_fre_factor = sys_fre/spi_fre-1;
reg [9:0] div_cnt;
always @(posedge clk or negedge rst) begin
if(!rst)
div_cnt <= 10'd0;
else if(spi_start) begin
if(div_cnt == div_fre_factor)
div_cnt <= 10'd0;
else
div_cnt <= div_cnt + 10'd1;
end
else
div_cnt <= 10'd0;
end
assign spi_cs = ~spi_start;
always @(posedge clk or negedge rst) begin
if(!rst)
spi_clk <= 1'b1;
else if(!spi_cs) begin
if(div_cnt == div_fre_factor)
spi_clk <= ~spi_clk;
else
spi_clk <= spi_clk;
end
else
spi_clk <= 1'b1;
end
reg [9:0] spi_clk_edge_cnt;
always @(posedge spi_clk or negedge spi_clk or negedge rst) begin
if(!rst)
spi_clk_edge_cnt <= 10'd0;
else if(!spi_cs)
if(spi_clk_edge_cnt == 10'd31)
spi_clk_edge_cnt <= 10'd0;
else
spi_clk_edge_cnt <= spi_clk_edge_cnt + 10'd1;
else
spi_clk_edge_cnt <= 10'd0;
end
reg [data_receie_width-1:0] data_receive_temp;
wire [data_transmit_width-1:0] data_transmit_temp;
assign data_transmit_temp = (spi_clk_edge_cnt=='d0) ? {2'b11,addr,3'b111} : data_transmit_temp;
always @(negedge spi_clk or negedge rst) begin
if(!rst)
spi_mosi <= 1'b0;
else if(!spi_cs && (spi_clk_edge_cnt<=2*(data_transmit_width-1)))
spi_mosi <= data_transmit_temp[data_transmit_width-1-(spi_clk_edge_cnt/2)];
else
spi_mosi <= 1'b0;
end
always @(posedge spi_clk or negedge rst) begin
if(!rst) begin
data_receive_temp <= 'b0;
end
else if(!spi_cs && (spi_clk_edge_cnt>='d9) && (spi_clk_edge_cnt<='d32) )
data_receive_temp[data_receie_width-1-(spi_clk_edge_cnt-10'd9)/2] <= spi_miso;
else
data_receive_temp <= data_receive_temp;
end
assign data_receive = (spi_clk_edge_cnt=='d0) ? data_receive_temp : data_receive;
endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。