SPI通信的四种方式 FPGA的SPI从机实现方案

时间:2025-11-01  作者:Diven  阅读:0

一. SPI总线协议

SPI通信的四种方式 FPGA的SPI从机实现方案

SPI(Serial Peripheral Interface)接口,中文为串行外设接口。只需要3根线或4根线即可完成通信工作(这里讨论4根线的情况)。

这4根通信线分别为NCS/NSS(片选信号)、SCK/SCLK(串行同步时钟)、MOSI/SDO(主机输出从机输入,Master Output Slave Input)、MISO/SDI(主机输入从机输出)。

SPI通信有四种方式,由CPOL(时钟极性)、CPHA(时钟相位)的4种组合决定的。CPOL决定总线空闲时,SCK是高电平还是低电平(CPOL=,0,无数据传输时,SCK=0;CPOL=1,无数据传输时,SCK=1)。CPHA决定在数据开始传输时,SCK第几个跳变沿采集数据(CPHA=0,开始传输时,在第一个跳变沿采集数据,第二个跳变沿改变发送数据(即改变MISO或者MOSI线上电平);CPHA=1,开始传输是,在第一个跳变沿改变发送的数据,在第二个跳变沿采集数据)(见图1)。

图1

确立可靠通信前,必须保证主从机处于同的传输方式,这里为方便起见,专门以CPOL=0,CPHA=0的传输方式进行讨论。需要注意的是:在CPOL=0,CPHA=0的情况下,主从机都在SCK上跳沿对数据进行采集,SCK下跳沿改变总线电平(见图2)。

图2

这里在使用FPGA实现SPI模块时,做一个规定:

1. 使用CPOL=0,、CPHA=0的传输方式;

2. 传输时,以最高位先输出,最后输出最低位;

3. FPGA实现的SPI模块作从机,SCK由外部主机提供;

4. 通信数据长度为8位。

二. FPGA的SPI从机实现

实现SPI从机,可以分为两个模块:一个是SPI接收模块,另一个则是SPI发送模块。

1. 首先确定模块的输出输入管脚

由标题一可以知道,SPI通信脚有4根线,我们还是用到时钟总线和模块复位脚,因此模块管脚可以定义为

Module myspi(nrst, clk, ncs, mosi, miso, sck);
input clk, nrst;input ncs, mosi, sck;output miso;

2. SCK跳变沿检测

原理十分简单:使用寄存器记录SCK状态,由状态判断SCK是否出现跳变沿。

reg[2:0] sck_edge;

always @ (posedge clk or negedge nrst)

begin

if(~nrst)

begin

sck_edge <= 3'b000;

end

else

begin

sck_edge <= {sck_edge[1:0], sck};

end

end

wire sck_riseedge, sck_falledge;

assign sck_riseedge = (sck_edge[2:1] == 2'b01); //检测到SCK由0变成1,则认为发现上跳沿

assign sck_falledge = (sck_edge[2:1] == 2'b10); //检测到SCK由1变成0,则认为发现下跳沿

3. SPI接收部分

SPI接收部分使用有限状态机:

状态1:等待SCK上跳沿,并将MOSI的数据移入移位寄存器byte_received,接收位数寄存器bit_received_cnt记录接收到的数据位数,接收到8位数据后转入状态2;

状态2:保存移位寄存器byte_received数据到接收缓存器rec_data,接收标志位/接收缓存器非空标志位rec_flag置高4个clk时钟周期后转入状态3;

状态3:清除rec_flag并转入状态1。

reg[7:0] byte_received;reg[3:0] bit_received_cnt;reg rec_flag;reg[1:0] rec_status; //SPI接收部分状态机reg[7:0] rec_data;reg[2:0] rec_flag_width; //SPI接收完成标志位脉冲宽度寄存器always @ (posedge clk or negedge nrst) //每次sck都会接收数据,spi的顶端模块状态机决定是否取用beginif(~nrst)beginbyte_received <= 8'h00;bit_received_cnt <= 4'h0;rec_flag <= 1'b0;rec_status <= 2'b00;rec_flag_width <= 3'b000;endelsebeginif(~ncs)begincase (rec_status)2'b00: beginif(sck_riseedge)beginbyte_received <= {byte_received[6:0], mosi};if(bit_received_cnt == 4'h7)beginbit_received_cnt <= 4'b0000;rec_status <= 2'b01;endelsebeginbit_received_cnt <= bit_received_cnt+1;endendend2'b01: beginrec_data <= byte_received;rec_flag <= 1'b1;if(rec_flag_width==3'b100) beginrec_flag_width <= 3'b000;rec_status <= 2'b11;endelse beginrec_flag_width <= rec_flag_width+1;endend2'b11: beginrec_flag <= 1'b0;rec_status <= 2'b00;endendcaseendendend

     这里,使用rec_flag的原因是通知另一个模块处理接收数据(后面将会提到),rec_data若在下一次数据传输完成前不做处理则会丢失。

4. SPI发送部分

SPI从机一般在解析主机发送的命令后,主动发出主机所需数据,所以,SPI发送部分,需要其模块的触发,并将数据送往MISO管脚。

SPI发送部分也离不开状态机:

状态1:等待发送触发标志位send_flag置高,一旦标志位send_flag置高,发送移位寄存器byte_sended存储外部触发模块的数据send_data,miso管脚输出发送数据最高位send_data[7],置位正在发送标志位sending_flag,转入状态2;

状态2:等待SCK上跳沿,即等待主机接收数据最高位后进入状态3;(其实这个状态可有可无的状态)

状态3:在SCK下跳沿,将发送移位寄存器byte_sended最高位移入miso管脚,当发送移位寄存器被移空,清除正在发送标志位sending_flag,进入状态4;

状态4:置低miso管脚,转入状态1。

reg miso;reg sending_flag; //正在发送标志位reg[7:0] byte_sended; //发送移位寄存器reg[3:0] bit_sended_cnt; //SPI发送位计数器reg[1:0] send_status; //SPI发送部分状态机always @ (posedge clk or negedge nrst)beginif(~nrst)beginbyte_sended <= 8'h00;bit_sended_cnt <= 4'b0000;send_status <= 2'b00;sending_flag <= 1'b0;endelsebeginif(~ncs)begincase (send_status)2'b00: beginif(send_flag)begin //锁存发送数据send_status <= 2'b01; //2'b01;byte_sended <= send_data;sending_flag <= 1'b1;miso <= send_data[7];endend2'b01: begin //发送数据移入移位寄存器if(sck_riseedge) begin//miso <= byte_sended[7];//byte_sended <= {byte_sended[6:0], 1'b0};send_status <= 2'b11;endend2'b11: begin //根据sck下降沿改变数据miso <= byte_sended[7];if(sck_falledge) ///---------------------------------------这里多移了一位begin//miso <= byte_sended[7];byte_sended <= {byte_sended[6:0], 1'b0};if(bit_sended_cnt == 4'b0111)beginsend_status <= 2'b10;bit_sended_cnt <= 4'b0000;sending_flag <= 1'b0;endelsebeginbit_sended_cnt <= bit_sended_cnt+1;endendend2'b10: begin //数据发送完毕send_status <= 2'b00;//sending_flag <= 1'b0;miso <= 1'b0;endendcaseendendend

经过实测,SCK频率低于clk频率8倍以上,通信可靠稳定,测试芯片为XC3S50-TQ144,平台为ISE,clk为25MHz。

​​​编辑:黄飞

 

猜您喜欢

贴片电阻上的「2051」并非直接代表阻值大小,而是采用一种数字编码方式来表示。其中,「205」代表阻值有效数字,而「1」代表乘数因子。具体来说,「205」表示有...
2024-11-26 11:29:40

分流器作为重要的无源器件,应用于信号分配和功率分配系统中。RALEC(旺诠)作为知名的分流器品牌,高品质的产品性能和可靠的品牌信誉,赢得了众多客户的青睐。本文将...
2016-04-26 02:17:30

发光二极管(LED)是应用于照明、显示和信号指示的电子元件。在电路图中,LED的符号通常包含一个箭头,这个箭头不仅是图形的一部分,更蕴含着重要的含义。本文将深入...
2025-04-08 05:31:08

在智能手机市场的激烈竞争中,iPhone系列始终以其卓越的相机性能著称,这离不开索尼相机传感器的贡献。当前,iPhone 15 Pro Max便搭载了索尼的IM...
2024-07-25 15:09:00

你是否想过,智能手机是如何在长时间使用后依然保持稳定运行的?电子设备内部错综复杂的电路,又是如何得到精准供电的呢?这其中,就少不了超低压线性稳压器的功劳。简单来...
2024-09-01 00:00:00

内六角凹端紧定螺钉是应用于机械和电子设备中的紧固件。主要作用是提供稳定的连接和固定,确保组件在使用过程中不会松动或移位。与普通螺钉相比,内六角凹端设计使其在安装...
2008-07-24 00:00:00

在汽修行业中,各种工具的选择直接影响到维修效果和效率。手动工具与电动工具的区别显而易见。手动工具如扳手和螺丝刀,适用于简单的维修和细致的操作,而电动工具则能在短...
2012-11-12 00:00:00

555定时器作为电子电路中的经典元件,其主要优势不容忽视。555定时器具有多功能性,能够实现定时、脉冲生成、频率计数等多种应用,适用于的电子项目。其结构简单,易...
2023-01-12 00:00:00

贴片电阻规格尺寸中的字母a和b分别代表其长和宽。例如,常见的0402封装尺寸,表示该电阻的长为0.04英寸(约1.0毫米),宽为0.02英寸(约0.5毫米)。 ...
2024-11-26 11:29:32

贴片排阻作为电子元器件中的重要组成部分,应用于各种电子设备中。SEI(世达柏科技)作为知名的电子元器件供应商,提供多种类型的贴片排阻产品,满足不同客户的需求。本...
2016-12-01 05:56:30