基于FPGA的SPI接口设计
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于 FPGA 的 SPI 接口设计
目录 第一部分:什么是 SPI 第二部分:SPI 的简单实现 第三部分:应用
第一部分:什么是 SPI SPI 是一种在 FPGA 和其他芯片之间传输数据的简单有效的接口方式。SPI 是允许一个器
件同其他一个或多个器件进行通讯的简单接口。 SPI 是什么样的? 首先让我们来看看两个芯片之间的SPI接口是如何连接的。 在两个芯片时间通讯时,SPI 需要 4 条连线。
else byte_data_sent <= {byte_data_sent[6:0], 1'b0};
end end assign MISO = byte_data_sent[7]; // send MSB first // we assume that there is only one slave on the SPI bus, so we don't bother with a tri‐state buffer for MISO // otherwise we would need to tri‐state MISO when SSEL is inactive endmodule We have established communication between the ARM and the FPGA! Running the code As we step through the ARM code, we can see the LED changing state, and the data returned by the FPGA.
if(SSEL_startmessage) byte_data_sent <= cnt; // first byte sent in a message is the message count
else if(SCK_fallingedge) begin
if(bitcnt==3'b000) byte_data_sent <= 8'h00; // after that, we send 0s
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
// 初始化 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.
详细的说是这样的:
1,首先主控芯片使能相应的 SSEL 信号,通知相应的从芯片数据传输要开始了; 2,主控芯片产生 8 个 SPI 时钟周期,并将数据在每个时钟沿发送出去,同时从芯片在 也每个时钟沿将数据发送到 MISO 线上。 3,主控芯片撤销 SSEL 信号,一次 SPI 传输结束 多个从芯片的情况 通过扩展 SSEL 信号,一个主控芯片可以和多个从芯片进行 SPI 通讯。下图是有三个从 芯片的情况:
主控芯片有 3 条 SSEL 线,每次只使能条,和其中一个从芯片进行 SPI 通讯。由于所有 芯片的 MISO 都连接在一起,所以不允许同时有多个从芯片驱动 MISO 线。
SPI 有多快 SPI 可以很轻易的做到几 Mbps 的传输速率,这就意味着 SPI 可以用来进行非压缩的音频
和和压缩的视频信号传输。 相关链接:Wikipedia 的 SPI 接口总线 http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
SPI 是一种同步全双工的通讯接口,每个时钟在两条数据线上各传输 1 比特数据。 假设在主从芯片之间进行的是 8 位长度的,高位数据在前的 SPI 传输,则单个字节的传 输在波形上看起来是这样的。
MOSI 是主输出线 SPI 是一种在 FPGA 和其他芯片之间传输数据的简单有效的接口方式。 而 MISO 则是从输出线。由于 SPI 是全双工的,所以在时钟沿上两条线同时传输数据。MOSI 将数据从主控芯片传输至从芯片,MISO 则将从芯片的数据传输到主控芯片。
正如你所看到的,他们是 SCK、MISO、MOSI 以及 SSEL。其中一个芯片叫做主控芯片, 另一个叫从芯片。
SPI 基础 http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus 基本特点: 1.同步 2.串行 3.全双工 4.非即插即用 5.一主多从 更多细节: 1.同步时钟有主控芯片产生,每个时钟传输一位数据 2.数据在传输前,首先许要进行并转串,才能用一条线传输 3.两条数据线,一条输入、一条输出 4.主从双方有关于 SPI 传输的先验知识,如比特顺序、数据长度等 5.数据传输有主控芯片发起,每次只与一个从芯片通讯
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
Now let's see if we can do useful things with SPI.
第二部分 SPI 接口的 FPGA 简单实现 ARM 处理器 为了检验我们刚学得的关于 SPI 的知识,我们使用一个带有 SPI 接口的 ARM7 板和 FPGA 板,板间由 SPI 总线连接。 ARM 处理器作为主控器,FPGA 作为 SPI 从机。来自百度文库图为他们之间的连接方式。
SPI 主控机 ‐ C 语言程序 使用 ARM 的 SPI 接口,只需要初始化一些寄存器,然后对 SPI 接口进行写数和读数操作 即可让 SPI 接口自动完成发送和接收数据。 void main(void) {
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; always @(posedge clk) if(byte_received) LED <= byte_data_received[0]; Finally the transmission part. reg [7:0] byte_data_sent; reg [7:0] cnt; always @(posedge clk) if(SSEL_startmessage) cnt<=cnt+8'h1; // count the messages always @(posedge clk) if(SSEL_active) begin
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.
目录 第一部分:什么是 SPI 第二部分:SPI 的简单实现 第三部分:应用
第一部分:什么是 SPI SPI 是一种在 FPGA 和其他芯片之间传输数据的简单有效的接口方式。SPI 是允许一个器
件同其他一个或多个器件进行通讯的简单接口。 SPI 是什么样的? 首先让我们来看看两个芯片之间的SPI接口是如何连接的。 在两个芯片时间通讯时,SPI 需要 4 条连线。
else byte_data_sent <= {byte_data_sent[6:0], 1'b0};
end end assign MISO = byte_data_sent[7]; // send MSB first // we assume that there is only one slave on the SPI bus, so we don't bother with a tri‐state buffer for MISO // otherwise we would need to tri‐state MISO when SSEL is inactive endmodule We have established communication between the ARM and the FPGA! Running the code As we step through the ARM code, we can see the LED changing state, and the data returned by the FPGA.
if(SSEL_startmessage) byte_data_sent <= cnt; // first byte sent in a message is the message count
else if(SCK_fallingedge) begin
if(bitcnt==3'b000) byte_data_sent <= 8'h00; // after that, we send 0s
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
// 初始化 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.
详细的说是这样的:
1,首先主控芯片使能相应的 SSEL 信号,通知相应的从芯片数据传输要开始了; 2,主控芯片产生 8 个 SPI 时钟周期,并将数据在每个时钟沿发送出去,同时从芯片在 也每个时钟沿将数据发送到 MISO 线上。 3,主控芯片撤销 SSEL 信号,一次 SPI 传输结束 多个从芯片的情况 通过扩展 SSEL 信号,一个主控芯片可以和多个从芯片进行 SPI 通讯。下图是有三个从 芯片的情况:
主控芯片有 3 条 SSEL 线,每次只使能条,和其中一个从芯片进行 SPI 通讯。由于所有 芯片的 MISO 都连接在一起,所以不允许同时有多个从芯片驱动 MISO 线。
SPI 有多快 SPI 可以很轻易的做到几 Mbps 的传输速率,这就意味着 SPI 可以用来进行非压缩的音频
和和压缩的视频信号传输。 相关链接:Wikipedia 的 SPI 接口总线 http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
SPI 是一种同步全双工的通讯接口,每个时钟在两条数据线上各传输 1 比特数据。 假设在主从芯片之间进行的是 8 位长度的,高位数据在前的 SPI 传输,则单个字节的传 输在波形上看起来是这样的。
MOSI 是主输出线 SPI 是一种在 FPGA 和其他芯片之间传输数据的简单有效的接口方式。 而 MISO 则是从输出线。由于 SPI 是全双工的,所以在时钟沿上两条线同时传输数据。MOSI 将数据从主控芯片传输至从芯片,MISO 则将从芯片的数据传输到主控芯片。
正如你所看到的,他们是 SCK、MISO、MOSI 以及 SSEL。其中一个芯片叫做主控芯片, 另一个叫从芯片。
SPI 基础 http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus 基本特点: 1.同步 2.串行 3.全双工 4.非即插即用 5.一主多从 更多细节: 1.同步时钟有主控芯片产生,每个时钟传输一位数据 2.数据在传输前,首先许要进行并转串,才能用一条线传输 3.两条数据线,一条输入、一条输出 4.主从双方有关于 SPI 传输的先验知识,如比特顺序、数据长度等 5.数据传输有主控芯片发起,每次只与一个从芯片通讯
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
Now let's see if we can do useful things with SPI.
第二部分 SPI 接口的 FPGA 简单实现 ARM 处理器 为了检验我们刚学得的关于 SPI 的知识,我们使用一个带有 SPI 接口的 ARM7 板和 FPGA 板,板间由 SPI 总线连接。 ARM 处理器作为主控器,FPGA 作为 SPI 从机。来自百度文库图为他们之间的连接方式。
SPI 主控机 ‐ C 语言程序 使用 ARM 的 SPI 接口,只需要初始化一些寄存器,然后对 SPI 接口进行写数和读数操作 即可让 SPI 接口自动完成发送和接收数据。 void main(void) {
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; always @(posedge clk) if(byte_received) LED <= byte_data_received[0]; Finally the transmission part. reg [7:0] byte_data_sent; reg [7:0] cnt; always @(posedge clk) if(SSEL_startmessage) cnt<=cnt+8'h1; // count the messages always @(posedge clk) if(SSEL_active) begin
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.