|
楼主 |
发表于 2012-4-11 10:10:07
|
显示全部楼层
wye11083 发表于 2012-4-10 23:22
SPI协议的模式只和开始状态有关,不管是什么模式,SI总是在SCK上升沿被锁存,SO总是在SCK下降沿输出(JTAG ...
谢谢,观察入微哦,在数据存取时,我多打了一拍,现在是STM32 --> FPGA数据正确,有时也会出错,STM32 <-- FPGA 收不到数据的。
以下是STM32的代码:SPI是8分频的
#define SCS_HIGH GPIO_SetBits(GPIOA, GPIO_Pin_4)
#define SCS_LOW GPIO_ResetBits(GPIOA, GPIO_Pin_4)
void SPI1_Configeration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //NSS(PA.4) 推免输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; //MOSI(PA.7) SCK(PA.5) 复用推免输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //MISO(PA.6) 浮点输入
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
////////////////////////////////////////////////////////////////////////////////////////
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE); //打开端口复用时钟、SPI1时钟
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟悬空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第1个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件控制NSS型号
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //比特率8分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //定义了用于CRC值计算的多项式
SPI_Init(SPI1,&SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE); //使能SPI1
}
/**********************************************************
函数名称: SPI_SendByte
功 能: SPI1发/收一个字节数据(硬件SPI)
**********************************************************/
unsigned char SPI1_SendByte(unsigned char dt)
{
SCS_LOW;
//等待SPI1发送完毕
while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET));
SPI_I2S_SendData(SPI1,dt);
//等待SPI1接收完毕
while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET));
SCS_HIGH;
return SPI_I2S_ReceiveData(SPI1);
}
FPGA的SPI模块代码: 和上面差不多,由于个人习惯,改了一些名称
//`timescale 1ns/1ps
module SPI_Slave(clk,rst_n,
SCK,MOSI,MISO,NSS,INT,
Data_Ready,Data_Received
);
input clk; //FPGA clock,50MHz
input rst_n; //FPGA reset signal,fallingedge is effective
input SCK; //Master's SPI SCK signal,Idle:0/Risingedge:Sample/Fallingedge:Latched
input MOSI; //Master Out Slaver In
output MISO; //Master In Slaver Out
input NSS; //SPI Chip-select signal
output INT; //Slaver interrupt signal of requesting to send data to Master
output Data_Ready; //detect Data_Received ready or not
output[7:0] Data_Received; //SPI_Bus receive data from the Master
//===============================================================================
//sync SCK to the FPGA clock using a 3-bits shift register
reg[2:0] SCK_r;
always @(posedge clk or negedge rst_n)
if(!rst_n) SCK_r <= 3'b000;
else SCK_r <= {SCK_r[1:0],SCK};
wire SCK_risingedge = (SCK_r[2:1]==2'b01); //Now we can detect SCK rising edges
wire SCK_fallingedge = (SCK_r[2:1]==2'b10); //and falling edges
//the same thing for NSS
reg[2:0] NSS_r;
always @(posedge clk or negedge rst_n)
if(!rst_n) NSS_r <= 3'b000;
else NSS_r <= {NSS_r[1:0],NSS};
wire NSS_Active = ~NSS_r[1]; //NSS is active now
wire NSS_startmessage = (NSS_r[2:1]==2'b10); //message starts at falling edge
//not be used//wire NSS_endmessage = (NSS_r[2:1]==2'b01); //message stops at rising edge
//and for MOSI
reg[1:0] MOSI_r;
always @(posedge clk or negedge rst_n)
if(!rst_n) MOSI_r <= 2'b00;
else MOSI_r <= {MOSI_r[0],MOSI};
wire MOSI_Data = MOSI_r[1];
//===============================================================================
//we handle SPI in 8-bits format,so we need a 3-bits counter to count the bits as they come in.
reg[2:0] bitcnt;
reg byte_received; //high while a byte has already been received
reg[7:0] byte_data_received;
always @(posedge clk or negedge rst_n)
if(!rst_n) begin bitcnt <= 3'b000; byte_data_received <= 7'h00; end
else if(!NSS_Active) bitcnt <= 3'b000;
else if(SCK_risingedge) begin
bitcnt <= bitcnt +1'b1;
//implement a shift-left register(since we receive the data MSB first)
byte_data_received <= {byte_data_received[6:0],MOSI_Data};
end
assign Data_Received = byte_data_received;
always @(posedge clk or negedge rst_n)
if(!rst_n) byte_received <= 1'b1;
else
byte_received <= NSS_Active && SCK_risingedge && (bitcnt==3'b111);
assign Data_Ready = byte_received;
//===============================================================================
//Here we use INT signal for test,we use the LSB of the data received to control an LED
reg INT;
always @(posedge clk) if(Data_Ready) INT <= byte_data_received[0];
// count the messages
reg[7:0] cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt <= 8'h00;
else if(NSS_startmessage) cnt <= cnt + 8'h1;//NSS_Active && SCK_risingedge && (bitcnt==3'b111)
//===============================================================================
reg[7:0] byte_data_send;
always @(posedge clk)
if(NSS_Active)
begin
if(NSS_startmessage) byte_data_send <=cnt; //first byte send in a message is the message count
else
if(SCK_fallingedge)
begin
if(bitcnt==3'b000) byte_data_send <= 8'h00; //after that,we send 0s
else byte_data_send <= {byte_data_send[6:0],1'b0};
end
end
//always @(posedge clk or negedge rst_n)
// if(!rst_n) byte_data_send <= 8'd123;
// else if(NSS_Active&&SCK_fallingedge)
// byte_data_send <= {byte_data_send[6:0],1'b0};
//
assign MISO = byte_data_send[7]; //send MSB first
endmodule
|
|