1 FPGA实现SPI接口--什么是SPI接口?( 二 )


SPI 每次数据传输可以 8 位或 16 位为单位,每次传输的单位数不受限制 。
2.4、SPI协议的特性2.5、SPI协议的优势、劣势
优势:
劣势:
3、驱动代码的设计实现
接下来实现的SPI驱动代码特性如下:MSB 先行;仅限模式0;每次传输8位(1个BYTE) 。

1  FPGA实现SPI接口--什么是SPI接口?

文章插图
3.1、接口定义与整体设计
SPI驱动的整体框图、输入输出信号如下所示:
其中信号描述如下:
该模块的使用方法如下:
3.2、代码
代码并不复杂,结合下图的SPI通信过程,可以发现以下要点:
`timescale 1ns/1ns//时间单位/精度 // 模式0module spi_drive(// 系统接口inputsys_clk,// 全局时钟50MHzinputsys_rst_n ,// 复位信号,低电平有效// 用户接口 inputspi_start ,// 发送传输开始信号,一个高电平inputspi_end,// 发送传输结束信号,一个高电平input[7:0]data_send,// 要发送的数据outputreg[7:0]data_rec,// 接收到的数据outputregsend_done ,// 主机发送一个字节完毕标志位outputregrec_done ,// 主机接收一个字节完毕标志位// SPI物理接口inputspi_miso ,// SPI串行输入,用来接收从机的数据outputregspi_sclk ,// SPI时钟outputregspi_cs,// SPI片选信号,低电平有效outputregspi_mosi// SPI输出,用来给从机发送数据);reg [1:0] cnt;//4分频计数器reg [3:0] bit_cnt_send;//发送计数器reg [3:0] bit_cnt_rec;//接收计数器regspi_end_req;//结束请求// 生成片选信号spi_csalways @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)spi_cs <= 1'b1;//默认为高电平else if(spi_start)//开始SPI准备传输,拉低片选信号spi_cs <= 1'b0;//收到了SPI结束信号,且结束了最近的一个BYTEelse if(spi_end_req && (cnt == 2'd1 && bit_cnt_rec == 4'd0))spi_cs <= 1'b1;//拉高片选信号,结束SPI传输end// 生成结束请求信号(捕捉spi_end信号)always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)spi_end_req <= 1'b0;//默认不使能else if(spi_cs)spi_end_req <= 1'b0;//结束SPI传输后拉低请求else if(spi_end)spi_end_req <= 1'b1;//接收到SPI结束信号后就把结束请求拉高end// 发送数据过程--------------------------------------------------------------------// 发送数据always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginspi_mosi <= 1'b0;//模式0空闲bit_cnt_send <= 4'd0;endelse if(cnt == 2'd0 && !spi_cs)begin//模式0的上升沿spi_mosi <= data_send[7-bit_cnt_send]; //发送数据移位if(bit_cnt_send == 4'd7)//发送完8bitbit_cnt_send <= 4'd0;elsebit_cnt_send <= bit_cnt_send + 1'b1; endelse if(spi_cs)begin//非传输时间段spi_mosi <= 1'b0;//模式0空闲bit_cnt_send <= 4'd0;endelse beginspi_mosi <= spi_mosi;bit_cnt_send <= bit_cnt_send;endend// 发送数据标志always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)send_done <= 1'b0;else if(cnt == 2'd0 && bit_cnt_send == 4'd7)//发送完了8bit数据send_done <= 1'b1;//拉高一个周期,表示发送完成 else send_done <= 1'b0;end// 接收数据过程--------------------------------------------------------------------// 接收数据spi_misoalways @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)begindata_rec <= 8'd0;bit_cnt_rec <= 4'd0;endelse if(cnt == 2'd2 && !spi_cs)begin//模式0的上升沿data_rec[7-bit_cnt_rec] <=spi_miso;//移位接收if(bit_cnt_rec == 4'd7)//接收完了8bitbit_cnt_rec <= 4'd0;elsebit_cnt_rec <= bit_cnt_rec + 1'b1; endelse if(spi_cs)beginbit_cnt_rec <= 4'd0;endelse begindata_rec <= data_rec;bit_cnt_rec <= bit_cnt_rec;endend// 接收数据标志always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)rec_done <= 1'b0;else if(cnt == 2'd2 && bit_cnt_rec == 4'd7)//接收完了8bitrec_done <= 1'b1;//拉高一个周期,表示接收完成else rec_done <= 1'b0;endendmodule