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