SPI
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
Step1、检验管脚连接是否正确
由单片机传送数据到FPGA,在signaltap上验证 单片机部分代码
#include "stm32f4xx.h"
#include "delay.h"
#include "test.h"
#include "SPI.h"
void gpio_led_tick_loop(int n){
int count = n;
while(count)
{
GPIO_SetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
GPIO_ResetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
break;
}
}
void gpio_clk_loop(){
while(1) {
GPIO_SetBits (GPIOC,GPIO_Pin_4);
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
GPIO_SetBits (GPIOA,GPIO_Pin_7);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
GPIO_SetBits (GPIOC,GPIO_Pin_5);
GPIO_ResetBits(GPIOC,GPIO_Pin_5);
}
}
int main(void)
{
delay_init(168);
ALLGPIO_Init();
gpio_led_tick_loop(1);
gpio_clk_loop();
}
#include "test.h"
void ALLGPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIOA->MODER=0x01;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_15);
GPIO_InitStructure.GPIO_Pin = PIN_MY_SPI_O_CS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
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_SCLK;
GPIO_Init(PORT_MY_SPI_O_SCLK, &GPIO_InitStructure);
GPIO_SetBits(PORT_MY_SPI_O_SCLK,PIN_MY_SPI_O_SCLK);
GPIO_InitStructure.GPIO_Pin = PIN_MY_SPI_O_SDA;
GPIO_Init(PORT_MY_SPI_O_SDA, &GPIO_InitStructure);
GPIO_SetBits(PORT_MY_SPI_O_SDA,PIN_MY_SPI_O_SDA);
}
#ifndef _GPIO_H
#define _GPIO_H
#include "sys.h"
#define PIN_MY_SPI_O_SCLK GPIO_Pin_4
#define PIN_MY_SPI_O_CS GPIO_Pin_7
#define PIN_MY_SPI_O_SDA GPIO_Pin_5
#define PORT_MY_SPI_O_SCLK GPIOC
#define PORT_MY_SPI_O_CS GPIOA
#define PORT_MY_SPI_O_SDA GPIOC
void ALLGPIO_Init(void);
#endif
FPGA部分代码
module spi_bus(
I_CLK ,
I_CS ,
I_SCK ,
I_SDA ,
O_TESTOUT);
input I_CLK ;
input I_CS ;
input I_SCK ;
input I_SDA ;
output O_TESTOUT;
reg R1_I_CS ;
reg R1_I_SCK ;
reg R1_I_SDA ;
always @ (posedge I_CLK) begin
R1_I_CS <= I_CS ;
R1_I_SCK <= I_SCK ;
R1_I_SDA <= I_SDA ;
end
assign O_TESTOUT = R1_I_CS | R1_I_SDA| R1_I_SCK;
endmodule
signaltap的波形与单片机程序对应,确认连接无误
Step2、SPI的数据传给FPGA
单片机部分代码
#include "stm32f4xx.h"
#include "delay.h"
#include "test.h"
#include "SPI.h"
void gpio_led_tick_loop(int n){
int count = n;
while(count)
{
GPIO_SetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
GPIO_ResetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
break;
}
}
int main(void)
{
delay_init(168);
ALLGPIO_Init();
gpio_led_tick_loop(1);
spi_wr_data_loop();
}
void spi_wr_data_loop(){
delay_init(168);
while(1) {
spi_wr_32bit_MSB_first(0xA5, 0xA6, 0xA7, 0xA8);
delay_us(10);
spi_wr_32bit_MSB_first(0x5A, 0x5B, 0x5C, 0x5D);
}
}
FPGA部分
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
signaltap验证如下
Step3、stm32通过spi读取fpga的地址
单片机部分代码
#include "stm32f4xx.h"
#include "delay.h"
#include "test.h"
#include "SPI.h"
void gpio_led_tick_loop(int n){
int count = n;
while(count)
{
GPIO_SetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
GPIO_ResetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
break;
}
}
int main(void)
{
delay_init(168);
ALLGPIO_Init();
gpio_led_tick_loop(1);
spi_wr_addr_16b_data_16b_loop();
}
void spi_wr_addr_16b_data_16b_loop(){
while(1) {
spi_wr_32bit_MSB_first(0x00, 0x00, 0x02, 0x02);
spi_wr_32bit_MSB_first(0x00, 0x01, 0x01, 0x01);
spi_wr_32bit_MSB_first(0x00, 0x00, 0x04, 0x04);
spi_wr_32bit_MSB_first(0x00, 0x01, 0x05, 0x05);
spi_wr_32bit_MSB_first(0x00, 0x02, 0x01, 0x02);
spi_wr_32bit_MSB_first(0x00, 0x03, 0x03, 0x04);
spi_wr_32bit_MSB_first(0x00, 0x04, 0x00, 0x00);
spi_wr_32bit_MSB_first(0x00, 0x02, 0x04, 0x03);
spi_wr_32bit_MSB_first(0x00, 0x03, 0x02, 0x01);
spi_wr_32bit_MSB_first(0x00, 0x04, 0x00, 0x00);
spi_wr_addr_16b_data_16b_ram_128();
}
}
FPGA部分 signaltap验证
Step4、stm32_SPI_read_select_write_fpga_addr_decode
这一步实现fpga与单片机的互传,并在单片机的显示屏上显示 单片机部分代码
//main函数
#include "stm32f4xx.h"
#include "delay.h"
#include "test.h"
#include "SPI.h"
#include "usart.h"
#include "tftlcd.h"
void gpio_led_tick_loop(int n){
int count = n;
while(count)
{
GPIO_SetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
GPIO_ResetBits(GPIOA,GPIO_Pin_15);
delay_ms(2000);
break;
}
}
void my_sys_init(){
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //??NVIC????2:2??????,2??????
//??????115200
}
int main(void)
{
uart_init(115200);
delay_init(168);
delay_ms(2000);
printf("hello?");
LCD_Init();
//LCD_DrawLine(0,240,800,240);
//LCD_ShowString(340,30,300,24,24,"TFTLCD TEST");
my_sys_init();
printf("Hello Stm32 \r\n");
delay_init(168);
ALLGPIO_Init();
// gpio_led_tick_loop(1);
// spi_wr_test_loop();
// spi_wr_data_loop();
spi_write_reg_ram_read_reg_rom_test();
}
//spi_write_reg_ram_read_reg_rom_test函数
void spi_write_reg_ram_read_reg_rom_test(){
unsigned int rd_val = 0;
LCD_Clear(65535);
while(1) {
char text[]="";
// counter increase value write test case
// A_H A_L , D_H , D_L
spi_wr_32bit_MSB_first(0x00, 0x00, 0x02, 0x02); // 16 bit counter 1
spi_wr_32bit_MSB_first(0x00, 0x01, 0x01, 0x01); // 16 bit counter 2
spi_wr_32bit_MSB_first(0x00, 0x00, 0x04, 0x04); // 16 bit counter 1
spi_wr_32bit_MSB_first(0x00, 0x01, 0x05, 0x05); // 16 bit counter 2
spi_wr_32bit_MSB_first(0x00, 0x02, 0x01, 0x02); // 32 bit counter L
spi_wr_32bit_MSB_first(0x00, 0x03, 0x03, 0x04); // 32 bit counter H
spi_wr_32bit_MSB_first(0x00, 0x04, 0x00, 0x00); // 32 bit counter Update
spi_wr_32bit_MSB_first(0x00, 0x02, 0x04, 0x03); // 32 bit counter L
spi_wr_32bit_MSB_first(0x00, 0x03, 0x02, 0x01); // 32 bit counter H
spi_wr_32bit_MSB_first(0x00, 0x04, 0x00, 0x00); // 32 bit counter Update
// ram write test case
spi_wr_addr_7b_data_16b_ram_128();
printf("#------------------------------------------------------------------------------- \r\n");
printf("# Counter read test \r\n");
// read address write test case
// before read, write the read select value to mux first, select the mux input 0 to output
spi_wr_32bit_MSB_first(0x00, 0x07, 0x00, 0x00);
// read the output value of the selected mux input port 0, a 16 bit counter value
rd_val = spi_wr_1bit_cmd_read_16bit();
//printf("# counter 0 read value = %4x\r\n", rd_val);
sprintf(text,"# counter 0 read value = %4x\r\n", rd_val);
LCD_ShowString(100,50,200,200,24,text);
spi_rd_addr_7b_data_8_rom_128();
}
}
以及LCD部分代码 FPGA部分
验证: signaltap上的数据与显示屏上的一致,说明数据传输过程无误
在显示屏上打印rom表
应用
将频率计的数值送到单片机,并在LCD屏幕上显示
将频率计输出的频率分为高低十六位分别送进DIN0和DIN1,即可顺利传送数据,然后将高位数据×65536,+第十六位数据,得到最终结果,并在显示屏上显示
结果验证:
|