SPI通信实验---verilog(FPGA作为从机,使用可读可写)

本实验讲究实用性,故设计思想为:主机先向从机发送地址,若是向从机写入数据,则向从机发送数据,若是读取从机数据,则向从机发送时钟,然后在时钟下降沿读取数据即可。cs信号上升沿作为SPI通信的结束信号。rom程序只是做测试使用。

每次发送16个时钟信号,前八个是地址和命令,后八个是数据。其中:前8个时钟接受的数据的最高位决定着这次通信是读取数据还是写入数据,最高位为1,则是读取数据,为0则是写入数据。

程序:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name  :spi_slave_2.v
** CreateDate :2015.004
** Funtions   :spi通信试验。FPGA作为从机,与主机进行通信。先接收主机发来的地址,再根据地址最高位来判断是读数据还是些数据,
               然后从机是接收数据还是送出数据。地址最高位为高则是读取数据,否则为写数据.上升沿接收数据,下降沿发送数据
** Operate on :M5C06N3L114C7
** Copyright  :All rights reserved.
** Version    :V1.0
**---------------------------Modify the file information----------------
** Modified by   :
** Modified data :
** Modify Content:
*******************************************************************************/
  module  spi_slave_2  (
                                 clk,
                                 rst_n,

                                 spi_cs,
                                 spi_sck,
                                 spi_miso,
                                 spi_mosi,

                                 spi_over

                  );
     input          clk;
     input          rst_n;

     input          spi_cs;
     input          spi_sck;
     input          spi_mosi;

     output   reg      spi_miso;
     output         spi_over;

     //-----------------------------//
     reg        spi_cs_2,spi_cs_1;
     reg        spi_sck_2,spi_sck_1;
     reg        spi_mosi_2,spi_mosi_1;
     wire       spi_cs_pos;
     wire       spi_cs_flag;
     wire       spi_sck_neg;
     wire       spi_sck_pos;
     wire       spi_mosi_flag;
     always @(posedge clk or negedge rst_n)
     begin
      if(!rst_n)
       begin
        {spi_cs_2,spi_cs_1} <= 2‘b11;
        {spi_sck_2,spi_sck_1} <= 2‘b00;
            {spi_mosi_2,spi_mosi_1} <= 2‘b00;
         end
      else
        begin
         {spi_cs_2,spi_cs_1} <= {spi_cs_1,spi_cs};
         {spi_sck_2,spi_sck_1} <= {spi_sck_1,spi_sck};
             {spi_mosi_2,spi_mosi_1} <= {spi_mosi_1,spi_mosi};
        end
      end

        assign spi_cs_pos = ~spi_cs_2 &spi_cs_1;
        assign spi_cs_flag = spi_cs_2;
        assign spi_sck_neg = ~spi_sck_1&spi_sck_2;
        assign spi_sck_pos = ~spi_sck_2&spi_sck_1;
        assign spi_mosi_flag = spi_mosi_2;

        assign spi_over = spi_cs_pos;
    //----------------------------------------//
     localparam idel       = 4‘d0;
     localparam rxd_addr   = 4‘d1;
     localparam jude_wr_rd = 4‘d2;
     localparam rxd_data   = 4‘d3;
     localparam rxd_over   = 4‘d4;
     localparam txd_data   = 4‘d5;
     localparam txd_over   = 4‘d6;
     localparam end_sta    = 4‘d7;

     reg    [3:0]     state;
     reg    [3:0]     cnt;
     reg    [7:0]     raddr;
     reg    [7:0]     rdata;
     reg    [7:0]     tdata;
     reg              rover_flag;
     reg              wover_flag;
     reg              rd_flag;
     wire  [7:0]      data_out;
     always @(posedge clk or negedge rst_n)
     begin
      if(!rst_n)
       begin
          state <= 4‘d0;
                cnt <= 0;
                raddr <= 8‘d0;
                rdata <= 8‘d0;
                tdata <= 8‘d0;
                rover_flag <= 0;
                wover_flag <= 0;
                rd_flag <= 0;
                spi_miso <= 1;
        end
      else if(!spi_cs_flag)
        begin
          case(state)
                 idel:
                   begin
                            state <= rxd_addr;
                            cnt <= 0;
                            raddr <= 8‘d0;
                            rdata <= 8‘d0;
                            tdata <= 8‘d0;
                            rover_flag <= 0;
                      wover_flag <= 0;
                            rd_flag <= 0;
                            spi_miso <= 1;
                         end
                    rxd_addr:
                      begin
                            if(cnt == 8)
                             begin
                               cnt <= 0;
                               state <= jude_wr_rd;
                                end
                            else if(spi_sck_pos)
                                begin
                                    cnt <= cnt + 1;
                                    raddr[7 - cnt[2:0]] <= spi_mosi_flag;
                                end
                         end
                jude_wr_rd:
                   begin
                            if(raddr[7] == 1)
                               state <= rxd_data;
                            else
                                 begin
                                   state <= txd_data;
                                     rd_flag <= 1;
                                    end
                         end
            rxd_data:
                begin
                        if(cnt == 8)
                             begin
                               cnt <= 0;
                               state <= rxd_over;
                                end
                         else if(spi_sck_pos)
                                begin
                                    cnt <= cnt + 1;
                                    rdata[7 - cnt[2:0]] <= spi_mosi_flag;
                                end
                     end
            rxd_over:
              begin
                     rover_flag <= 1;
                     state <= end_sta;
                    end
            txd_data:
              begin
                    tdata <= data_out;
                    if(cnt == 8)
                         begin
                              cnt <= 0;
                              state <= txd_over;
                            end
                    else if(spi_sck_pos)
                        begin
                                cnt <= cnt + 1;
                                spi_miso <= tdata[7 - cnt[2:0]];
                            end
                 end
            txd_over:
              begin
                    wover_flag <= 1;
                     state <= end_sta;
                    end
            end_sta:
               begin
                     rover_flag <= 0;
                     wover_flag <= 0;
                     state <= end_sta;
                 end
            default:state <= 4‘d0;
         endcase
     end
    else
            begin
            state <= 4‘d0;
                cnt <= 0;
                raddr <= 8‘d0;
                rdata <= 8‘d0;
                tdata <= 8‘d0;
                rover_flag <= 0;
                wover_flag <= 0;
                rd_flag <= 0;
                spi_miso <= 1;
            end
 end

    data_rom  data_rom_1 (
                                 .clk(clk),
                                 .rst_n(rst_n),

                                 .wr(rover_flag),
                                 .rd(rd_flag),

                                 .addr(raddr[6:0]),
                                 .data_in(rdata),
                                 .data_out(data_out)
                                     );
    endmodule
    

ROM:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name  :data_rom.v
** CreateDate :2015.04
** Funtions   : 简单的数据读写存储程序,配合测试
** Operate on :M5C06N3L114C7
** Copyright  :All rights reserved.
** Version    :V1.0
**---------------------------Modify the file information----------------
** Modified by   :
** Modified data :
** Modify Content:
*******************************************************************************/
  module  data_rom  (
               clk,
               rst_n,

                         wr,
                         rd,

                         addr,
                         data_in,
                         data_out
                 );
     input          clk;
     input          rst_n;

     input          wr;
     input          rd;
     input  [6:0]   addr;
     input  [7:0]   data_in;

     output reg [7:0]   data_out;

     reg  [7:0]  table_1   [7:0];
     wire [7:0]  table_2   [7:0];
     always @(posedge clk or negedge rst_n)
     begin
      if(!rst_n)
       begin
          table_1[7] <= 0;
                table_1[6] <= 0;
                table_1[5] <= 0;
                table_1[4] <= 0;
                table_1[3] <= 0;
                table_1[2] <= 0;
                table_1[1] <= 0;
                table_1[0] <= 0;
                data_out <= 0;
        end
      else if(wr)
        begin
          table_1[addr] <= data_in;
        end
        else if(rd)
           data_out <= table_1[addr];
        else
            begin
          table_1[7] <= table_1[7];
                table_1[6] <= table_1[6];
                table_1[5] <= table_1[5];
                table_1[4] <= table_1[4];
                table_1[3] <= table_1[3];
                table_1[2] <= table_1[2];
                table_1[1] <= table_1[1];
                table_1[0] <= table_1[0];
                data_out <= data_out;
        end
      end

    assign table_2[7] = table_1[7];
    assign table_2[6] = table_1[6];
    assign table_2[5] = table_1[5];
    assign table_2[4] = table_1[4];
    assign table_2[3] = table_1[3];
    assign table_2[2] = table_1[2];
    assign table_2[1] = table_1[1];
    assign table_2[0] = table_1[0];    

    endmodule

测试程序:

    /********************************Copyright**************************************
    **----------------------------File information--------------------------
    ** File name  :spi_slave_tb.v
    ** CreateDate :2015.04
    ** Funtions   :测试文件
    ** Operate on :M5C06N3L114C7
    ** Copyright  :All rights reserved.
    ** Version    :V1.0
    **---------------------------Modify the file information----------------
    ** Modified by   :
    ** Modified data :
    ** Modify Content:
    *******************************************************************************/

    `timescale 1 ns/1 ns

    module  spi_slave_tb ;
       reg          clk;
         reg          rst_n;

         reg           spi_cs;
         reg           spi_sck;
         wire          spi_miso;
         reg           spi_mosi;

         wire          spi_over;

    spi_slave_2  spi_slave_2_1(
                                 .clk,
                                 .rst_n,

                                 .spi_cs,
                                 .spi_sck,
                                 .spi_miso,
                                 .spi_mosi,

                                 .spi_over
                                     );

     parameter tck = 24;
     parameter t = 1000/tck;

     always
       #(t/2) clk = ~clk;

     //-------------------------------
  /* 模仿spi主机的发送程序,这个task很好,仿顺序操作,可以直观的显示过程 */
    task  spi_sd;
    input [7:0]  data_in;
    begin
    #(5*t);

        spi_sck = 0; spi_mosi= data_in[7]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[7]
        spi_sck = 0; spi_mosi= data_in[6]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[6]
        spi_sck = 0; spi_mosi= data_in[5]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[5]
        spi_sck = 0; spi_mosi= data_in[4]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[4]
        spi_sck = 0; spi_mosi= data_in[3]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[3]
        spi_sck = 0; spi_mosi= data_in[2]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[2]
        spi_sck = 0; spi_mosi= data_in[1]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[1]
        spi_sck = 0; spi_mosi= data_in[0]; #(5*t);    spi_sck = 1; #(5*t);    //send bit[0]
      spi_sck = 0;

        end
    endtask

    initial
      begin
       clk = 0;
         rst_n = 0;
         spi_cs = 1;
         spi_sck = 0;
       spi_mosi = 1;

         #(20*t) rst_n = 1;
         #(10*t);
          spi_cs = 0;
          spi_sd(8‘h81);
          #(50*t);
          spi_sd(8‘h04);
            #(50*t);
             #(50*t);
          spi_cs = 1;

            #(20*t);
          spi_cs = 0;
           spi_sd(8‘h01);
            #(50*t);
           spi_sd(8‘h00);
          #(50*t);
          spi_cs = 1;
      end

    endmodule

仿真图:

图中可以看出,第一次输入8‘h81,意味着向01的地址写入数据。第二个数8’h04,则是要写入的数据。然后写入数据8‘h01,则意味着要读取01地址的数据,然后发送8个时钟则是再读取数据。

时间: 2024-07-31 05:10:14

SPI通信实验---verilog(FPGA作为从机,使用可读可写)的相关文章

【iCore3 双核心板_FPGA】实验十六:SPI通信实验

实验指导书及代码包下载: http://pan.baidu.com/s/1hs6lDdi iCore3 购买链接: https://item.taobao.com/item.htm?id=524229438677

STM32与FPGA进行SPI通信

一.器件 32单片机:STM32F407ZG FPGA     :EP4CE6E22C8N 二.通信方式 STM32作为主机(软件); FPGA作为从机; SPI通信方式为0; 三.STM32源代码 1 #include "delay.h" 2 #include "stm32f4xx.h" 3 4 #ifndef __SPI_H 5 #define __SPI_H 6 7 #define SPI1_SCK PBout(2) 8 #define SPI1_MOSI P

SPI通信

SPI是由Motorola公司提出的一种同步串行外围接口:它在速度要求不高,低功耗,需要保存少量参数的智能化传感系统中得到了广泛应用: SPI是一个全双工的同步串行接口,在数据传输过程中,总线上只能是一个主机和一个从机进行通信: 通信四种模式: 1.MISO(Master In Slave Out) 主机输入,从机输出: 2.MOSI(Master  Out  Slave In) 主机输出,从机输入: 3.SCK(Serial  Clock) 串行时钟信号 4.SS(Slave  Select)

ANT无线通信技术(5) ANT与MCU的SPI通信时序分析及相关程序设计

ANT与MCU可以使用异步UART或同步SPI两种方式连接.异步通信与同步通信的各自特点这里不赘述,总之我们选择使用同步方式进行连接. 一.SPI简介 SPI(Serial Peripheral Interface),串行外设接口.是摩托罗拉公司开发的一种同步全双工通信协议.依靠收发两端的移位寄存器,以及主机master提供的时钟信号,双方可以实现较高速率的同步全双工传输. 标准的SPI是3/4根线,分别用于一主一从/多主从的情况.4根线分别是: MOSI 主机发,从机收 master out

[转]SPI通信原理简介

[转自]http://www.cnblogs.com/deng-tao/p/6004280.html 1.前言 SPI是串行外设接口(Serial Peripheral Interface)的缩写.是 Motorola 公司推出的一 种同步串行接口技术,是一种高速的,全双工,同步的通信总线. 2. SPI特点 高速.同步.非差分.总线式.支持全双工通信 主从式通信 通信协议简单 可靠性有缺陷.没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据,可靠性上有一定的缺陷.

STM32 SPI 通信

SPI  是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口.是 Motorola首先在其 MC68HCXX 系列处理器上定义的. SPI 接口主要应用在  EEPROM, FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信

IDC通信实验

[背景]模拟下IDC机房通信流程,其实就是根据自己的想法来做的实验,有不对之处,请指正! 在这里我们假设有两种流量,应用与管理流量,我们想让其管理流量与应用流量分开,但以下实验并没有完全将应用流量与管理流量分开,因我们有内网的应用如DB,那么,我们应该使用其管理口来使流量分开,此次实验没有做,而且内网还可以再细化,如不同部门应用服务器不同,他们之间应该也需要做相应的限制,而且网段过大的话,也会造成广播风暴,还会因arp攻击造成全局的问题,所以后期,我还会做上相应的vlan划分,并且此处没有做Ha

SPI 通信

信号组成 链接线 SPI通信过程 主从模式设置 相位和级性 传输格式 设置步骤 发送和接收过程 SPI 通信,布布扣,bubuko.com

51单片机学习笔记【六】——串口通信实验

一.串口通信基础 1.串行通信 串行通信将数据字节分成一位一位的形式在一条传输线上逐个传送.单片机采用串行通信.特点是:传输线少,长距离传送成本低,但数据传送控制复杂. 串行通信的传输的传输方向:单工(数据传输只能沿一个方向),办双工(传输数据和接受数据分布进行),全双工(传输和接受同步进行). 单片机采用异步通信,发送和接受设备使用各自的时钟频率,容易实现,但传输效率不高,数据格式 2.MAX232 实验通过MAX232电平转换芯片,可把计算机串口电平(-12V~+12V)转换为单片及TTL电