SPI通信方式的详解

Serial Peripheral Interface

SPI是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI是一种高速的、全双工、同步的通信总线。

  1. 连接图
    在这里插入图片描述 CS/SS 片选信号,此信号有效表示此从机被选中通信;SCLK主机给从机的系统时钟;
    SDI/MISO主机输出给从机的数据;SDO/MOSI 从机输出给主机的数据;
    注意:三线的SPI是把SDI和SDO合并成了一个双向的SDIO(后章中有具体用法)
  2. SPI接口时序图
    在这里插入图片描述
    CPOL=0;CPHA =0:
    主机在SCLK下降沿输出MOSI的数据,上升沿读取MISO上的数据
    从机在SCLK下降沿输出MISO的数据,上升沿读取MOSI上的数据(注意MISO第一个数据是在拉低CS信号就已经输出)
    CPOL=1,CPHA =1:
    主机在SCLK下降沿输出MOSI的数据,上升沿读取MISO上的数据
    从机在SCLK下降沿输出MISO的数据,上升沿读取MOSI上的数据(注意MISO第一个数据是在拉低CS信号就已经输出)
  3. SPI驱动代码
/***************************************************
*	Module Name		:	spi_master		   
*	Engineer		:	GUAN 
*	Target Device	:	EP4CE6E17C8
*	Tool versions	:	Quartus II 13.0
*	Create Date		:	2020-3-5
*	Revision		:	v1.0
*	Description		:	SPI主机控制器
***************************************************/
module spi_master
(
	input                       	sys_clk,	
	input                       	rst_n,
	output                      	cs_n,       //chip select (SPI mode) 
	output reg                   	sclk,      	//spi clock
	output                      	mosi,      	//spi master data output
	input                       	miso,      	//spi master input
	input                       	CPOL,
	input                       	CPHA,
	input     	[9:0]           	spi_div,
	input                       	cs_ctrl,
	input                       	wr_req,		
	output                      	wr_ack,
	input		[7:0]             	data_in,
	output		[7:0]             	data_out
);
localparam                   		IDLE        		= 0;
localparam                   		SCLK_RUN    		= 1;
localparam                   		ACK					= 2;
localparam                   		ACK_WAIT			= 3;
reg		[2:0]                    	cur_state ;
reg		[2:0]                  		next_state;
reg 	[9:0] 						clk_cnt;			// 分频时钟
reg 	[4:0] 						cnt;				// 计数
reg 	[7:0] 						mosi_shift;
reg 	[7:0] 						miso_shift;
reg									wr_ack_r;
wire								wr_ack_reg;
assign	cs_n 		= cs_ctrl;
assign	mosi 		= mosi_shift[7];	
assign	wr_ack 		= (cur_state == ACK);
assign	data_out 	=  miso_shift ;
//生成SPI的SCLK的二倍频率(25M)的驱动时钟用于驱动spi的操作
always @(posedge sys_clk or negedge rst_n) 
begin
    if(!rst_n) 
		clk_cnt <= 10'd0;
    else if(clk_cnt >= (spi_div-1)) 	
		clk_cnt <= 10'd0;
    else
       clk_cnt <= clk_cnt + 1'b1;
end

wire sclk_plus = (clk_cnt == (spi_div-1));
//同步时序描述状态转移
always @(posedge sys_clk or negedge rst_n) 
begin
    if(!rst_n) 
		cur_state <= IDLE;
	else
		cur_state <= next_state;
end
//组合逻辑判断状态转移条件
always@(*)
begin
	case(cur_state)
		IDLE:
			if(wr_req == 1'b1)
				next_state = SCLK_RUN;
			else
				next_state = IDLE;
		SCLK_RUN:
			if(cnt == 5'd17)
				next_state = ACK;
			else
				next_state = SCLK_RUN;
		//send one byte complete		
		ACK:
			next_state = ACK_WAIT;
		//wait for one clock cycle, to ensure that the cancel request signal
		//确保wr_req信号和cur_state==IDLE同时发生变化
		ACK_WAIT:
			next_state <= IDLE;
		default:
			next_state <= IDLE;
	endcase
end
//时序电路描述时钟控制信号的输出
always @(posedge sys_clk or negedge rst_n) begin
    //复位初始化
	if(!rst_n) begin
		sclk		<= CPOL;						
		//CPOL=0,串行同步时钟的空闲状态为低电平,也就是说第一个跳变沿为上升沿
		//CPOL=1,串行同步时钟的空闲状态为高电平,也就是说第一个跳变沿为下降沿
		cnt			<= 0;							
	end
	else if(cur_state != SCLK_RUN)
		cnt			<= 5'd0;
	else if(cur_state == SCLK_RUN && sclk_plus)
	begin 
		cnt        <= cnt +5'd1 ;
		case
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值