MCU通过该SPI接口和FPGA通信,MCU可以读写4个寄存器:以及连续读写N(1-255)
字节数据,当然可以增加更多的寄存器。
MCU访问FPGA方式:
写寄存器时:在SPI_DI上发送 CMD + PARA 数据流
读寄存器时:在SPI_DI上发送 CMD + DUMMY 数据流 ,在第2字节SPI_DO上会所需的数据流
module STM32_FPGA_SPI(
input main_clk,
output arm_clk,
// input clk,
// input [7:0] data_in,
input spi_cs,
input spi_clk,
input spi_di, //MOSI
output spi_do, //MISO
output led
);
reg [24:0] led_cnt = 0;
always @(posedge clk)
led_cnt <= led_cnt + 1'b1;
assign led = led_cnt[24]; //闪灯,无关紧要
pll_8_50M pll_8_50M_inst (
.inclk0 ( main_clk ),//25M
.c0 ( arm_clk ), //8M
.c1 ( clk ) //50M
);
//定义读写寄存器cmd
parameter ARM_FPGA_REG1_ADDR = 8'h10;
parameter ARM_FPGA_REG2_ADDR = 8'h20;
parameter ARM_FPGA_REG3_ADDR = 8'h30;
parameter ARM_FPGA_REG4_ADDR = 8'h40;
parameter ARM_FPGA_BUF_READ_ADDR = 8'h70; //连续读命令
reg [7:0] ARM_FPGA_REG1 = 0;
reg [7:0] ARM_FPGA_REG2 = 0;
reg [7:0] ARM_FPGA_REG3 = 0;
reg [7:0] ARM_FPGA_REG4 = 0;
reg [7:0] ARM_FPGA_BUF_NUM = 0;
reg spi_clk_tmp1 = 0;
reg spi_clk_tmp2 = 0;
reg spi_clk_tmp3 = 0;
always @(posedge clk) //3级同步,比较可靠,2级也可以
begin
// spi_clk_tmp1 <= spi_clk;
// spi_clk_tmp2 <= spi_clk_tmp1;
spi_clk_tmp2 <= spi_clk;
spi_clk_tmp3 <= spi_clk_tmp2;
end
wire spi_clk_pos = (~spi_clk_tmp3) & spi_clk_tmp2;//上升沿
wire spi_clk_neg = (~spi_clk_tmp2) & spi_clk_tmp3;//下降沿
reg [2:0] state = 0;
reg [7:0] cmd_reg = 0;
reg [7:0] reg_data = 0;
reg [7:0] out_data = 0;
reg [3:0] cnt = 0;
reg [8:0] read_cnt = 0;
reg spi_di_tmp1 = 0;
reg spi_di_tmp2 = 0;
always @(posedge clk)
begin
// spi_di_tmp1 <= spi_di;
// spi_di_tmp2 <= spi_di_tmp1;
spi_di_tmp2 <= spi_di;
end
always @(posedge clk)
begin
if(~spi_cs)
case(state)
0 : if(spi_clk_pos)
begin
cmd_reg <= {cmd_reg[6:0],spi_di_tmp2}; //也可以将spi_di寄存
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 1;
end
end
1 : begin
case(cmd_reg)
ARM_FPGA_REG1_ADDR : if(spi_clk_pos) //写FPGA寄存器是上升沿 begin
MCU访问FPGA方式:
写寄存器时:在SPI_DI上发送 CMD + PARA 数据流
读寄存器时:在SPI_DI上发送 CMD + DUMMY 数据流 ,在第2字节SPI_DO上会所需的数据流
module STM32_FPGA_SPI(
input main_clk,
output arm_clk,
// input clk,
// input [7:0] data_in,
input spi_cs,
input spi_clk,
input spi_di, //MOSI
output spi_do, //MISO
output led
);
reg [24:0] led_cnt = 0;
always @(posedge clk)
led_cnt <= led_cnt + 1'b1;
assign led = led_cnt[24]; //闪灯,无关紧要
pll_8_50M pll_8_50M_inst (
.inclk0 ( main_clk ),//25M
.c0 ( arm_clk ), //8M
.c1 ( clk ) //50M
);
//定义读写寄存器cmd
parameter ARM_FPGA_REG1_ADDR = 8'h10;
parameter ARM_FPGA_REG2_ADDR = 8'h20;
parameter ARM_FPGA_REG3_ADDR = 8'h30;
parameter ARM_FPGA_REG4_ADDR = 8'h40;
parameter ARM_FPGA_BUF_READ_ADDR = 8'h70; //连续读命令
reg [7:0] ARM_FPGA_REG1 = 0;
reg [7:0] ARM_FPGA_REG2 = 0;
reg [7:0] ARM_FPGA_REG3 = 0;
reg [7:0] ARM_FPGA_REG4 = 0;
reg [7:0] ARM_FPGA_BUF_NUM = 0;
reg spi_clk_tmp1 = 0;
reg spi_clk_tmp2 = 0;
reg spi_clk_tmp3 = 0;
always @(posedge clk) //3级同步,比较可靠,2级也可以
begin
// spi_clk_tmp1 <= spi_clk;
// spi_clk_tmp2 <= spi_clk_tmp1;
spi_clk_tmp2 <= spi_clk;
spi_clk_tmp3 <= spi_clk_tmp2;
end
wire spi_clk_pos = (~spi_clk_tmp3) & spi_clk_tmp2;//上升沿
wire spi_clk_neg = (~spi_clk_tmp2) & spi_clk_tmp3;//下降沿
reg [2:0] state = 0;
reg [7:0] cmd_reg = 0;
reg [7:0] reg_data = 0;
reg [7:0] out_data = 0;
reg [3:0] cnt = 0;
reg [8:0] read_cnt = 0;
reg spi_di_tmp1 = 0;
reg spi_di_tmp2 = 0;
always @(posedge clk)
begin
// spi_di_tmp1 <= spi_di;
// spi_di_tmp2 <= spi_di_tmp1;
spi_di_tmp2 <= spi_di;
end
always @(posedge clk)
begin
if(~spi_cs)
case(state)
0 : if(spi_clk_pos)
begin
cmd_reg <= {cmd_reg[6:0],spi_di_tmp2}; //也可以将spi_di寄存
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 1;
end
end
1 : begin
case(cmd_reg)
ARM_FPGA_REG1_ADDR : if(spi_clk_pos) //写FPGA寄存器是上升沿 begin
ARM_FPGA_REG1 <= {ARM_FPGA_REG1[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_REG2_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_REG2 <= {ARM_FPGA_REG2[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_REG3_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_REG3 <= {ARM_FPGA_REG3[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_REG4_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_REG4 <= {ARM_FPGA_REG4[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_BUF_READ_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_BUF_NUM <= {ARM_FPGA_BUF_NUM[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 3;
end
end
/*以下为寄存器读*/
ARM_FPGA_REG1_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG1;
state <= 2;
end
ARM_FPGA_REG2_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG2;
state <= 2;
end
ARM_FPGA_REG3_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG3;
state <= 2;
end
ARM_FPGA_REG4_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG4;
state <= 2;
end
default : state<= 0;
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_REG2_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_REG2 <= {ARM_FPGA_REG2[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_REG3_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_REG3 <= {ARM_FPGA_REG3[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_REG4_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_REG4 <= {ARM_FPGA_REG4[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
ARM_FPGA_BUF_READ_ADDR : if(spi_clk_pos)
begin
ARM_FPGA_BUF_NUM <= {ARM_FPGA_BUF_NUM[6:0],spi_di_tmp2};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 3;
end
end
/*以下为寄存器读*/
ARM_FPGA_REG1_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG1;
state <= 2;
end
ARM_FPGA_REG2_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG2;
state <= 2;
end
ARM_FPGA_REG3_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG3;
state <= 2;
end
ARM_FPGA_REG4_ADDR + 1'b1 : if(spi_clk_neg) //读FPGA寄存器是下降沿
begin
out_data <= ARM_FPGA_REG4;
state <= 2;
end
default : state<= 0;
endcase
end
2 : begin //移位发送
if(spi_clk_neg)
begin
out_data <= {out_data[6:0],1'b0};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
end
3 : begin //连续读装载第一个初值
if(spi_clk_neg)
begin
out_data <= read_cnt;//data_in;
if(read_cnt == ARM_FPGA_BUF_NUM)
begin
read_cnt <= 0;
state <= 0;
end
else
state <= 4;
end
end
4 : begin //移位发送
if(spi_clk_neg)
begin
out_data <= {out_data[6:0],1'b0};
cnt <= cnt + 1;
if(cnt == 6) //6就可以了
begin
cnt <= 0;
read_cnt <= read_cnt + 1;
state <= 3;
end
end
end
default : state <= 0;
endcase
end
assign spi_do = out_data[7]; //SPI发送
endmodule
MCU驱动:
基本的SPI模式设置
CPOL_Low
CPHA_1Edge
SPI_DataSize_8b
SPI_FirstBit_MSB
/*******************************************************************************
最基本的SPI发送与接收函数,其他函数都以其为基础
通过SPI MOSI发送一字节,同时返回从MISO读的一字节,写与读共用8个clk
*******************************************************************************/
u8 SPI_FPGA_SendByte(u8 byte)
{
/* Loop while DR register in not emplty */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI1, byte);
/* Wait to receive a byte */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI1);
}
u8 SPI_FPGA_ReadByte(void)
{
return (SPI_FPGA_SendByte(Dummy_Byte));
}
void SPI_FPGA_Write_Reg(u8 cmd, u8 para)
{
SPI_FPGA_CS_LOW();
SPI_FPGA_SendByte(cmd);
SPI_FPGA_SendByte(para);
SPI_FPGA_CS_HIGH();
}
u8 SPI_FPGA_Read_Reg(u8 cmd)
{
u8 reg_val = 0xFF;
SPI_FPGA_CS_LOW();
SPI_FPGA_SendByte(cmd | 0x01);
reg_val = SPI_FPGA_ReadByte(); //dummy
SPI_FPGA_CS_HIGH();
return(reg_val);
}
/*读取 N 字节*/
void SPI_FPGA_Buf_Read(u8* pBuffer, u8 num)
{
SPI_FPGA_CS_LOW();
SPI_FPGA_SendByte(0x70);//读取一行 0x70命令
SPI_FPGA_SendByte(num); //dummy
while(num--)
{
*pBuffer = SPI_FPGA_ReadByte(); //dummy
pBuffer++;
}
SPI_FPGA_CS_HIGH();
}
实际测试发现3级寄存时,在4.5M的SPI时钟下工作稳定,理论上可以达到7、8M,需要检验,但是9M时已经不行了。 3级寄存改为2级寄存后,测试发现9M的spi_clk没有问题,这时理论可以达到12M。
end
2 : begin //移位发送
if(spi_clk_neg)
begin
out_data <= {out_data[6:0],1'b0};
cnt <= cnt + 1;
if(cnt == 7)
begin
cnt <= 0;
state <= 0;
end
end
end
3 : begin //连续读装载第一个初值
if(spi_clk_neg)
begin
out_data <= read_cnt;//data_in;
if(read_cnt == ARM_FPGA_BUF_NUM)
begin
read_cnt <= 0;
state <= 0;
end
else
state <= 4;
end
end
4 : begin //移位发送
if(spi_clk_neg)
begin
out_data <= {out_data[6:0],1'b0};
cnt <= cnt + 1;
if(cnt == 6) //6就可以了
begin
cnt <= 0;
read_cnt <= read_cnt + 1;
state <= 3;
end
end
end
default : state <= 0;
endcase
end
assign spi_do = out_data[7]; //SPI发送
endmodule
MCU驱动:
基本的SPI模式设置
CPOL_Low
CPHA_1Edge
SPI_DataSize_8b
SPI_FirstBit_MSB
/*******************************************************************************
最基本的SPI发送与接收函数,其他函数都以其为基础
通过SPI MOSI发送一字节,同时返回从MISO读的一字节,写与读共用8个clk
*******************************************************************************/
u8 SPI_FPGA_SendByte(u8 byte)
{
/* Loop while DR register in not emplty */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI1, byte);
/* Wait to receive a byte */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI1);
}
u8 SPI_FPGA_ReadByte(void)
{
return (SPI_FPGA_SendByte(Dummy_Byte));
}
void SPI_FPGA_Write_Reg(u8 cmd, u8 para)
{
SPI_FPGA_CS_LOW();
SPI_FPGA_SendByte(cmd);
SPI_FPGA_SendByte(para);
SPI_FPGA_CS_HIGH();
}
u8 SPI_FPGA_Read_Reg(u8 cmd)
{
u8 reg_val = 0xFF;
SPI_FPGA_CS_LOW();
SPI_FPGA_SendByte(cmd | 0x01);
reg_val = SPI_FPGA_ReadByte(); //dummy
SPI_FPGA_CS_HIGH();
return(reg_val);
}
/*读取 N 字节*/
void SPI_FPGA_Buf_Read(u8* pBuffer, u8 num)
{
SPI_FPGA_CS_LOW();
SPI_FPGA_SendByte(0x70);//读取一行 0x70命令
SPI_FPGA_SendByte(num); //dummy
while(num--)
{
*pBuffer = SPI_FPGA_ReadByte(); //dummy
pBuffer++;
}
SPI_FPGA_CS_HIGH();
}
实际测试发现3级寄存时,在4.5M的SPI时钟下工作稳定,理论上可以达到7、8M,需要检验,但是9M时已经不行了。 3级寄存改为2级寄存后,测试发现9M的spi_clk没有问题,这时理论可以达到12M。