STM32与FPGA通过SPI通信


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

你可能感兴趣的:(FPGA)