1. 程式人生 > >STM32與FPGA通過SPI通訊

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。