基于FPGA的SPI接口设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于FPGA的SPI接口设计
SPI是一种在FPGA和其他芯片之间传输数据的简单有效的接口方式。
SPI项目
第一部分:什么是SPI
第二部分:SPI的简单实现
第三部分:应用
第一部分:什么是SPI
SPI是允许一个器件同其他一个或多个器件进行通讯的简单接口。
SPI是什么样的?
首先让我们来看看两个芯片之间的SPI接口是如何连接的。
在两个芯片时间通讯时,SPI需要4条连线。
正如你所看到的,他们是SCK、MISO、MOSI以及SSEL。其中一个芯片叫做主控芯片,另一个叫从芯片。
SPI基础
基本特点:
1.同步
2.串行
3.全双工
4.非即插即用
5.一主多从
更多细节:
1.同步时钟有主控芯片产生,每个时钟传输一位数据
2.数据在传输前,首先许要进行并转串,才能用一条线传输
3.两条数据线,一条输入、一条输出
4.主从双方有关于SPI传输的先验知识,如比特顺序、数据长度等
5.数据传输有主控芯片发起,每次只与一个从芯片通讯
SPI是一种同步全双工的通讯接口,每个时钟在两条数据线上各传输一比特数据。
简单的传输
假设在主从芯片之间进行的是8位长度的,高位数据在前的SPI传输,则单个字节的传输在波形上看起来是这样的。
MOSI是主输出线,而MISO则是从输出线。由于SPI是全双工的,所以在时钟沿上两条线同时传输数据。MOSI将数据从主控芯片传输至从芯片,MISO则将从芯片的数据传输到主控芯片。
详细的说是这样的:
1,首先主控芯片使能相应的SSEL信号,通知相应的从芯片数据传输要开始了;
2,主控芯片产生8个SPI时钟周期,并将数据在每个时钟沿发送出去,同时从芯片在也每个时钟沿将数据发送到MISO线上。
3,主控芯片撤销SSEL信号,一次SPI传输结束
多个从芯片的情况
通过扩展SSEL信号,一个主控芯片可以和多个从芯片进行SPI通讯。下图是有三个从芯片的情况:
主控芯片有3条SSEL线,每次只使能条,和其中一个从芯片进行SPI通讯。由于所有芯片的MISO都连接在一起,所以不允许同时有多个从芯片驱动MISO线。
SPI有多快
SPI可以很轻易的做到几Mbps的传输速率,这就意味着SPI可以用来进行非压缩的音频和和压缩的视频信号传输。
相关链接:Wikipedia的SPI接口总线
第二部分
SPI接口的FPGA简单实现
ARM 处理器
为了检验我们刚学得的关于SPI的知识,我们使用一个带有SPI接口的ARM7板和FPGA板,板间由SPI总线连接。
ARM处理器作为主控器,FPGA作为SPI从机。下图为他们之间的连接方式。
SPI 主控机- C语言程序
使用ARM的SPI接口,只需要初始化一些寄存器,然后对SPI接口进行写数和读数操作即可让SPI接口自动完成发送和接收数据。
void main(void)
{
// 初始化SPI接口,因处理器而异
SSP0CPSR = 0x02;
SSP0CR0 = 0x07;
SSP0CR1 = 0x02;
PINSEL1 = 0x2A8;
while(1)
{
// 发送两个字节
SSP0DR = 0x55;
SSP0DR = 0x54;
// 等待数据发送完毕
while(!(SSP0SR & 0x01));
// 读数
int data1 = SSP0DR;
int data2 = SSP0DR;
// ...
}
}
SPI 从机- HDL 代码
再来考虑FPGA端SPI从机的设计。
Since the SPI bus is typically much slower than the FPGA operating clock speed, we choose to over-sample the SPI bus using the FPGA clock. That makes the slave code slightly more complicated, but has the advantage of having the SPI logic run in the FPGA clock domain, which
will make things easier afterwards.
First the module declaration.
module SPI_slave(clk, SCK, MOSI, MISO, SSEL, LED);
input clk;
input SCK, SSEL, MOSI;
output MISO;
output LED;
Note that we have "clk" (the FPGA clock) and an LED output... a nice little debug tool. "clk" needs to be faster than the SPI bus. Saxo-L has a default clock of 24MHz, which works fine here.
We sample/synchronize the SPI signals (SCK, SSEL and MOSI) using the FPGA clock and shift registers.
// sync SCK to the FPGA clock using a 3-bits shift register
reg [2:0] SCKr; always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
wire SCK_risingedge = (SCKr[2:1]==2'b01); // now we can detect SCK rising edges
wire SCK_fallingedge = (SCKr[2:1]==2'b10); // and falling edges
// same thing for SSEL
reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
wire SSEL_active = ~SSELr[1]; // SSEL is active low
wire SSEL_startmessage = (SSELr[2:1]==2'b10); // message starts at falling edge
wire SSEL_endmessage = (SSELr[2:1]==2'b01); // message stops at rising edge
// and for MOSI
reg [1:0] MOSIr; always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
wire MOSI_data = MOSIr[1];
Now receiving data from the SPI bus is easy.
reg [2:0] bitcnt; // we handle SPI in 8-bits format, so we need a 3 bits counter to count the bits as they come in
reg byte_received; // high when a byte has been received
reg [7:0] byte_data_received;
always @(posedge clk)
begin
if(~SSEL_active)
bitcnt <= 3'b000;
else
if(SCK_risingedge)
begin
bitcnt <= bitcnt + 3'b001;
byte_data_received <= {byte_data_received[6:0], MOSI_data}; // implement a shift-left register (since we receive the data MSB first)
end
end
always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111);
// we use the LSB of the data received to control an LED
reg LED;