SPI协议理解(未完)

SPI(Serial Peripheral Interface,串行外围设备接口)通讯协议,是 Motorola 公司提出的一种同步串行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,广泛用于 EEPROM、Flash、ADC(数模转换器)、DSP(数字信号处理器)以及数字信号解码器上,是常用的也是较为重要的通讯协议之一。
SPI 通讯协议的优点是支持全双工通信,通讯方式较为简单,且相对数据传输速率较快;缺点是没有指定的流控制,没有应答机制确认数据是否接收。
SPI 通讯协议包含 1 条时钟信号线、2 条数据总线和 1 条片选信号线, 时钟信号线为SCK,2 条数据总线分别为 MOSI(主输出从输入)、MISO(主输入从输出),片选信号线为CS_N,它们的作用介绍如下:
(1) SCK (Serial Clock):时钟信号线,用于同步通讯数据。由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不同,两个设备之间通讯时,通讯速率受限于低速设备。
(2) MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,数据方向由主机到从机。
(3) MISO (Master Input,Slave Output):主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,数据方向由从机到主机。
(4) CS_N(Chip Select):片选信号线-。当有多个 SPI 从设备与 SPI 主机相连时,设备的其它信号线 SCK、MOSI 及 MISO 同时并联到相同的 SPI总线上,即无论有多少个从设备,都共同使用这 3 条总线;而每个从设备都有独立的这一条 CS_N 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。
SPI 通讯协议的 4 种模式如下。
模式 0:CPOL= 0,CPHA=0。空闲状态时 SCK 串行时钟为低电平;数据采样在 SCK时钟的奇数边沿,本模式中,奇数边沿为上升沿;数据更新在 SCK 时钟的偶数边沿,本模式中,偶数边沿为下降沿。
模式 1:CPOL= 0,CPHA=1。空闲状态时 SCK 串行时钟为低电平;数据采样在 SCK时钟的偶数边沿,本模式中,偶数边沿为下降沿;数据更新在 SCK 时钟的奇数边沿,本模式中,偶数边沿为上升沿。
模式 2:CPOL= 1,CPHA=0。空闲状态时 SCK 串行时钟为高电平;数据采样在 SCK时钟的奇数边沿,本模式中,奇数边沿为下降沿;数据更新在 SCK 时钟的偶数边沿,本模式中,偶数边沿为上升沿。
模式 3:CPOL= 1,CPHA=1。空闲状态时 SCK 串行时钟为高电平;数据采样在 SCK时钟的偶数边沿,本模式中,偶数边沿为上升沿;数据更新在 SCK 时钟的奇数边沿,本模式中,偶数边沿为下降沿。

//spi: flash全擦除实验
module spi(
		 sys_clk,
		 sys_rstn,
		 key,
		 miso,
		cs_n,
		sck,
		mosi
);
input sys_clk;
input sys_rstn;
input key;
input miso;
output cs_n;
output sck;
output mosi;
reg cs_n;
reg sck;
reg mosi;
parameter wr_en = 8'h06;//flash 写使能指令
parameter be = 8'hc7;//全擦除指令
reg [1:0] cnt_sck;
reg [4:0] cnt;
reg [2:0] cnt_bit; 
reg [2:0] cnt_byte;
reg [1:0] state;
//产生sck,cnt_sck为2'b2时为上升沿
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				cnt_sck <= 2'b0;
		end
		else if(cnt_sck  == 2'd3)begin
				cnt_sck <= 2'b0;
		end
		else if(state == 2'b01&&cnt_byte==3'd1)begin
				cnt_sck <= cnt_sck +1'b1;
		end
		else if(state == 2'b11&&cnt_byte==3'd5)begin
				cnt_sck <= cnt_sck +1'b1;
		end
		else begin
				cnt_sck <= 0;
		end
end
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				sck <= 1'b0;
		end
		else if(cnt_sck  == 2'b0)begin
				sck <= 0;
		end
		else if(cnt_sck  == 2'd2)begin
				sck <= 1;
		end
		else begin
				sck <= sck;
		end
end
//从高位输出
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				cnt_bit <= 3'b0;
		end
		else if(cnt_sck  == 2'd2)begin
				cnt_bit  <= cnt_bit + 1'b1;
		end
		else begin
				cnt_bit  <= cnt_bit ;
		end
end
//产生基础周期32sys_clk
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				cnt <= 5'b0;
		end
		else if(cnt  == 5'd31)begin
				cnt <= 5'b0;
		end
		else begin
				cnt <= cnt + 1'b1;
		end
end
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				cnt_byte <= 3'b0;
		end
		else if(cnt_byte==3'd6&&cnt  == 5'd31)begin
				cnt_byte <= 3'b0;
		end
		else  if(cnt  == 5'd31)begin
				cnt_byte<= cnt_byte + 1'b1;
		end
		else begin
				cnt_byte <= cnt_byte;
		end
end
//状态机
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				state <= 2'b0;
		end
		else begin
				case(state)  
					2'b00:  begin
						if(key) begin
							state <= 2'b01;
						end
						else begin
							state <= state;
						end
					end
					2'b01: begin
						if(cnt_byte==3'd2&&cnt  == 5'd31)begin
							state <= 2'b10;
						end
						else begin
							state <= state;
						end
					end
					2'b10: begin	
						if(cnt_byte==3'd3&&cnt  == 5'd31)begin
							state <= 2'b11;
						end
						else begin
							state <= state;
						end
					end	
					2'b11: begin	
						if(cnt_byte==3'd6&&cnt  == 5'd31)begin
							state <= 2'b00;
						end
						else begin
							state <= state;
						end
					end
				endcase
		end
end
//片选
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				cs_n <= 1'b1;
		end
		else if(key)begin
				cs_n <= 1'b0;
		end
		else if(state==3'b01&&cnt_byte==3'd2&&cnt  == 5'd31)begin
				cs_n <= 1'b1;
		end
		else  if(state==3'b10&&cnt_byte==3'd3&&cnt  == 5'd31)begin
				cs_n<= 1'b0;
		end
		else  if(state==3'b11&&cnt_byte==3'd6&&cnt  == 5'd31)begin
				cs_n<= 1'b1;
		end
		else begin
				cs_n <= cs_n;
		end
end
//mosi
always@(posedge sys_clk)
begin
		if(!sys_rstn)begin
				mosi <= 3'b0;
		end
		else if(state==3'b01&&cnt_byte==3'd2)begin
				mosi <= 0;
		end
		else  if(state==3'b11&&cnt_byte==3'd6)begin
				mosi <= 0;
		end
		else if(state==3'b01&&cnt_byte==3'd1&&cnt_sck==2'b0)begin
				mosi <= wr_en[7-cnt_bit];
		end
		else  if(state==3'b11&&cnt_byte==3'd5&&cnt_sck==2'b0)begin
				mosi <= be[7-cnt_bit];
		end
		else begin
				mosi <= mosi;
		end
end
endmodule



//test_bench
`timescale 1ns/1ps
module tb_spi();
reg sys_clk;
reg sys_rstn;
reg key;
wire cs_n;
wire sck;
wire mosi;
always #1 sys_clk = ~sys_clk;
initial
begin
		sys_clk = 0;
		sys_rstn = 0;
		key = 0;
		#20
		sys_rstn = 1;
		#20
		key = 1;
		#2
		key = 0;
end
spi inst0(
		.sys_clk  (sys_clk ),  
		.sys_rstn (sys_rstn ),
		.key        (key ),
		.cs_n      (cs_n ),
		.sck        (sck ),
		.mosi      ( mosi )
);
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值