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))
标签:芯片,AD7793,SPI,Verilog,寄存器,reg,时钟 From: https://www.cnblogs.com/xuhuiyuan/p/17196231.html