银杏科技有限公司旗下技术文档发布平台 |
技术支持电话 | 0379-69926675-801 |
技术支持邮件 | Gingko@vip.163.com |
版本 | 日期 | 作者 | 修改内容 |
V1.0 | 2020-07-02 | gingko | 初次建立 |
实验十三:SPI通信实验——基于SPI总线的ARM与FPGA通信
一、 实验目的与意义
掌握SPI通信协议及实现方法。
掌握QuartusII的使用方法。
二、 实验设备及平台
-
-
JLINK(或相同功能)仿真器。
Micro USB线缆。
Keil MDK 开发平台。
Quartus开发平台。
电脑一台。
三、 实验原理
1.SPI简介
2.SPI功能说明
3.SPI通信指令表
指令名称 | 字节1 | 字节2 | 字节3 | 字节4 |
器件ID | 01h | | | |
写数据长度 | 02h | A15~A8 | A7~A0 | |
写数据 | 04h | A15~A8 | A7~A0 | 数据(直至写完所有数据) |
读数据长度 | 05h | A15~A8 | A7~A0 | |
读数据 | 07h | A15~A8 | A7~A0 | 数据(直至读完所有数据) |
读错误信息 | 08h | | | |
ARM与FPGA通信采用的是半双工式通信,FPGA通过识别指令完成与ARM的交互。
器件ID指令为01h,接下来为两字节的伪指令,第四字节仍为伪指令读取ID标志。
写数据长度指令02h,接下来两个字节为写数据的长度,先发高字节,后发低字节,接下来为一个字节的伪指令00h。
写数据指令为04h,接下来为两字节的地址指令,后为要写入的数据,数据写入完毕以伪指令00h结束数据传输。
读数据长度指令05h,接下来两个字节为写数据的长度,先发高字节,后发低字节,接下来为一个字节的伪指令00h。
读数据指令为07h,接下来为两字节的地址指令,其后为伪指令00h开始读取数据进行数据传输,第五字节以后为要读取的数据。
读错误信息指令08h,FPGA接收数据是否出错,先发送两个字节的伪指令,第四字节仍为伪指令读取错误标志信息。
4、本实验实现方式
四、 代码讲解
本实验基于ARM+FPGA构架,通过ARM首先发送查询ID指令,然后依次通过指令设置写数据的长度、写数据地址、读数据的长度、读数据的地址,然后对比写入数据和读出数据是否一致判断数据是否写入成功,从而基于SPI总线实现ARM与FPGA之间的通信。
实现ARM与FPGA通信,对FPGA而言,其关键就在于SPI时序的模拟,实现SPI数据的接收与发送,实现数据与传输信号之间的串并转换。FPGA首先接收ARM指令,然后解析指令,存储相应的信息与数据,并根据指令需求将相应的指令数据放到SIMO总线上,等待ARM读取,从而实现两者之间的数据交互。SPI时序的硬件语言描述如下:
////////////////按字节接收SPI发送过来的数据//////////////
///////接收模块///////
reg[3:0]i;
reg[7:0]data_in;
reg [39:0]temp_data,data;
always@(posedge spi_clk or negedge rst_n)
if(!rst_n)
begin
i <= 4'd0;
temp_data <= 40'd0;
data <= 40'd0;
data_in <= 8'd0;
end
else case(i) //从高位开始接收数据,每8个spi_clk时钟接收一个Byte
4'd0:
begin
i <= i + 1'd1;
data_in <= {data_in[6:0],spi_mosi};
temp_data <= {temp_data[31:0],data_in};
if(data_in == 8'd13)
begin
data <= temp_data;
end
else
begin
data <= data;
end
end
4'd1,4'd2,4'd3,4'd4,4'd5,4'd6:
begin
i <= i + 1'd1;
data_in <= {data_in[6:0],spi_mosi};
end
4'd7:begin
i <= 4'd0;
data_in <= {data_in[6:0],spi_mosi};
end
default: i <= 4'd0;
endcase
/*对比接收数据*/
reg [2:0]led;
always@(posedge clk_25m or negedge rst_n)
if(!rst_n)
begin
led <= 3'b101;
end
else if (data == ledr)
led <= 3'b011; //红灯亮
else if (data == ledg)
led <= 3'b101; //绿灯亮
else if (data == ledb)
led <= 3'b110; //蓝灯亮
assign {led_red,led_green,led_blue} = led;
//--------------------------delay----------------------------//
reg spi_clk_r;
always@(posedge clk_25m or negedge rst_n)
if(!rst_n)
begin
spi_clk_r <= 1'd1;
end
else
spi_clk_r <= spi_clk;
//--------------------------spi_miso----------------------------//
/*发送模块*/
reg [39:0]data_out;
reg [5:0]j;
reg spi_out;
always@(negedge spi_clk_r or negedge rst_n)
if(!rst_n)
begin
data_out <= hello;
spi_out <= 1'd0;
j <= 6'd0;
end
else case(j) //连续40个spi_clk_r时钟发送“hello”字符串
6'd0:
begin
{spi_out,data_out[39:1]} <= data_out;
j <= j + 1'd1;
end
6'd39:
begin
{spi_out,data_out[39:1]} <= data_out;
data_out <= hello;
j <= 6'd0;
end
default:
begin
{spi_out,data_out[39:1]} <= data_out;
j <= j + 1'd1;
end
endcase
五、 实验步骤
1、把仿真器与iCore4的SWD调试口连接(直接相连或者通过转换器相连)。
2、将USB-Blaster与iCore4的JTAG调试口相连。
3、将跳线帽插在USB_UART。
4、把iCore4(USB_UART)通过Micro USB线与计算机相连,为iCore4供电。如图13-2所示:
图13-2
5、打开串口精灵,找到对应口打开,如下图。
6、打开KeilMDK开发环境,并打开实验工程。
7、将ARM程序下载至iCore4。
8、打开QuartusII开发环境,并打开实验工程。
9、将FPGA程序下载至iCore4
10、输入串口命令,观察实验现象。
六、 实验现象
串口命令发送格式 | ARM_LED现象 | FPGA_LED灯现象 |
LEDR\CR\LF | 红灯亮 | 红灯亮 |
LEDG\CR\LF | 绿灯亮 | 绿灯亮 |
LEDB\CR\LF | 蓝灯亮 | 蓝灯亮 |