首页 > 其他分享 >SPI-Verilog

SPI-Verilog

时间:2023-03-08 20:55:54浏览次数:47  
标签:芯片 AD7793 SPI Verilog 寄存器 reg 时钟

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

相关文章

  • 跟着思兼学习Klipper(22)稳中求胜: 工业级的 Fysetc Spider King 简要观察记录
    稳中求胜:工业级的FysetcSpiderKing简要观察记录前言本文感谢富源盛(Fysetc)赞助的SpiderKing主板。最初接触8轴主板就是当时买的mksmonster8v1和三叉戟自带......
  • MCP2515国产替代DP2515带有SPI 接口的独立CAN 控制器
    DP2515是一款独立控制器局域网络(ControllerAreaNetwork,CAN)协议控制器,完全支持CANV2.0B技术规范。该器件能发送和接收标准和扩展数据帧以及远程帧。DP2515自带的两个验......
  • 状态机的Verilog写法
    状态机的Verilog写法 “硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工......
  • SpingMVC:如何设置一个拦截器?
    (interceptors) 拦截器类似于springaop和tomcat中过滤器,但是作用域不同。AOP:针对特点方法前后进行扩充,一般对serviceimpl进行拦截器:针对控制器方法进行控制。 一、步......
  • Pspice 设置电容电感初始状态
    Pspice中的capacitor与inductor的IC值它们的IC值很重要,含义是初值。也就是电感(电容)的初始电流(电压)。因为Pspice在模拟时它不会把电感、电容的初始值默认当作0,而是会根......
  • 有符号加法的Verilog实现
    有符号加法的Verilog实现形式,推荐两种方式:方式一:传统方式,手动扩位,实现左右位宽匹配,扩位为符号位,另外信号输入有符号数,一定要显示定义,Verilog默认不定义就是无符号类型1 ......
  • ATSAMD21配置SPI_PIN
    学习SPIMASTERDEMO发现有一个参数config_spi_master.mux_setting=CONF_MASTER_MUX_SETTING;之前遇到跟串口的一样,就是配置pin脚的功能的,SPI应该是指定不同功能的pin......
  • Spring Boot SPI 机制探究
    SpringBootSPI机制探究前言SpringBoot带给我们的一大便利是当需要引入一个第三方依赖时,如果其有Starter,可以加入Starter依赖,就可以实现自动装配,这中便利就来自S......
  • Verilog 语句
    可综合语句Module...endmoduleModule(clk,a,b,c,d);inputclk;input[2:0]a,b;outputb;inoute;endmodulemodule括号声明所有输入和输出......
  • spingboot随笔
    idea如何创建springboot项目NewMoudle>>SpringInitializrProjectMetadata:Type>>Maven,Packaging>>jar/war加载starters选项:DeveloperTools>>Lombok,Web>>S......