FPGA:三大协议(UART、IIC、SPI)之SPI

这篇具有很好参考价值的文章主要介绍了FPGA:三大协议(UART、IIC、SPI)之SPI。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘要:1、本文介绍SPI物理层面连接(通过哪几条线通信),2、本文介绍SPI时序(通过哪种方式进行器件之间交流)。3、提供主机和从机verilog代码。4、仅供自己参考

一、SPI物理层连接

(1)有四根线连接:CS_N(片选信号--主机发出)、miso(从机发出,主机接收)、mosi(主机发出,从机接收)、SCLK(时钟信号,主机发出,作为数据传输的参考时钟)。

(2)结构图:

fpga通信协议,fpga开发

(3)总结:

1、SPI是一种全双工,同步通信总线,需要四根信号线(可用于FLASH器件的控制);

2、SPI通信有主从之分,可以实现一主多从或者是一主多从,但是不能实现多主多从,因为从器件只有一根cs_n片选信号线,没办法知道是哪个主机发出的控制信号;

3、SCLK是主机产生的,用来同步数据;

4、SPI是以MSB方式传播(高位先发);

二、SPI协议层时序

(1)SPI要记住以下几个知识(必须死记)

1、miso是从机发送,主机接收的信号线;

2、mosi是主机发送,从机接收的信号线;

3、mosi和mosi可以同时工作;

4、SCLK是主机产生,用来同步数据;且!!!:主机接收和发送数据都是在SCLK的跳变沿

从机接收和发送数据也是在SCLK的跳变沿。

5、根据4可知,数据的接收和发送是在SCLK的上升沿,究竟是在上升沿还是下降沿是由SPI的通信模式决定。注!!!:这个通信模式是双发同时遵守的!!,不是通过什么信号线配置的!!。

6、cs_n片选信号是由主机产生的,控制从机是否开始工作。

(2)通信模式:

解释:什么叫通信模式,就是决定数据的采集是在SCLK的上升沿还是下降沿,并且还决定SCLK在空闲时候是什么状态。

1、由CPOL和CPHA决定(这两个就是两个名称,没有什么用,相当于你的名字,没有实际的用处),所以可以有四种通信模式,00 、01、 10、 11。

2、CPOL        :clock polarity 时钟极性

CPHA             :clock phase 时钟相位,表示奇偶边沿采样。

CPHA = 0      :表示在时钟(SCLK)奇数边沿对数据采样,CPHA = 1表示在SCLK时钟偶数边沿采样。

CPOL = 0       :表示SCLK空闲时低电平,CPOL = 1表示SCLK时钟空闲时是高电平。

总结表格:

fpga通信协议,fpga开发

时序图示意(提供11模式时序图):

fpga通信协议,fpga开发

 注!!!:以上的CPOL和CPHA是没有任何物理意义,仅仅用他们来表示这种通信模式,也可以用其他名字来代替CPOL和CPHA,是要双方用同一个模式就可以了。

(3)怎么通信:

1、首先要知道:miso、mosi、cs_n在空闲时是高电平,sclk空闲状态由通信模式决定。

2、由起始信号和停止信号表示传输开始和停止:

fpga通信协议,fpga开发

 3、sclk怎么产生:用计数器记录一段时间实现SCLK的翻转,就产生了sclk脉冲信号;

4、mosi怎么产生:mosi的产生根据通信模式产生,比如在11模式:sclk空闲为高,在上升沿采样。那么在sclk下降沿的时候更具数据改变mosi信号线的高低;

5、miso怎么接收:比如在11模式。在sclk上升沿来临的时候采集miso,把串行数据变成并行数据;

6、定位数据哪一位接收或者发送:用一个计数器记录这一次接受了好多bit数据,并且放在数据对应位上,实现串并转换。

fpga通信协议,fpga开发

如上图:当bit为0的时候发送data的第7位(MSB),cnt_bit的变化是当sclk记录完一个周期之后加一。

主机verilog代码:

module spi_master(
    input  					clk		, //system clock 50MHz
    input  			 		rst_n	, //reset, low valid
    
    input					start	, //按键控制数据发送
    /* input			[7:00]	send_data	, //要发送的数据 */

    input                   spi_miso,//从机发送,主机接收

    output					send_done	, //这一次发送结束
    output reg     [7:0]    rx_data,
    output			 reg   	sclk,	  //
    output           reg    spi_mosi,//主发
    output           reg    spi_cs   //片选信号
);
//Parameter Declarations
localparam
        IDLE             =  4'b0001,
        START            =  4'b0010,
        WR_RD_DATA       =  4'b0100,
        STOP             =  4'b1000;
//Internal wire/reg declarations
reg		[3:00]	state_c, state_n; //
//跳转条件定义
wire			idle2start;
wire			start2wr_rd_data;
wire			wr_rd_data2stop;
wire			stop2dile;
      
reg     [7:0]   data_tmp;//输入数据暂存
reg     [7:0]   data_tmp_rx;

reg		[5:00]	cnt_sclk		; //Counter   
wire			add_cnt_sclk ; //Counter Enable
wire			end_cnt_sclk ; //Counter Reset 

reg		[3:00]	cnt_bit	; //Counter   
wire			add_cnt_bit ; //Counter Enable
wire			end_cnt_bit ; //Counter Reset 

//Module instantiations , self-build module
//缓存数据
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        data_tmp <= 8'd20;
    end  
    else if(start)begin
        data_tmp <= data_tmp + 3;
    end 
    else begin
        data_tmp <= data_tmp;
    end
end //always end

//Logic Description      
        
//第一段设置状态转移空间
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n;
    end
end //always end
//第二段、组合逻辑定义状态转移
always@(*)begin
    case(state_c)
        IDLE:begin
            if(idle2start)begin
                state_n = START;
            end
            else begin
                state_n = state_c;
            end
        end
        START:begin
            if(start2wr_rd_data)begin
                state_n = WR_RD_DATA;
            end 
            else begin
                state_n = state_c;	
            end 
        end
        WR_RD_DATA:begin
            if(wr_rd_data2stop)begin
                state_n = STOP;
            end 	
            else begin
                state_n = state_c;	
            end 
        end 
        STOP:begin
            if(stop2dile)begin
                state_n = IDLE;
            end 
            else begin
                state_n = state_c;	
            end 
        end 
        default: begin
            state_n = IDLE;
        end
    endcase
end //always end
        
assign	idle2start	        =	state_c ==  IDLE	&& 	start;
assign	start2wr_rd_data	=	state_c	==	START	&&	spi_cs == 0;
assign	wr_rd_data2stop	    =	state_c	==	WR_RD_DATA	&&	end_cnt_bit ;
assign	stop2dile	        =	state_c	==	STOP	&&	spi_cs == 1;
        
//计数器
//cnt_sclk[5:00]
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin  
        cnt_sclk <= 6'd0; 
    end  
    else if(add_cnt_sclk)begin  
        if(end_cnt_sclk)begin  
            cnt_sclk <= 6'd0; 
        end  
        else begin  
            cnt_sclk <= cnt_sclk + 1'b1; 
        end  
    end  
    else begin  
        cnt_sclk <= 6'd0;  
    end  
end 
assign add_cnt_sclk = state_c == WR_RD_DATA; 
assign end_cnt_sclk = add_cnt_sclk && cnt_sclk >= 9; //周期是10个时钟周期,当cnt_sclk加到5的时候翻转

//cnt_bit     
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin  
        cnt_bit <= 4'd0; 
    end  
    else if(wr_rd_data2stop)begin
        cnt_bit <= 4'd0; 
    end
    else if(add_cnt_bit)begin  
        if(end_cnt_bit)begin  
            cnt_bit <= 4'd0; 
        end  
        else begin  
            cnt_bit <= cnt_bit + 1'b1; 
        end  
    end  
    else begin  
        cnt_bit <= cnt_bit;  
    end  
end 
        
assign add_cnt_bit = state_c == WR_RD_DATA && end_cnt_sclk; //在计数器为0的时候加一,表示数据变化是在下降沿,采集是在上升沿
assign end_cnt_bit = add_cnt_bit && cnt_bit >= 7; 
//第三段,定义状态机输出情况,可以时序逻辑,也可以组合逻辑
always @(posedge clk or negedge rst_n)begin  
    if(!rst_n)begin  
        sclk <= 1'b1;
        spi_cs <= 1'b1;
        spi_mosi <= 1'b1;
        rx_data <= 8'd0;
    end  
    else begin  
        case(state_c)
            IDLE          :begin//全高
                sclk <= 1'b1;
                spi_cs <= 1'b1;
                spi_mosi <= 1'b1;
            end   
            START         :begin
                spi_cs <= 1'b0;
                sclk <= 1'b1;
                spi_mosi <= 1'b1;
            end   
            WR_RD_DATA    :begin
                //发送
                spi_cs <= 1'b0;
                if(cnt_sclk < 5)begin
                    sclk <= 1'b0;
                end
                else begin
                    sclk <= 1'b1;
                end
                spi_mosi <= data_tmp[7-cnt_bit];
                //接收

                if(sclk == 1'b1)begin
                    data_tmp_rx[7-cnt_bit] <= spi_miso;
                end
            end   
            STOP          :begin
                rx_data <= data_tmp_rx;
                sclk <= 1'b1;
                spi_cs <= 1'b1;
                spi_mosi <= 1'b1;
            end   
            default:;
        endcase
        
    end  
end //always end
assign send_done = stop2dile;

endmodule 

 从机verilog代码:文章来源地址https://www.toymoban.com/news/detail-623342.html

module spi_slave(
    input					sclk	, //
    input			    	spi_cs	, //
    input                   spi_mosi,//接收的数据
    output		reg			spi_miso,	//输出的无数据

    output      [7:0]       rx_data,
    output                  data_vld//信号有效
);
//Parameter Declarations
reg     [7:0]   rx_data_tmp;

reg     [2:0]   cnt_bit;
reg     [7:0]   tx_data = 8'd0;
//Internal wire/reg declarations


//Module instantiations , self-build module

    
//Logic Description
always @(posedge sclk)begin
    if(spi_cs == 1'b1)begin
        rx_data_tmp <= 8'd0;
        spi_miso <= 1'b1;
        cnt_bit <= 3'b111;
    end
    else begin
        cnt_bit = cnt_bit + 1;
        if(sclk)begin
            rx_data_tmp[7-cnt_bit] <= spi_mosi;
        end
        else ;
        if(cnt_bit == 1'b1)begin
            tx_data <=  tx_data + 1;
        end
        else ;
    end
end

always @(*)begin
    if(spi_cs == 1'b1)begin
        spi_miso = 1'b1;
    end
    else   begin
        if(sclk == 1'b0)begin
            spi_miso = tx_data[7 - cnt_bit];
        end
        else begin
            spi_miso = spi_miso;
        end
    end
end

assign rx_data = rx_data_tmp;
assign data_vld = cnt_bit == 3'd7;

endmodule 

到了这里,关于FPGA:三大协议(UART、IIC、SPI)之SPI的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式Linux裸机开发(七)UART串口、IIC、SPI通信

    大概学完这三种通信后,之后就先去学系统移植,其他的先暂时放下 串口全称叫做串行接口,通常也叫做 COM 接口。 UART:(Universal Asynchronous Receiver/Trasmitter)通用异步串行收发器。 USART:(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行收发器,相比 UART多了

    2024年02月07日
    浏览(52)
  • 【FPGA协议篇】UART通信及其verilog实现(代码采用传参实现模块通用性,适用于快速开发)

    ​ 即通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种 串行、异步、全双工 的通信协议。特点是通信线路简单,适用于远距离通信,但传输速度慢。 数据传输速率:波特率(单位:baud,波特) 常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和11520

    2024年02月05日
    浏览(36)
  • 详解UART通信协议以及FPGA实现

      从《浅谈UART,TTL,RS-232,RS-485的区别》这篇文章,我们知道了UART是一种串行、异步、全双工的通信协议,属于协议层;传输过程一般采用RS-232,RS-485电平标准,将所需传输的数据一位接一位地传输;整体传输框架如下:   串口通信由发送端和接收端构成,两根信号线

    2024年04月28日
    浏览(31)
  • 【LabVIEW FPGA入门】LabVIEW FPGA 实现SPI通信协议

            该实现由两个组件组成:在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口,同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA(直接内存访问

    2024年01月17日
    浏览(39)
  • IIC通信协议详解 & PCF8591应用(Verilog实现FPGA)

    该文章结合PCF8591 8-bit AD/DA 模数/数模转换器来详细介绍IIC通信协议,尽量做到条理清晰,通俗易懂。该文图片均从PCF8591手册中截取,一定程度上引导读者学习阅读data sheet。 之后可能会更新 如何将IIC的Verilog实现变为一个IP核,并在pynq-Z2板子上使用 。 2.1 地址位 在I2C总线系统

    2024年02月04日
    浏览(50)
  • FPGA开发(2)——IIC通信

    IIC物理层框图如下图所示。 (1) 它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。 (2) 一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线(SCL)。数

    2024年02月02日
    浏览(32)
  • UART、IIC、SPI、CAN通信的区别与应用

    数据通信基本方式可以分为 串行通信与并行通信 两种 1.1.1、串行通信 (1)定义:串行通信是指利用一条传输线将数据一位位地顺序传送。 (2)传输方式:传输一个字节(8个位)的数据时,串口是将8个位排好队,逐个地在1条连接线上传输。 (3)特点:通信线路简单,成

    2024年02月06日
    浏览(33)
  • IIC、SPI、Uart、One-wire等常见协议

    IIC两线式 串行 总线,由数据线 SDA 和时钟线 SCL 构成,由于数据在同一条线上传输,因此IIC通信是 半双工 通信方式; IIC使用 多主从架构 , 每个器件都有唯一的识别地址,都可以作为一个发送器或接收器,这里的主从并没有绝对的概念,基本上谁控制时钟线谁就是主设备,

    2024年02月12日
    浏览(32)
  • 常用通讯协议(UART、RS232、RS485、IIC、SPI)简单介绍

    目录 常用通讯协议随笔 通讯基础 UART UART存在的问题: RS232 接口 信号 电平转换 RS232存在的问题 RS485 信号 接口 电平转换 RS485的优势 IIC IIC总线通讯过程 IIC总线寻址方式 起始信号和停止信号 字节传输于应答 同步信号 典型IIC时序 SPI SPI寻址方式 SPI总线通讯过程 极性和相位

    2024年02月02日
    浏览(33)
  • FPGA协议篇:UART通信及Verilog最易懂实现方式/通用于任何工程/带握手信号 ----UART_TX

            UART(Universal Asynchronous Receiver/Transmitter)是一种通用的 异步收发传输协议 ,用于在计算机系统和外部设备之间进行串行数据传输。UART 协议定义了数据的传输格式和通信规则,使得不同设备之间能够进行可靠的数据交换。 首先先把设计代码放到这里: UART_TX完整代

    2024年03月27日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包