zoukankan      html  css  js  c++  java
  • 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
        
    View Code

     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
        
        
    View Code

     测试程序:

        

     
        /********************************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
        
        
      
    View Code

     仿真图:

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

         

  • 相关阅读:
    Python基础闯关失败总结
    fileinput
    squid安装配置
    服务器添加ipa MIME 类型,防止ipa下载后变zip后缀
    单例之懒汉式和饿汉式
    java集合类,详解
    Android 常用动画
    activity和fragment之前运行的生命周期
    Handler 消息传递机制
    startActivityForResult的用法,以及intent传递图片
  • 原文地址:https://www.cnblogs.com/fhyfhy/p/4429302.html
Copyright © 2011-2022 走看看