基于单片机与FPGA的SPI

1.SPI含义

SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议。

 2.步骤

step1 stm32_3pin_to_fpga_input

 prj_fpga_spi_input

  由单片机传送数据到FPGA。

prj_stm32_gpio_wave_3pin

#include "stm32f10x.h" 
#include "usart.h"
void Delay(u32 count) 
{ 
  u32 i=0; 
  for(;i<count;i++); 
} 

void init_gpio_clk(){
  GPIO_InitTypeDef    GPIO_InitStructure;
  //使能PE 端口时钟 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);        
  //PE.10 端口配置 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;           
  // 推挽输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
  //IO 口 速度50MHz 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  // 初始化GPIOE.10
  GPIO_Init(GPIOE, &GPIO_InitStructure);             
  // PE.10 为高
  GPIO_SetBits(GPIOE,GPIO_Pin_10);          
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;           
  GPIO_Init(GPIOE, &GPIO_InitStructure);             
  GPIO_SetBits(GPIOE,GPIO_Pin_12);          
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;           
  GPIO_Init(GPIOE, &GPIO_InitStructure);             
  GPIO_SetBits(GPIOE,GPIO_Pin_14);          

}
void gpio_clk_loop(){
  while(1) {
    GPIO_SetBits  (GPIOE,GPIO_Pin_10);          
    GPIO_ResetBits(GPIOE,GPIO_Pin_10);          
    GPIO_SetBits  (GPIOE,GPIO_Pin_12);          
    GPIO_ResetBits(GPIOE,GPIO_Pin_12);          
    GPIO_SetBits  (GPIOE,GPIO_Pin_14);          
    GPIO_ResetBits(GPIOE,GPIO_Pin_14);          
  }
}

void init_gpio_led(){
  GPIO_InitTypeDef    GPIO_InitStructure;
  //使能PB,PE 端口时钟 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOE, ENABLE);        
  //LED0-->PB.5 端口配置 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;           
  // 推挽输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
  //IO 口 速度50MHz 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  // 初始化GPIOB.5
  GPIO_Init(GPIOB, &GPIO_InitStructure);             
  // PB.5 为低
  GPIO_ResetBits(GPIOB,GPIO_Pin_5);          
  //LED1-->PE.5  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                      
  // 初始化 GPIO
  GPIO_Init(GPIOE, &GPIO_InitStructure);                      
  //PE.5  输出为低      
  GPIO_ResetBits(GPIOE,GPIO_Pin_5);          
}

void gpio_led_tick_loop(int n){
  int count = n;
  while(count) 
  {
    if(n > 0){
      count = count - 1;
    }
    GPIO_SetBits(GPIOE,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    Delay(2000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(2000000); 
    
    GPIO_SetBits(GPIOE,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    Delay(2000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(2000000); 
   
    GPIO_SetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
   
    GPIO_SetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
   
    GPIO_SetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(4000000); 
  }
}
int main(void) 
{   
  init_gpio_clk();
  init_gpio_led();
  gpio_led_tick_loop(1);
  gpio_clk_loop();
}

step2 stm32_SPI_to_fpga_input

prj_fpga_spi_input

module spi_bus(
  I_CLK     ,
  I_CS      ,
  I_SCLK    ,
  I_SDIN    ,
  O_DOUT    ,
  O_DOV     ,
  O_TESTOUT1);


input I_CLK    ;
input I_CS     ;
input I_SCLK   ;
input I_SDIN    ;

output O_TESTOUT1;

reg  R1_I_CS  ,R2_I_CS ,R3_I_CS  ;
reg  R1_I_SCLK ,R2_I_SCLK,R3_I_SCLK ;
reg  R1_I_SDIN ,R2_I_SDIN,R3_I_SDIN ;
reg  W_I_CS_up , W_I_CS_down, W_I_SCLK_up;

reg [32-1:0] R_sdin_shift, R_out_buf;
output [32-1:0] O_DOUT;
output          O_DOV ;   
reg             O_DOV ;   

always @ (*) begin
  W_I_CS_up   = ((R3_I_CS == 1'b0)&&( R2_I_CS == 1'b1)) ? 1'b1 : 1'b0;
  W_I_CS_down = ((R3_I_CS == 1'b1)&&( R2_I_CS == 1'b0)) ? 1'b1 : 1'b0;
  W_I_SCLK_up  = ((R3_I_SCLK == 1'b0)&&( R2_I_SCLK == 1'b1)) ? 1'b1 : 1'b0;
end
always @ (posedge I_CLK) begin
  R1_I_CS   <= I_CS       ;
  R1_I_SCLK <= I_SCLK     ;
  R1_I_SDIN <= I_SDIN     ;
  R2_I_CS   <= R1_I_CS    ;
  R2_I_SCLK <= R1_I_SCLK  ;
  R2_I_SDIN <= R1_I_SDIN  ;
  R3_I_CS   <= R2_I_CS    ;
  R3_I_SCLK <= R2_I_SCLK  ;
  R3_I_SDIN <= R2_I_SDIN  ;
end
always @ (posedge I_CLK) begin
  if(W_I_CS_down)
    R_sdin_shift <= 0;
  else
    if(W_I_SCLK_up)
      R_sdin_shift <= {R_sdin_shift[30:0],R2_I_SDIN};
  if(W_I_CS_up)
    R_out_buf <= R_sdin_shift;
  O_DOV <= W_I_CS_up;
end
assign O_DOUT = R_out_buf;


assign O_TESTOUT1 =  W_I_SCLK_up ;

endmodule

 这个程序是32位输出,SPI的数据传给FPGA。

prj_stm32_SPI_to_fpga_input

#include "stm32f10x.h" 
#include "usart.h"
void Delay(u32 count) 
{ 
  u32 i=0; 
  for(;i<count;i++){
   __nop(); 
  }
} 

#define PIN_MY_SPI_O_SCLK GPIO_Pin_10
#define PIN_MY_SPI_O_CS   GPIO_Pin_12
#define PIN_MY_SPI_O_SDA  GPIO_Pin_14

#define PORT_MY_SPI_O_SCLK GPIOE
#define PORT_MY_SPI_O_CS   GPIOE
#define PORT_MY_SPI_O_SDA  GPIOE

void init_spi_pin(){
  GPIO_InitTypeDef    GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);     //使能PE 端口时钟 
  GPIO_InitStructure.GPIO_Pin = PIN_MY_SPI_O_SCLK;              //PE.PIN 端口配置 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          // 推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO 口 速度50MHz 
  GPIO_Init(PORT_MY_SPI_O_SCLK, &GPIO_InitStructure);                    // 初始化GPIOE.PIN
  GPIO_SetBits(PORT_MY_SPI_O_SCLK,PIN_MY_SPI_O_SCLK);                        // PE.PIN 为高
  
  GPIO_InitStructure.GPIO_Pin = PIN_MY_SPI_O_CS;           
  GPIO_Init(PORT_MY_SPI_O_CS, &GPIO_InitStructure);             
  GPIO_SetBits(PORT_MY_SPI_O_CS,PIN_MY_SPI_O_CS);          
  
  GPIO_InitStructure.GPIO_Pin = PIN_MY_SPI_O_SDA;           
  GPIO_Init(GPIOE, &GPIO_InitStructure);             
  GPIO_SetBits(PORT_MY_SPI_O_SDA,PIN_MY_SPI_O_SDA);          

}

void spi_wr_cs(int val){
  GPIO_WriteBit(PORT_MY_SPI_O_CS,PIN_MY_SPI_O_CS      ,(val&0x1)?Bit_SET:Bit_RESET    );
}
void spi_wr_sck(int val){
  GPIO_WriteBit(PORT_MY_SPI_O_SCLK,PIN_MY_SPI_O_SCLK      ,(val&0x1)?Bit_SET:Bit_RESET    );
}
void spi_wr_sda_out(int val){
  GPIO_WriteBit(PORT_MY_SPI_O_SDA,PIN_MY_SPI_O_SDA      ,(val&0x1)?Bit_SET:Bit_RESET    );
}


void spi_wr_32bit_MSB_first(unsigned char B3,unsigned char B2,unsigned char B1,unsigned char B0){
  int delay_unit = 5;
  int i = 0, j = 0;
  unsigned char byte4[4] = {0};
  unsigned char buf = 0;
  byte4[3] = B3; byte4[2] = B2; byte4[1] = B1; byte4[0] = B0;

  
  spi_wr_cs(1);
  spi_wr_sck(1);
  spi_wr_sda_out(1);
  // drop down cs
  spi_wr_cs(0);
  Delay(1);
  // drop down sck
  spi_wr_sck(0);
  Delay(1);
  // put data
  for(j = 0; j < 4; j ++){
    buf = byte4[3-j];
    for(i = 0; i < 8; i ++){
      spi_wr_sda_out((buf&0x80) >> 7);
      buf = buf << 1;
      Delay(1);
      spi_wr_sck(1);
      Delay(1);
      spi_wr_sck(0);
    }
  }
  spi_wr_cs(1);
  spi_wr_sck(1);
}


void spi_wr_test_loop(){
  while(1) {
    spi_wr_cs(1);
    spi_wr_cs(0);
    spi_wr_sck(1);
    spi_wr_sck(1);
    spi_wr_sck(0);
    spi_wr_sck(0);
    spi_wr_sda_out(1);
    spi_wr_sda_out(1);
    spi_wr_sda_out(1);
    spi_wr_sda_out(0);
    spi_wr_sda_out(0);
    spi_wr_sda_out(0);
  }
}

void spi_wr_data_loop(){
  while(1) {
    spi_wr_32bit_MSB_first(0xA5, 0xA7, 0xA9, 0xAB);
    spi_wr_32bit_MSB_first(0x5A, 0x5B, 0x5C, 0x5D);
  }
}

void init_gpio_led(){
  GPIO_InitTypeDef    GPIO_InitStructure;
  //使能PB,PE 端口时钟 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOE, ENABLE);        
  //LED0-->PB.5 端口配置 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;           
  // 推挽输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
  //IO 口 速度50MHz 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  // 初始化GPIOB.5
  GPIO_Init(GPIOB, &GPIO_InitStructure);             
  // PB.5 为低
  GPIO_ResetBits(GPIOB,GPIO_Pin_5);          
  //LED1-->PE.5  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                      
  // 初始化 GPIO
  GPIO_Init(GPIOE, &GPIO_InitStructure);                      
  //PE.5  输出为低      
  GPIO_ResetBits(GPIOE,GPIO_Pin_5);          
}

void gpio_led_tick_loop(int n){
  int count = n;
  while(count) 
  {
    if(n > 0){
      count = count - 1;
    }
    GPIO_SetBits(GPIOE,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    Delay(2000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(2000000); 
    
    GPIO_SetBits(GPIOE,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    Delay(2000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(2000000); 
   
    GPIO_SetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
   
    GPIO_SetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
   
    GPIO_SetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(1000000); 
    GPIO_ResetBits(GPIOB,GPIO_Pin_5); 
    GPIO_ResetBits(GPIOE,GPIO_Pin_5); 
    Delay(4000000); 
  }
}
int main(void) 
{   
  init_spi_pin();
  init_gpio_led();
  gpio_led_tick_loop(1);
  // spi_wr_test_loop();
  spi_wr_data_loop();
}

输出32位数据,要分成4次,每次8位。

step3 stm32_SPI_write_fpga_addr_decode

prj_fpga_spi_input_bus_addr_decode

 

prj_stm32_SPI_to_fpga_bus_addr_decode

stm32通过spi读取fpga的地址。

step4 stm32_SPI_read_select_write_fpga_addr_decode

prj_fpga_spi_input_bus_read_write

 实现fpga与单片机的互传,并在单片机的显示屏上显示

prj_stm32_SPI_to_fpga_bus_read_write 

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值