SPI-Verilog
SPI通讯协议(简介)
SPl ( Serial Peripheral Interface,串行外围设备接口)通讯协议,是Motorola公司提出的一种同步串行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输。
应用:EEPROM、Flash、RTC、ADC、DSP等。
优缺点︰全双工通信,通讯方式较为简单,相对数据传输速率较快﹔没有应答机制确认数据是否接收,在数据可靠性上有一定缺陷(与l2C相比)。
SPI物理层连接

第二种:单对多(一主多从)

spi四根管脚的作用:
SCK(Serial Clock):时钟信号线,用于同步通讯数据;
MOSI (Master Output, Slave lnput):主设备输出/从设备输入引脚
MISO (Master Input,Slave Output):主设备输入/从设备输出引脚
cs (Chip Select):片选信号线,也称为CS_N。
SPI协议层
SPI串行同步时钟可以设置为不同的极性(Clock Polarity ,CPOL)与相位(Clock Phase ,CPHA)。
时钟的极性(CPOL):用来决定在总线空闲时,同步时钟(SCK)信号线上的电位是高电平还是低电平。当时钟极性为0时(CPOL=0),SCK信号线在空闲时为低电平;当时钟极性为1时(CPOL=1),SCK信号线在空闲时为高电平;
时钟的相位(CPHA):用来决定何时进行信号采样。当时钟相位为1时(CPHA=1),在SCK信号线的第二个跳变沿进行采样;这里的跳变沿究竟是上升沿还是下降沿?取决于时钟的极性。当时钟极性为0时,取下降沿;当时钟极性为1时,取上升沿。或者说是当时钟极性为0时,在奇数边沿取信号,当时钟极性为1时,在偶数边沿取信号。
根据CPOL和CPHA不同SPI具有四种工作模式,如下图:

SPI应用举例-AD7793芯片
芯片手册(网上查)

AD7793芯片是采用4线spi接口用于转换把传输进来的模拟信号转换为数字信号。
AD7793芯片读写时序
AD7793芯片写时序

AD7793芯片读时序

AD7793芯片工作主要引脚说明
AD7792/AD7793的串行接口由四个信号组成:CS、DIN、SCLK和DOUT/RDY。
DIN线路用于将数据传输至片内寄存器中,DOUT/RDY则用于从片内寄存器中获取数据。SCLK是器件的串行时钟输入,所有数据传输(无论是DIN上还是DOUT/RDY上)均与SCLK信号相关。
DOUT/RDY引脚也可输出数据就绪信号;当输出寄存器中有新数字字可用时,该线路变为低电平。对数据寄存器的读操作完成时,该线路复位为高电平。数据寄存器更新之前,该线路也会变为高电平,提示在此时不应对器件进行读操作,以确保在更新数据寄存器的过程中不会发生数据读取操作。
AD7793芯片一般工作流程
读写大体流程是:
1、先向通讯寄存器写入地址和读写请求;
2、然后写入或者读取指定bit位宽的数据;
一般流程:
1、读ID寄存器,判断芯片是否符合要求;
2、选择输入通道
3、配置需要增益;
4、进行校准设置
5、发起单次或者连续AD转换读取

举例:AD7793控制模块(仅供参考,程序以及过程未验证)

输入:
Sys_clk:系统时钟
Sys_rst_n:复位信号
Key_flag:开始信号
MISO(DUT):AD7793(从机)传给主机的信号
输出:
Sclk: AD7793的钟控制信号
Cs:AD7793的片选信号
MOSI(DIN):主机输入从机输出
adc_convertion_data:转换完成的数据
AD7793控制模块状态图:

AD7793控制模块时序图
中间变量说明:
State:状态变量;
cnt_sclk:系统时钟的计数变量,主要用于生成sclk时钟用于驱动AD7793,根据手册知道sclk时钟最小为20;所以计数到10时钟翻转;
Cnt_bit:bit计数器,用于计算传输的bit个数;
Cnt_byte:字节计数器,用于计算传输的字节个数;
miso_flag:有效数据标志位,用于提示有效数据生成
data:用于有效数据保存
data_vld:有效数据接收完成标志

1、复位------------>向通信寄存器写入001_0000表示写配置寄存器---------->配置寄存器0x6e10----------->通信寄存器写0000_1000

模式寄存器写入0x200a---------------->通信寄存器写0101_1100设置为连续读取模式------------------->等待转换完成

rdy_n为0-------------->读取转换结果
代码(仅供参考未-不要指望完全对,我是一个新手)
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/03/03 19:42:16
// Design Name:
// Module Name: AD7793
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module AD7793(
input wire sys_clk,
input wire sys_rst_n,
input wire key_flag,
input wire miso_dout,
output reg sclk,
output reg cs,
output reg mosi_din,
output reg [23:0] adc_convertion_data
);
parameter IDLE = 4'b0001;
parameter WR = 4'b0010;
parameter WAIT = 4'b0100;
parameter READ = 4'b1000;
reg [3:0] state;
reg [3:0] cnt_clk;
reg [2:0] cnt_bit;
reg [2:0] cnt_byte;
reg miso_flag;
reg data_vld;
reg [23:0] data;
//状态机的生成
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
state <= IDLE;
else
case(state)
IDLE:if (cs == 1'b0)
state <= WR;
else
state <= IDLE;
WR :if ((cnt_clk == 4'd9)&&(cnt_bit == 3'd7)&&(cnt_byte == 3'd6))
state <= WAIT;
else
state <= WR;
WAIT:if (miso_dout == 1'b0)
state <= READ;
else if(cs == 1'b1)
state <= IDLE;
else
state <= WAIT;
READ:if (cs == 1'b1)
state <= IDLE;
else if((state == READ)&&(cnt_clk == 4'd9)&&(cnt_bit == 3'd7)&&(cnt_byte == 3'd2))
state <= WAIT;
else
state <= READ;
default:state <= IDLE;
endcase
end
//片选
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cs <= 1'b1;
else if(key_flag == 1'b1)
cs <= ~cs;
else
cs <= cs;
end
//系统时钟计数
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_clk <= 4'd0;
else if(cnt_clk == 4'd9)
cnt_clk <= 4'd0;
else if(state == WAIT)
cnt_clk <= 4'd0;
else if(cs == 1'b1)
cnt_clk <= 4'd0;
else
cnt_clk <= cnt_clk + 1'b1;
end
//bit计数
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bit <= 3'd0;
else if(cnt_clk == 4'd9)
cnt_bit <= cnt_bit + 1'b1;
else
cnt_bit <= cnt_bit;
end
//字节计数器
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_byte <= 3'd0;
else if((cnt_byte == 3'd6)&&(cnt_bit == 4'd7)&&(cnt_clk == 4'd9))
cnt_byte <= 3'd0;
else if((cnt_bit == 4'd7)&&(cnt_clk == 4'd9))
cnt_byte <= cnt_byte + 1'b1;
else
cnt_byte <= cnt_byte;
end
//sclk产生
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
sclk <= 1'd1;
else if(state == WAIT)
sclk <= 1'd1;
else if(cs == 1'b1)
sclk <= 1'd1;
else if(cnt_clk == 4'd4 ||cnt_clk == 4'd9)
sclk = ~sclk;
else
sclk <=sclk;
end
//mosi的输出波形
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
mosi_din <= 1'b1;
else if((state == WR)&&(cnt_clk == 4'd4)&&(cnt_bit == 3'd0)&&(cnt_byte == 3'd0))
mosi_din <= 1'b0;
else if((state == WR)&&(cnt_clk == 4'd4)&&(cnt_bit == 3'd3)&&(cnt_byte == 3'd0))
mosi_din <= 1'b1;
else if((state == WR)&&(cnt_clk == 4'd4)&&(cnt_bit == 3'd4)&&(cnt_byte == 3'd0))
mosi_din <= 1'b0;
else if(((state == WR)&&(cnt_byte == 3'd1)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd1||cnt_bit == 3'd4))
mosi_din <= 1'b1;
else if(((state == WR)&&(cnt_byte == 3'd1)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd3||cnt_bit == 3'd7))
mosi_din <= 1'b0;
else if(((state == WR)&&(cnt_byte == 3'd2)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd3))
mosi_din <= 1'b1;
else if(((state == WR)&&(cnt_byte == 3'd2)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd4))
mosi_din <= 1'b0;
else if(((state == WR)&&(cnt_byte == 3'd3)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd4))
mosi_din <= 1'b1;
else if(((state == WR)&&(cnt_byte == 3'd3)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd5))
mosi_din <= 1'b0;
else if(((state == WR)&&(cnt_byte == 3'd5)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd4))
mosi_din <= 1'b1;
else if(((state == WR)&&(cnt_byte == 3'd6)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd0||cnt_bit == 3'd2||cnt_bit == 3'd6))
mosi_din <= 1'b0;
else if(((state == WR)&&(cnt_byte == 3'd6)&&(cnt_clk == 4'd4))&&(cnt_bit == 3'd1||cnt_bit == 3'd3))
mosi_din <= 1'b1;
else if(cs == 1'd1)
mosi_din <= 1'b1;
else if (miso_dout == 1'd0)
mosi_din <= 1'b0;
else
mosi_din <= mosi_din;
end
//miso_flag 接收的bit奇数
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
miso_flag <=1'b0;
else if((state == READ)&&(cnt_clk == 4'd8))
miso_flag <=1'b1;
else
miso_flag <=1'b0;
end
//串并转化标识符
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
data <= 24'd0;
else if(miso_flag <=1'b1)
data <={data,miso_dout};
else
data <=data;
end
//串并转换完成标识符
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
data_vld <= 1'b0;
else if(state == READ && cnt_bit == 3'd7 && cnt_clk == 4'd9 && cnt_byte == 3'd2)
data_vld <= 1'b1;
else
data_vld <= 1'b0;
end
//有效转换数据
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
adc_convertion_data <= 24'd0;
else if(data_vld == 1'b1)
adc_convertion_data <= data;
else
adc_convertion_data <= adc_convertion_data ;
end
endmodule
图源以及参考(17. 基于spi协议的flash驱动控制 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 文档 (embedfire.com))

浙公网安备 33010602011771号