目录

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

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

一、 实验目的与意义

  1. 掌握SPI通信协议及实现方法。
  2. 掌握QuartusII的使用方法。

二、 实验设备及平台

  1. iCore4T 双核心板。
  2. iTool A(或相同功能)仿真器。
  3. USB Type C 线缆。
  4. Keil MDK 开发平台。
  5. Quartus开发平台。
  6. 电脑一台。

三、 实验原理

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

四、 代码讲解

    //Parameter Value
    //注意:地址和长度之和不能大于1024
    write_address = 0;
    write_length = 1024;
    read_address = 0;
    read_length = 1024;
//------------------------------------------------//
////////////////按字节接收SPI发送过来的数据//////////////
///////接收模块///////
reg [3:0]receive_state;
reg [7:0]data_in;
reg [7:0]receive_byte_r;
 
reg spi_rx_en_r;
 
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;
            data_in <= 8'd0;
 
            spi_rx_en_r <= 1'd0;
        end
        else //低时钟时可以利用提取沿的方式
        begin
            case(receive_state)   //从高位开始接收数据,每8个spi_clk时钟接收一个Byte
                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     

五、 实验步骤及实验结果

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

图17.3

六、 拓展实验

  1. 通过Signaltap观察SPI通信的时序是否和参考时序一致。
  2. 实现错误信息读取指令功能。