您的位置:首页 > 其它

FPGA学习之路—接口(3)—SPI详解及Verilog源码分析

2020-07-15 05:40 169 查看

FPGA学习之路——SPI详解及Verilog源码分析

概述

SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。

  • 优点
    支持全双工
    支持高速
    协议支持字长不限于8bit,可以根据应用灵活选择消息字长。
    硬件连接简单
  • 缺点
    相比I2C多两条线
    没有寻址机制,只能靠片选选择不同的设备
    没有回应ACK机制,主设备不知道消息发送是否成功
    典型应用仅支持单主控

硬件结构

  • 信号定义
    SCK:Serial Clock,时钟信号,由主设备产生。
    MOSI:Master Output,Slave Input 主发从收信号。在片选信号有效时,数据由高位到低位,在时钟的上升沿依次发送给从设备。
    MISO:Master Input,Slave Output 主收从发信号,在片选信号有效时,数据由高位到低位,在时钟的上升沿依次发送给主设备。
    SS/CS:Slave Select 片选信号,低有效,由主设备控制。即只有片选信号为预先规定的使能信号时,对应的芯片操作才有效,这使得在同一总线上连接多个SPI设备成为可能。
  • 电路连接
    单个主设备和单个从设备:

    单个主设备和多个从设备,通过用多个片选信号或者菊花链的形式完成。
  • 传输模式
    通过设置相关控制寄存器,SPI可以有四种传输模式。
    1、时钟空闲时的电平为高或低。
    2、数据采样发生在时钟(SCK)的上/下边沿。
    将以上两种情况两两组合,即可得四种传输模式。
    数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取,完成一位数据传输,输入与输出原理相近。这样通过至少8次时钟信号的改变(上升沿和下降沿为一次),就可以完成8位数据的传输。如下图所示。
  • 标准SPI读

    片选→读指令→地址→数据读出
  • 标准SPI写

    片选→写指令→地址→数据写入

Verilog代码解析

本文以SPI Master控制器为例来对Verilog源码进行分析,参考资料为《VERILOG HDL应用程序设计实例精讲》,仅供学习参考,项目在文章末尾给出下载链接。
1、时钟分频模块,将原始时钟进行四分频,过程较为简单,不再详述。

module clkdiv(clk,clkout);
input clk;
output clkout;

reg [1:0]cnt=2'd0;
reg clkout=1'b0;

always @(posedge clk)begin
if(cnt==2'd1)begin
clkout<=1'b1;
cnt<=cnt+2'd1;
end
else if(cnt == 2'd3)begin
clkout<=1'b0;
cnt<=2'd0;
end
else begin
cnt<=cnt+2'd1;
end
end
endmodule

2、SPI发送数据部分,在spiclk的上升沿完成数据的传输。spics为片选信号,低有效;spido为输出的数据;dstate为FSM变量。dsend为待传送数据,其中部分数据过程重复,代码中仅保留首尾数据的传输过程。

begin
case (dstate)
8'd0:
begin
spics <= 1'b0;
spiclk <= 1'b1;
spido <= 1'b1;
dstate <= 8'd1;
end
8'd1:
begin
spics <= 1'b0;
spiclk <= 1'b1;
spido <= 1'b1;
dstate <= 8'd2;
end
8'd2:
begin
spics <= 1'b0;
spiclk <= 1'b0;
spido <= 1'b1;
dstate <= 8'd3;
end
8'd3:
begin
spics <= 1'b0;
spiclk <= 1'b1;
spido <= dsend[7];
dstate <= 8'd4;
end
8'd4:
begin
spics <= 1'b0;
spiclk <= 1'b0;
spido <= dsend[7];
dstate <= 8'd5;
end
……
8'd17:
begin
spics <= 1'b0;
spiclk <= 1'b1;
spido <= dsend[0];
dstate <= 8'd18;
end
8'd18:
begin
spics <= 1'b0;
spiclk <= 1'b0;
spido <= dsend[0];
dstate <= 8'd19;
end
8'd19:
begin
spics <= 1'b0;
spiclk <= 1'b1;
spido <= 1'b1;
dstate <= 8'd20;
end
8'd20:
begin
spics <= 1'b0;
spiclk <= 1'b1;
spido <= 1'b1;
dstate <= 8'd0;
spistate <= idle;
end
endcase
end
default:
begin
spics <= 1'b1;
spiclk <= 1'b1;
spido <= 1'b1;
spistate <= 2'b00;
end
endcase
end


可以看到当片选信号spics为低有效时,数据在spiclk的上升沿按顺序被发送至SPI总线上,数据信号spido与输入数据相对应,SPI Master发送时序得到验证。
3、SPI接收数据部分,参数定义与2一样,其中部分数据过程重复,代码中仅保留首尾数据的传输过程。在时钟的下降沿进行数据的接收。

begin
case (dstate)
8'd0:
begin
spics <= 1'b0;
spiclk <= 1'b1;
dstate <= 8'd1;
end
8'd1:
begin
spics <= 1'b0;
spiclk <= 1'b1;
dstate <= 8'd2;
end
8'd2:
begin
spics <= 1'b0;
spiclk <= 1'b0;
dstate <= 8'd3;
end
8'd3:
begin
spics <= 1'b0;
spiclk <= 1'b1;
dstate <= 8'd4;
end
8'd4:
begin
spics <= 1'b0;
spiclk <= 1'b0;
dreceive[7] <= spidi;
dstate <= 8'd5;
end
8'd5:
begin
spics <= 1'b0;
spiclk <= 1'b1;
dstate <= 8'd6;
end
……
8'd18:
begin
spics <= 1'b0;
spiclk <= 1'b0;
dreceive[0] <= spidi;
dstate <= 8'd19;
end
8'd19:
begin
spics <= 1'b0;
spiclk <= 1'b1;
dstate <= 8'd20;
dataout <= dreceive;
end
8'd20:
begin
spics <= 1'b0;
spiclk <= 1'b1;
dstate <= 8'd0;
spistate <= 2'b00;
end
endcase
end


由上图分析看出,收到的数据与SPI传输的数据相对应,SPI接收数据部分得到正确验证。

实验项目框图:

实验心得
1、在给复位信号低电平时时间过短,分频后时钟上升沿还未到复位信号就拉高了,导致未进行有效复位。
2、进行发送/接收状态检测时设置的计数子过大,如下图,每过40个时钟周期进行一次检测,当仿真时间过短时,容易看不到结果。

if(cnt == 8'd40)
begin
cnt <= 8'd0;
if((wr == 1'b0) && (rd == 1'b1))
begin
spistate <= send_data;
dstate <= 8'd0;
dsend <= datain;
end
else if((wr == 1'b1) && (rd == 1'b0))
begin
spistate <= receive_data;
dstate <= 8'd0;
end
end
else
begin
cnt <= cnt + 8'd1;
end

3、若结果出现问题,将相关控制信号添加至窗口,观察其状态,分析程序存在的问题。

项目下载链接

参考资料:https://blog.csdn.net/weixin_42509369/article/details/83096349
《VERILOG HDL应用程序设计实例精讲》

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐