关于SPI的主机和从机请看;https://blog.csdn.net/qq_40893012/article/details/103995154
本设计在FPGA用32个寄存器构建了一个8bit*32的ROM,可通过STM32使用SPI写入命令字节来实现对32个寄存器的读写操作。
命令字节的格式:
bit 7:读写控制位,
1:W
0:R
bit6-bit2:寄存器地址
bit1-bit0:未使用
stm32的代码基于正电原子的探索者开发板和工程,使用软件模拟SPI,FPGA使用Verilog编写。
SPI的特性为:时钟空闲时为高电平,在时钟的下降沿将数据输出,在时钟的上升沿读取数据。
主要代码:
1 SPI从机部分
// 32位二段式状态机spi模块
module spi_slave16bit(
input wire clk,
input rst_n,
input wire CS,
input wire SCK,
input wire MOSI,
output reg MISO,
output reg [5:0]rom_addr,
output reg busy,//spi给fpga其他模块,busy=1时,禁止FPGA读写
input wire[15:0] data_to_out,
output reg[15:0] data_had_receive,
output rxd_over //rx 2byte will generate pulse
);
reg [1:0] state;
parameter IDLE = 2'b00;
parameter TRANS = 2'b01;
parameter WAIT = 2'b10;
reg [1:0]CS_buf;
wire CS_falling_flag;
wire CS_rising_flag;
always@(posedge clk)
begin
CS_buf[1] <= CS_buf[0];
CS_buf[0] <= CS;
end
assign CS_falling_flag = CS_buf[1] &(~CS_buf[0]);
assign CS_rising_flag = (~CS_buf[1]) & CS_buf[0];
reg [1:0]SCK_buf;
wire SCK_falling_flag;
wire SCK_rising_flag;
always@(posedge clk)
begin
SCK_buf[1] <= SCK_buf[0];
SCK_buf[0] <= SCK;
end
assign SCK_falling_flag = SCK_buf[1]&(~SCK_buf[0]);
assign SCK_rising_flag = (~SCK_buf[1])&SCK_buf[0];
reg [5:0]count;
// state machine
always@(posedge clk)
begin
case(state)
IDLE:begin
if(CS_falling_flag==1) state <= TRANS;
end
TRANS:begin
if(count == 6'b010000) state <= WAIT; // 传完16个数
else if (CS_rising_flag==1) state <= IDLE; // 意外结束
end
WAIT:begin
if (CS_rising_flag) state <= IDLE;
end
endcase
end
// count
always@(posedge clk)
begin
case(state)
IDLE: count<=6'b0;
TRANS:begin
if(SCK_rising_flag == 1) count <= count + 6'b1;
end
endcase
end
// MISO
always@(posedge clk)
begin
if ((state == TRANS)&&(SCK_falling_flag == 1))
begin
case(count)
6'b000000: MISO <= data_to_out[15];
6'b000001: MISO <= data_to_out[14];
6'b000010: MISO <= data_to_out[13];
6'b000011: MISO <= data_to_out[12];
6'b000100: MISO <= data_to_out[11];
6'b000101: MISO <= data_to_out[10];
6'b000110: MISO <= data_to_out[9];
6'b000111: MISO <= data_to_out[8];
6'b001000: MISO <= data_to_out[7];
6'b001001: MISO <= data_to_out[6];
6'b001010: MISO <= data_to_out[5];
6'b001011: MISO <= data_to_out[4];
6'b001100: MISO <= data_to_out[3];
6'b001101: MISO <= data_to_out[2];
6'b001110: MISO <= data_to_out[1];
6'b001111: MISO <= data_to_out[0];
/* 6'b010000: MISO <= data_to_out[15];
6'b010001: MISO <= data_to_out[14];
6'b010010: MISO <= data_to_out[13];
6'b010011: MISO <= data_to_out[12];
6'b010100: MISO <= data_to_out[11];
6'b010101: MISO <= data_to_out[10];
6'b010110: MISO <= data_to_out[9];
6'b010111: MISO <= data_to_out[8];
6'b011000: MISO <= data_to_out[7];
6'b011001: MISO <= data_to_out[6];
6'b011010: MISO <= data_to_out[5];
6'b011011: MISO <= data_to_out[4];
6'b011100: MISO <= data_to_out[3];
6'b011101: MISO <= data_to_out[2];
6'b011110: MISO <= data_to_out[1];
6'b011111: MISO <= data_to_out[0]; */
endcase
end
end
// MOSI
reg rxd_flag_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rxd_flag_r <= 0;
else
begin
if ((state == TRANS)&&(SCK_rising_flag == 1))
begin
case(count)
6'b000000: begin data_had_receive[15] <= MOSI;rxd_flag_r<=1'b0;end
6'b000001: data_had_receive[14] <= MOSI;
6'b000010: data_had_receive[13] <= MOSI;
6'b000011: data_had_receive[12] <= MOSI;
6'b000100: data_had_receive[11] <= MOSI;
6'b000101: begin
data_had_receive[10] <= MOSI; //set rom addr
rom_addr[5:0] <= {data_had_receive[15:11],MOSI};
end
6'b000110: data_had_receive[9] <= MOSI;
6'b000111: data_had_receive[8] <= MOSI;
6'b001000: data_had_receive[7] <= MOSI;
6'b001001: data_had_receive[6] <= MOSI;
6'b001010: data_had_receive[5] <= MOSI;
6'b001011: data_had_receive[4] <= MOSI;
6'b001100: data_had_receive[3] <= MOSI;
6'b001101: data_had_receive[2] <= MOSI;
6'b001110: data_had_receive[1] <= MOSI;
6'b001111: begin data_had_receive[0] <= MOSI; rxd_flag_r<=1'b1;end
/* 6'b010000: data_had_receive[15] <= MOSI;
6'b010001: data_had_receive[14] <= MOSI;
6'b010010: data_had_receive[13] <= MOSI;
6'b010011: data_had_receive[12] <= MOSI;
6'b010100: data_had_receive[11] <= MOSI;
6'b010101: data_had_receive[10] <= MOSI;
6'b010110: data_had_receive[9] <= MOSI;
6'b010111: data_had_receive[8] <= MOSI;
6'b011000: data_had_receive[7] <= MOSI;
6'b011001: data_had_receive[6] <= MOSI;
6'b011010: data_had_receive[5] <= MOSI;
6'b011011: data_had_receive[4] <= MOSI;
6'b011100: data_had_receive[3] <= MOSI;
6'b011101: data_had_receive[2] <= MOSI;
6'b011110: data_had_receive[1] <= MOSI;
6'b011111: data_had_receive[0] <= MOSI; */
endcase
end
end
end
reg rxd_flag_r0,rxd_flag_r1;
always@(negedge rst_n or posedge clk)
begin
if(!rst_n)
begin
rxd_flag_r0 <= 1'b0;
rxd_flag_r1 <= 1'b0;
end
else
begin
rxd_flag_r0 <= rxd_flag_r;
rxd_flag_r1 <= rxd_flag_r0;
end
end
assign rxd_over = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;
// busy
always@(posedge clk)
begin
case(state)
IDLE: busy <= 0;
TRANS: busy <= 1;
WAIT: busy <= 0;
endcase
end
endmodule
2 寄存器构成ROM模块
module spi_rom
(
rst,
rxd_flag,
reg_addr,
reg_out,
rxd_in_spi
);
input rst,rxd_flag;
input [5:0] reg_addr;
input [15:0] rxd_in_spi;
output reg [7:0] reg_out;
reg [7:0] REG_ROM[31:0];
always@(negedge rst or posedge rxd_flag)
begin
if(!rst)
begin
REG_ROM[0] <= 8'd0;
REG_ROM[1] <= 8'd1;
REG_ROM[2] <= 8'd2;
REG_ROM[3] <= 8'd3;
REG_ROM[4] <= 8'd4;
REG_ROM[5] <= 8'd5;
REG_ROM[6] <= 8'd6;
REG_ROM[7] <= 8'd7;
REG_ROM[8] <= 8'd8;
REG_ROM[9] <= 8'd9;
REG_ROM[10] <= 8'd10;
REG_ROM[11] <= 8'd11;
REG_ROM[12] <= 8'd12;
REG_ROM[13] <= 8'd13;
REG_ROM[14] <= 8'd14;
REG_ROM[15] <= 8'd15;
REG_ROM[16] <= 8'd16;
REG_ROM[17] <= 8'd17;
REG_ROM[18] <= 8'd18;
REG_ROM[19] <= 8'd19;
REG_ROM[20] <= 8'd20;
REG_ROM[21] <= 8'd21;
REG_ROM[22] <= 8'd22;
REG_ROM[23] <= 8'd23;
REG_ROM[24] <= 8'd24;
REG_ROM[25] <= 8'd25;
REG_ROM[26] <= 8'd26;
REG_ROM[27] <= 8'd27;
REG_ROM[28] <= 8'd28;
REG_ROM[29] <= 8'd29;
REG_ROM[30] <= 8'd30;
REG_ROM[31] <= 8'd31;
end
else
begin
if(rxd_in_spi[15]==1'b1)
REG_ROM[rxd_in_spi[14:10]] = rxd_in_spi[7:0];
end
end
always@(reg_addr)
begin
if(reg_addr[5]==0)
reg_out=REG_ROM[reg_addr[4:0]];
else reg_out=8'd0; //if write and next byte will tx 8'b0
end
/* always@(posedge rxd_flag)
begin
if(rxd_in_spi[15]==1'b1)
REG_ROM[rxd_in_spi[14:10]] = rxd_in_spi[7:0];
end */
endmodule
3 顶层模块
module TEST_MODULE
(
clk,
rst,
cs,
sck,
MOSI,
MISO,
led_pin,
rxd_over
);
input clk,rst,cs,sck,MOSI;
output MISO,led_pin,rxd_over;
wire rxd_flag;
wire [5:0] rom_addr;
wire [7:0] reg_out;
wire [15:0]rxd_in_spi;
wire spi_busy;
wire rxd_over;
wire [7:0] dat_to_out;
//always@(posedge clk)
//begin
// if(!spi_busy)
// dat_to_out[15:8] <= 8'd255;
//end
LED_module LED_module_inst
(
.clk(clk),
.rst(rst),
.led_pin(led_pin)
);
spi_slave16bit(
.clk(clk),
.rst_n(rst),
.CS(cs),
.SCK(sck),
.MOSI(MOSI),
.MISO(MISO),
.rom_addr(rom_addr),
.busy(spi_busy),//spi给fpga其他模块,busy=1时,禁止FPGA读写
.data_to_out({8'hff,dat_to_out}),//first byte TX 0hff
.data_had_receive(rxd_in_spi),
.rxd_over(rxd_over)
);
spi_rom spi_rom_inst
(
.rst(rst),
.rxd_flag(rxd_over),
.reg_addr(rom_addr),
.reg_out(dat_to_out),
.rxd_in_spi(rxd_in_spi)
);
endmodule
1 头文件及部分定义
#define SPI_CS PGout(7)
#define SPI_MISO PBin(4)
#define SPI_MOSI PBout(5)
#define SPI_CLK PBout(3)
void soft_spi_ioinit(void);
u8 get_cmd(u8 wr,u8 addr);
u8 spi_read2byte(u8 reg_addr);
u8 spi_write2byte(u8 reg_addr,u8 dat);
2 函数声明部分
void soft_spi_ioinit()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//ʹÄÜGPIOB,GʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //CS
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//ÆÕͨÊä³öģʽ
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ
GPIO_Init(GPIOG, &GPIO_InitStructure);//³õʼ»¯PG6,7
SPI_CS=1; //SPIƬѡȡÏû
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//ʹÄÜGPIOAʱÖÓ
//GPIOFB3,5³õʼ»¯ÉèÖÃ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_5;//PB3~5¸´Óù¦ÄÜÊä³ö
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//¸´Óù¦ÄÜ
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯
SPI_CLK = 1;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//PB3~5¸´Óù¦ÄÜÊä³ö
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//ÆÕͨÊäÈëģʽ
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;//100M
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯
}
u8 get_cmd(u8 wr,u8 addr)//wr=1:w wr=0:r addr:0-31
{
u8 reg=0;
//if(wr) reg = 128;
reg = wr;
reg = reg<<5;
reg = reg+addr;
reg =reg<<2;
return reg;
};
u8 spi_read2byte(u8 reg_addr) //reg_addr:0-31
{
u32 tmp=0;
u8 i=0;
u8 addr;
SPI_CS = 1;
SPI_CLK = 1;
SPI_CS = 0;
addr = get_cmd(0,reg_addr);
delay_us(1);
for(i=0;i<8;i++)
{
SPI_CLK = 1;
if(addr&0x80)SPI_MOSI = 1;
else SPI_MOSI = 0;
addr = addr<<1;
delay_us(1);
SPI_CLK = 0;
delay_us(1);
SPI_CLK = 1;
tmp =tmp<<1;
tmp = tmp+SPI_MISO;
}
delay_us(2);
for(i=0;i<8;i++)
{
SPI_CLK = 1;
SPI_MOSI = 1;
delay_us(1);
SPI_CLK = 0;
delay_us(1);
SPI_CLK = 1;
tmp =tmp<<1;
tmp = tmp+SPI_MISO;
}
SPI_CLK = 1;
SPI_CS = 1;
return tmp&0x00ff;
}
u8 spi_write2byte(u8 reg_addr,u8 dat)
{
u32 tmp=0;
int i=0;
u8 addr;
u8 dat_buff = dat;
SPI_CS = 1;
SPI_CLK = 1;
SPI_CS = 0;
delay_us(1);
addr = get_cmd(1,reg_addr);
for(i=0;i<8;i++)
{
SPI_CLK = 1;
if(addr&0x80)SPI_MOSI = 1;
else SPI_MOSI = 0;
addr = addr<<1;
delay_us(1);
SPI_CLK = 0;
delay_us(1);
SPI_CLK = 1;
tmp =tmp<<1;
tmp = tmp+SPI_MISO;
}
delay_us(2);
for(i=0;i<8;i++)
{
SPI_CLK = 1;
if(dat_buff&0x80)SPI_MOSI = 1;
else SPI_MOSI = 0;
dat_buff = dat_buff<<1;
delay_us(1);
SPI_CLK = 0;
delay_us(1);
SPI_CLK = 1;
tmp =tmp<<1;
tmp = tmp+SPI_MISO;
}
SPI_CLK = 1;
SPI_CS = 1;
return tmp&0x00ff;
}
3 主函数
int main(void)
{
u8 key,mode;
u8 t=0;
u32 error_num=0;
u32 read_num=0;
u32 rec=0;
u8 tmp_buf[33];
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é2
delay_init(168); //³õʼ»¯ÑÓʱº¯Êý
uart_init(115200); //³õʼ»¯´®¿Ú²¨ÌØÂÊΪ115200
LED_Init(); //³õʼ»¯LED
// LCD_Init(); //LCD³õʼ»¯
// KEY_Init(); //°´¼ü³õʼ»¯
// NRF24L01_Init(); //³õʼ»¯NRF24L01
soft_spi_ioinit();
//NRF24L01_Read_Reg(reg);
while(1)
{
for(t=0;t<32;t++)
{
//key = get_reg(0,t);
key = rand()%100;
spi_write2byte(t,key);
rec = spi_read2byte(t);
if(rec!=key)
{
error_num++;
printf("error_num = %d\r\n",error_num);
}
read_num++;
if(read_num%100==0)
{
printf("error_num = %d\r\n",error_num);
}
printf("send = %d rec_num = %d read_num = %d\r\n",key,rec,read_num);
rec = 0;
//if(key==5)
//else printf("key = %d ERROR\r\n",key);
delay_ms(100);
}
t++;
}
}
读写上万次无错误