本篇主要介绍SPI协议在FPGA内部的实现,如何使用Verilog语言来搭建硬件描述电路,通过一款SPI通信协议的芯片ADC128S022来具体讲解,ADC128S022是一款AD转换芯片,具有8通道。
B站对应讲解本文视频链接
SPI概念:
SPI(Serial Peripheral Interface,串行外设接口)是Motorola公司提出的一种同步串行数据传输标准,在很多器件中被广泛应用。
接口:
SPI接口经常被称为4线串行总线,以主/从方式工作,数据传输过程由主机初始化。如图1所示,其使用的4条信号线分别为:
- SCLK:串行时钟,用来同步数据传输,由主机输出;
- MOSI:主机输出从机输入数据线,通常先传输MSB;
- MISO:主机输入从机输出数据线,通常先传输LSB;
- SS:片选线,低电平有效,由主机输出。
在SPI总线上,某一时刻可以出现多个从机,但只能存在一个主机,主机通过片选线来确定要通信的从机。这就要求从机的MISO口具有三态特性,使得该口线在器件未被选通时表现为高阻抗。
ADC128S022具体时序:
该接口使用标准的SPI 接口,因此可以直接连接到微控制器的片上SPI。对于FPGA 来说,则可按照 SPI 时序搭建控制电路,以实现对ADC128S022 的控制。
特别要注意一下两个的时序,DIN在SCLK的上升沿输入,DOUT在SCLK的下降沿输出,也就是说说DIN是在SCLK的下降沿改变,DOUT是在SCLK的上升沿改变。
借助器件的时序图就可以具体来实现对器件的写入和输出数据了。
ADC128S022具体实现(线性序列机):
此处借鉴小梅哥FPGA
该接口的时序是一个很有规律的序列,SCLK 信号什么时候该由低变高,什么时候由高变低。DIN 信号什么时候该传输哪一位数据,都是可以根据时序参数唯一确定下来的。 这样就可以将该数据波形放到以时间为横轴的一个二维坐标系中,纵轴就是每个信号对应的状态。因此只需要在逻辑中使用一个计数器来计数,然后每个计数值时就相当于在t 轴上对应了一个相应的时间点,那么在这个时间点上,各个信号需要进行什么操作,直接赋值即可。
按照线性序列机的设计思路,可以整理得到每个信号发生变化时对应的时刻
以及此时对应的计数器的值。表为依照线性序列机的设计思想,整理得到的每个信号发生变化时对应的时刻以及此时对应的计数器的值。其中CS_N 为芯片状态标志信号,SCLK 为芯片时钟输入脚,DIN 为芯片串行数据输入,DOUT为芯片串行数据输出。
ADC128S022 接口逻辑模块图如图所示:
代码:
//序列机实现ADC串行数据接口的数据发送和接收
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
ADC_SCLK <= 1'b1;
ADC_CS_N <= 1'b1;
ADC_DIN <= 1'b1;
end else if(en) begin
if(SCLK2X)begin
case(SCLK_GEN_CNT)
6'd0:begin ADC_CS_N <= 1'b0; end
6'd1:begin ADC_SCLK <= 1'b0; ADC_DIN <= 1'b0; end
6'd2:begin ADC_SCLK <= 1'b1; end
6'd3:begin ADC_SCLK <= 1'b0; end
6'd4:begin ADC_SCLK <= 1'b1; end
6'd5:begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[2];end //addr[2]
6'd6:begin ADC_SCLK <= 1'b1; end
6'd7:begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[1];end //addr[1]
6'd8:begin ADC_SCLK <= 1'b1; end
6'd9:begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[0];end //addr[0]
//每个上升沿,寄存ADC串行数据输出线上的转换结果
6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6'd22,6'd24,6'd26,6'd28,6'd30,6'd32:
begin ADC_SCLK <= 1'b1; r_data <= {r_data[10:0], ADC_DOUT}; end //循环移位寄存DOUT上的12个数据
6'd11,6'd13,6'd15,6'd17,6'd19,6'd21,6'd23,6'd25,6'd27,6'd29,6'd31:
begin ADC_SCLK <= 1'b0; end
6'd33:begin ADC_CS_N <= 1'b1; end
default:begin ADC_CS_N <= 1'b1; end //将转换结果输出
endcase
end
else ;
end else begin
ADC_CS_N <= 1'b1;
end
modelsim仿真:
同理,无论是SPI协议还是其他例如UART还是IIC协议都是一样的,实现器件的功能只需要去寻找所用的器件,然后根据器件中所给的时序图,通过时序给器件发送和接收指令,实现控制各种器件,有不明白的,或者想要各种参考资料的可以联系博主QQ:2859340499.