【Verilog实例】第一篇–SPI串行总线
1.SPI的简要介绍
SPI(Serial Parallel Bus)总线是Motorola公司提出的一个同步串行外设接口,允许CPU 与各种外围接口器件(包括模/数转换器、数/模转换器、液晶显示驱动器)以串行方式进行通信、交换信息。他使用4条线:串行时钟线(SCK)、主机输入/从机输出线(MISO)、主机输出/从机输入线(MOSI)、低电平有效的使能信号线(CS)。这样,仅需3~4根数据线和控制线即可扩展具有SPI接口的各种I/O器件,其典型结构如图所示:
*串行通信:“串行”数据传输方式指数据位按顺序依次传输,一个接一个地发送或接收。在串行通信中,数据被转换成位流,并通过单个通道(如电缆、光纤等)传输。在接收端,接收器将位流重新组装成数据。串行通信通常比并行通信需要更少的物理线路,因为它只需要一个通道来传输数据,而不是多个通道。这使得串行通信在一些情况下更加适用,特别是在长距离传输或高速传输的情况下。串行通信有许多不同的标准和协议,例如串行通信中常见的UART(通用异步收发传输器)、SPI(串行外围接口)、I2C(Inter-Integrated Circuit)和串行ATA(Advanced Technology Attachment)等。
2.SPI总线接口的设计与实现
该模块是802.1lb无线局域网芯片中的一子模块,其系统信号交互如下图所示:
其中base band(基带)为SPI的主控器(master),RF(射频)为SPI的受控器(slave)。该SPI接口需要完成以下工作:
1)将从base band接收到的16位的并行数据,转换为RF所能接收的串行数据,并将该数据根据SPI协议送给RF。
2) 产生RF所需的时钟信号SCLK,使能信号(也称:片选信号)CSB。
3) 接收从RF传回的串行数据,并将其转换为并行数据。
4) 将base band发送的数据,与RF返回的数据进行比较,并把比较结果传给base band。
以下为SPI数据传输的部分代码片段,主要功能为产生计数器以同步slave模块的时钟sclk,并且将串行数据转换为并行数据。
生成计数器:
always@(posedge clock or negedge reset)
begin
if(!enable)
counter<= 0;
else if(enable)
begin
if(counter< 53)
counter=counter + 1;
end
end
生成使能信号csb:
//片选信号低位有效
always@ (posedge clock or negedge reset)
begin
if(reset)
csb <=1;
else if(counter>= 1 && counter <= 50)
csb = 0;
else
csb = 1;
end
生成RF模块使用的时钟信号sclk:
//每三个节拍,RF信号拉为高电平,使其可以接收数据
always@ (posedge clock or negedge reset)
begin
case(counter)
6'd02: sclk = 1;
6'd05: sclk = 1;
6'd08: sclk = 1;
6'd11: sclk = 1;
6'd14: sclk = 1;
6'd17: sclk = 1;
6'd20: sclk = 1;
6'd23: sclk = 1;
6'd26: sclk = 1;
6'd29: sclk = 1;
6'd32: sclk = 1;
6'd35: sclk = 1;
6'd38: sclk = 1;
6'd41: sclk = 1;
6'd44: sclk = 1;
6'd47: sclk = 1;
default sclk = 0;
endcase
end
RF端接收数据:
//每三个节拍,slave接受一位数据
always@ (counter or csb)
begin
if(csb == 0)
case(counter)
6'h00,
6'h01,
6'h02,
6'h03:mosi_index = 5'h00;
6'h04,
6'h05,
6'h06:mosi_index = 5'h01;
6'h07,
6'h08,
6'h09:mosi_index = 5'h02;
6'h0A,
6'h0B,
6'h0C:mosi_index = 5'h03;
6'h0D,
6'h0E,
6'h0F:mosi_index = 5'h04;
6'h10,
6'h11,
6'h12:mosi_index = 5'h05;
6'h13,
6'h14,
6'h15:mosi_index = 5'h06;
6'h16,
6'h17,
6'h18:mosi_index = 5'h07;
6'h19,
6'h1A,
6'h1B:mosi_index = 5'h08;
6'h1C,
6'h1D,
6'hlE:mosi_index = 5'h09;
6'h1F,
6'h20,
6'h21:mosi_index = 5'h0A ;
6'h22,
6'h23,
6'h24:mosi_index = 5'h0B;
6'h25,
6'h26,
6'h27:mosi_index = 5'h0C ;
6'h28,
6'h29,
6'h2A:mosi_index = 5'h0D ;
6'h2B,
6'h2C,
6'h2D:mosi_index = 5'h0E;
6'h2E,
6'h2F,
6'h30:mosi_index = 5'h0F;
default:mosi_index = 5'h00;
endcase
else
mosi_index = 5'h00:
end
assign mosi=spi_data[mosi_index];
使用Vivado进行波形仿真:
附:一个简易的testbench文件为:
module SPI_test;
reg clock,reset;
reg [15:0] spi_data=16'haaaa;
reg enable;
wire [5:0] counter;
wire csb;
wire sclk;
wire mosi;
wire [4:0] mosi_index;
SPI spi(clock,reset,spi_data,enable,counter,csb,sclk,mosi,mosi_index);
always #5 clock=~clock;
initial begin
#0 clock=1'b0;
reset=1'b1;
enable=1'b0;
#10 reset=1'b0;
enable=1'b1;
end
endmodule