串口外设接口SPI(Serial Peripheral Interface)是一种由Motorola公司推出的一种同步串行接口,得到了广泛应用。
SPI通信协议
SPI,顾名思义就是串行外围通信接口,只需四条线就可以完成主、从与各种外围器件全双工同步通信。4根接口线分别是:串行时钟线(SCK)、主机输入/从机输出数据线(MISO)、主机输出/从机输入(MOSI),低电平有效从机选择线(CS)。
SPI系统可分为主机设备和从机设备两类设备,其中主机提供SPI时钟信号和片选信号,从机设备是接受SPI信号的任何集成电路。当SPI工作时,在移位寄存器中的数据逐位从输出引脚(MOSI)输出,同时从输入引脚(MISO)逐位接受数据。发送和接收操作都受控于SPI主机设备的时钟信号(SCK),从而保证同步,因此只能有一个主设备,但从设备可以有多个,通过不同的片选信号可以同时选择一个或多个从设备。
下面是用Verilog HDL实现的SPI主模式,其中读写操作都是低字节在前,高字节在后,每次传输一个字节
module spi_master(
addr,
in_data,
out_data,
wr,
rd,
cs,
clk,
miso,
mosi,
sclk
);
input[1:0]addr;
input [7:0]in_data;
output [7:0]out_data;
reg [7:0]out_data;
input clk;
input wr;
input rd;
input cs;
inout miso;
inout mosi;
inout sclk;
reg sclk_buffer = 0;
reg mosi_buffer = 0;
reg busy = 0;
reg [7:0]in_buffer = 0;
reg [7:0]out_buffer = 0;
reg [7:0]clkcount = 0;
reg [7:0]clkdiv = 0;
reg [4:0]count = 0;
always@(cs or rd or addr or out_buffer or busy or clkdiv) begin
out_data = 8'bx;
if(cs&&rd) begin
case(addr)
2'b00 : out_data = out_buffer;
2'b01 : out_data = {7'b0,busy};
2'b10 : out_data = clkdiv;
default: out_data = out_data;
endcase
end
end
always@(posedge clk) begin
if(!busy) begin
if(cs&&wr) begin
case(addr)
2'b00 : begin
in_buffer <= in_data;
busy <= 1'b1;
end
2'b10 : in_buffer <= clkdiv;
default : in_buffer <= in_buffer;
endcase
end// end if(cs&&wr);
end
else begin
clkcount <= clkcount+1;
if(clkcount >= clkdiv) begin
clkcount <=0;
if(count%2 == 0) begin
mosi_buffer <= in_buffer[7];
in_buffer <= in_buffer<<1;
end
if(count>0 && count<17) begin
sclk_buffer <= ~sclk_buffer;
end
count <= count+1;
if(count > 17) begin
busy <= 0;
count <= 0;
end
end
end
end
always@(posedge sclk_buffer) begin
out_buffer = out_buffer<<1;
out_buffer[0] = miso;
end
assign sclk=sclk_buffer;
assign mosi=mosi_buffer;
endmodule
写功能的仿真结果