SMT32通过SPI读写FPGA的寄存器

关于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的特性为:时钟空闲时为高电平,在时钟的下降沿将数据输出,在时钟的上升沿读取数据。

主要代码:

FPGA代码:

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 

SMT32部分

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++;		

	
	}     
		
}

运行结果

读写上万次无错误

猜你喜欢

转载自blog.csdn.net/qq_40893012/article/details/108013969
今日推荐