用户工具

站点工具


icore4tx_fpga_18
银杏科技有限公司旗下技术文档发布平台
技术支持电话0379-69926675-801
技术支持邮件Gingko@vip.163.com
版本 日期 作者 修改内容
V1.0 2020-06-29 gingko 初次建立



实验十八:SPI通信实验——基于SPI总线的ARM与FPGA通信

一、 实验目的与意义

  1. 掌握SPI通信协议及实现方法。
  2. 掌握ISE开发环境的使用。

二、 实验设备及平台

  1. iCore4TX 双核心板点击购买
  2. USB CABLE(或相同功能)仿真器。
  3. JLINK(或相同功能)仿真器。
  4. Micro USB线缆。
  5. Keil MDK 开发平台。
  6. ISE开发平台。
  7. 电脑一台。

三、 实验原理

1.SPI简介

  • SPI是串行外设接口(Serial PeripheralInterface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB布局节省空间。它以主从方式工作,这种模式通常有一个主设备,和一个或多个从设备;SPI的通信原理很简单,需要至少4根线(事实上单向传输时3根也可以),是所有基于SPI通信的设备共用的,它们是SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。
    • SPI硬件接口:
      • MISO :主设备数据输入,从设备数据输出
      • MOSI :主设备数据输出,从设备数据输入
      • SCLK :时钟信号,由主设备产生
      • CS :从设备片选信号,由主设备控制

2.SPI功能说明

  • SPI时钟极性和相位:
    • CPOL决定时钟空闲时的稳定电平,对主/从都有效
    • CPOL=0:空闲时低电平
    • CPOL=1:空闲时高电平
    • CPHA决定数据采样时刻
    • CPHA=0:第一个时钟沿开始采样MSBit
    • CPHA=1:第二个时钟沿开始采样MSBit
  • SPI总线四种工作方式
  • SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设备时钟相位和极性应该一致。如图18-1所示:

图18-1

3.SPI通信指令表

表18.1 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接收数据是否出错,先发送两个字节的伪指令,第四字节仍为伪指令读取错误标志信息。

四、 代码讲解

  • 本实验基于ARM+FPGA构架, ARM首先发送查询ID指令,然后依次通过指令设置写数据的长度、写数据地址、读数据的长度、读数据的地址,然后对比写入数据和读出数据是否一致判断数据是否写入成功,从而实现ARM与FPGA之间基于SPI总线的通信。
  • 1、更改写数据长度、写数据地址、读数据长度、读数据地址参数时,只需在ARM程序中更改初始化值即可。 这里有个地方需要注意:在设置过程中,地址和数据总长度之和不能大于1024,这是由FPGA内部设置的RAM容量决定的。
  • 2、实现ARM与FPGA通信,对FPGA而言,通过模拟SPI时序,实现SPI接收与发送数据,以及数据的串并转换。ARM通过SPI总线发送指令到FPGA,FPGA接受指令后进行解析;然后根据指令需求将相应的数据放到MOSI总线上,等待ARM读取,从而实现两者之间的
  • 数据交互。FPGA实现SPI时序的代码如下:
//--------------------------接收模块----------------------//
reg [3:0]receive_state;
reg [7:0]data_in;
reg [7:0]receive_byte_r;
reg spi_rx_en_r;
//按字节接收SPI发送过来的数据
always@(posedge spi_clk or negedge rst_n or posedge cs_delay)
    begin
        if((!rst_n)||(cs_delay))
        begin
            receive_state <= 4'd0;
            receive_byte_r <= 8'd0;
            spi_rx_en_r <= 1'd0;
        end
        else 
        begin //低时钟时利用提取沿的方式,从高位开始接收数据,每8个spi_clk时钟接收一个Byte
            case(receive_state)  
                4'd0:begin
                    receive_state <= receive_state + 1'd1;
                    data_in <= {data_in[6:0],spi_mosi};
                    spi_rx_en_r <= 1'd0;
                end
                4'd1,4'd2:begin
                    receive_state <= receive_state + 1'd1;
                    data_in <= {data_in[6:0],spi_mosi};
                end
                4'd3:begin
                    receive_state <= receive_state + 1'd1;
                    data_in <= {data_in[6:0],spi_mosi};
                    spi_rx_en_r <= 1'd1;
                end             
                4'd4,4'd5:begin
                    receive_state <= receive_state + 1'd1;
                    data_in <= {data_in[6:0],spi_mosi};
                    spi_rx_en_r <= 1'd0;
                end
                4'd6:begin
                    receive_state <= receive_state + 1'd1;
                    data_in <= {data_in[6:0],spi_mosi};
                end
                4'd7:begin
                    receive_state <= 4'd0;
                    data_in <= {data_in[6:0],spi_mosi};
                    receive_byte_r <= {data_in[6:0],spi_mosi};
                end                     
            endcase
        end
    end
//-----------------------发送模块-------------------------//
reg [3:0]send_state;
reg spi_miso_r;
reg spi_tx_en_r;
reg [7:0]data_out;
 
always@(negedge spi_clk or negedge rst_n or posedge cs_delay)
    if((!rst_n) || (cs_delay))
        begin
            send_state <= 4'd0;
            spi_tx_en_r <= 1'd0;
            data_out <= 8'd0;
        end
    else 
    begin
        case(send_state) 
            4'd0:begin
                spi_miso_r <= data_out[7];
                send_state <= send_state + 1'd1;
            end 
            4'd1:begin
                spi_miso_r <= data_out[6];
                send_state <= send_state + 1'd1;
            end 
            4'd2:begin
                spi_miso_r <= data_out[5];
                send_state <= send_state + 1'd1;
            end 
            4'd3:begin
                spi_miso_r <= data_out[4];
                send_state <= send_state + 1'd1;
            end 
            4'd4:begin
                spi_miso_r <= data_out[3];
                send_state <= send_state + 1'd1;
                spi_tx_en_r <= 1'd0;
            end 
            4'd5:begin
                spi_miso_r <= data_out[2];
                send_state <= send_state+ 1'd1;
                spi_tx_en_r <= 1'd1;
            end
            4'd6:begin
                spi_miso_r <= data_out[1];
                send_state <= send_state + 1'd1;    
                spi_tx_en_r <= 1'd0;      
            end 
            4'd7:begin
                data_out <= send_byte;
                spi_miso_r <= data_out[0];
                send_state <= 4'd0;
                spi_tx_en_r <= 1'd0;
            end
        endcase
    end 

五、 实验步骤及实验结果

图18-2

  1. 将硬件正确连接,如图18-2所示。
  2. 打开putty串口调试工具,打开设备管理器查看对应的端口信息,在putty中打开对应的端口,设置波特率115200,用于打印串口信息;
  3. 将编写好的FPGA代码进行编译,并下载到开发板中;
  4. 将编写好的ARM代码编译,并下载到开发板中,putty工具中会打印相应的SPI通信相关信息;
  5. 观察实验现象及putty终端打印信息——FPGA_LED闪烁,putty终端打印如图18-3所示。

图18-3

六、 拓展实验

  1. 通过仿真观察SPI通信的时序是否和参考时序一致。
  2. 实现错误信息读取的指令功能。
icore4tx_fpga_18.txt · 最后更改: 2022/04/01 11:38 由 sean