使用SPI接口读取从机的数据时,主机为啥要发送数据?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用SPI接口读取从机的数据时,主机为啥要发送数据?相关的知识,希望对你有一定的参考价值。

参考技术A 因为读数据也要主机发出时钟,一般的SPI口主机,发送一个数据的时候才会启动时钟,所以要发数据咯。
你如果可以单独启动时钟,就可以不发也能收到了。

spi master接口的fpga实现

前言

当你器件的引脚贼少的时候,需要主机和从机通信,spi就派上了用场,它可以一对多,但只是片选到的从机能和主机通信,其他的挂机。

spi:serial peripheral interface 串行外围接口

大致了解:

技术分享

spi是个同步协议,数据在master和slaver间交换通过时钟sck,由于它是同步协议,时钟速率就可以各种变换。

sck:主机提供,从机不能操控,从器件由主机产生的时钟控制。数据只有在sck来了的上升沿或者下降沿才传输。

高级一点的spi芯片有配置寄存器,高级一点的工作有四种模式,采样相位和sck空闲电平可配置。

当然在这里我们主要实现简单的spi协议:sck是系统时钟的四分频,wr请求信号有效时,主机开始工作,数据位8bit,sck空闲时低电平,工作时第一个沿数据传输。只有一个从机,cs低电平片选。

技术分享

看下结构:

技术分享

接口定义:

技术分享

编码实现:(版权所有,请勿用于商业用途,仅供学习使用)

  1 //************************************************
  2 //  Filename      : spi_ms_test1.v                             
  3 //  Author        : Kingstacker                  
  4 //  Company       : School                       
  5 //  Email         : [email protected]     
  6 //  Device        : Altera cyclone4 ep4ce6f17c8  
  7 //  Description   : spi master module;data 8bit;sck is 4 div of the clk;                              
  8 //************************************************
  9 module  spi_ms #(parameter WIDTH = 8)(
 10     //input;
 11     input    wire    clk, 
 12     input    wire    rst_n,
 13     input    wire    wr, //send request;
 14     input    wire    [WIDTH-1:0]    master_din, //the data you want send;
 15     input    wire    miso, //the data form slave;
 16     //output;
 17     output   reg     cs, //slave select;
 18     output   reg     sck, //data exchange clock;
 19     output   reg     mosi,    //master out;
 20     output   reg     [WIDTH-1:0]    master_dout //the data you received;
 21 );
 22 localparam [2:0] DIV_NUMBER = 4;      //div number,you can change;
 23 localparam       CNT_MAX = (DIV_NUMBER >>1) - 1b1;  //max cnt number,6/2 -1 ;
 24 reg cnt; //sck cnt;
 25 reg sck_en; //enable sck;
 26 reg data_cnt_en;
 27 reg sck_reg1;
 28 reg sck_reg2;
 29 wire sck_p; //posedge sck;
 30 wire sck_n; //negedge sck;
 31 wire send_over;
 32 localparam IDEL = 2b00;
 33 localparam SEND = 2b01;
 34 localparam FINISH = 2b10; 
 35 reg [1:0] cstate;
 36 reg [4:0] data_cnt; //cnt the send data;
 37 reg [7:0] master_din_reg; 
 38 reg [7:0] master_dout_reg;
 39 reg [2:0] mosi_cnt;
 40 //produce sck;
 41 always @(posedge clk or negedge rst_n) begin
 42     if (~rst_n) begin
 43         cnt <= 0;
 44         sck <= 1b0;
 45     end //if
 46     else begin
 47         if (sck_en == 1b1) begin
 48             if (cnt == CNT_MAX) begin
 49                 cnt <= 0;
 50                 sck <= ~sck;
 51             end
 52             else begin
 53                 cnt <= cnt + 1b1;
 54                 sck <= sck;
 55             end
 56         end
 57         else begin
 58             cnt <= 0;
 59             sck <= 1b0;
 60         end
 61     end //else
 62 end //always
 63 //produce sck_p and sck_n;
 64 always @(posedge clk or negedge rst_n) begin
 65     if (~rst_n) begin
 66         sck_reg1 <= 1b0;
 67         sck_reg2 <= 1b0;
 68     end //if
 69     else begin
 70         sck_reg1 <= sck;
 71         sck_reg2 <= sck_reg1;    
 72     end //else
 73 end //always
 74 assign sck_p = (sck_reg1 & (~sck_reg2)); //sck posedge;
 75 assign sck_n = ((~sck_reg1) & sck_reg2); //sck negedge;
 76 //fsm;hot code;
 77 always @(posedge clk or negedge rst_n) begin
 78     if (~rst_n) begin
 79         cstate <= IDEL;
 80     end
 81     else begin
 82         case (cstate)
 83             IDEL:    cstate <= (wr)? SEND : IDEL; 
 84             SEND:    cstate <= (send_over) ? FINISH : SEND; 
 85             FINISH:  cstate <= IDEL;
 86             default: cstate <= IDEL;
 87         endcase //case
 88     end
 89 end
 90 always @(posedge clk or negedge rst_n) begin
 91     if (~rst_n) begin
 92         cs <= 1b1;
 93         data_cnt_en <= 1b0;
 94         sck_en <= 1b0;
 95         master_din_reg <= 0;
 96         master_dout <= 0;
 97     end
 98     else begin
 99         case (cstate)
100             IDEL: begin
101             data_cnt_en <= 1b0;
102             master_din_reg <= (wr) ? master_din : master_din_reg; //load the data you want send to slaver;
103             end 
104             SEND: begin
105                 data_cnt_en <= 1b1;
106                 cs <= 1b0; 
107                 sck_en <= 1b1;
108                 master_dout <= (send_over) ? master_dout_reg : master_dout; //master receiverd data;
109             end
110             FINISH: begin                  //send and load ok;
111                 sck_en <= 1b0;
112                 cs <= 1b1;
113                 data_cnt_en <= 1b0;
114             end
115             default: begin
116                 cs <= 1b1;
117                 sck_en <= 1b0;
118                 data_cnt_en <= 1b0;
119             end
120         endcase //case
121     end
122 end
123 always @(posedge clk or negedge rst_n) begin
124     if (~rst_n) begin
125         data_cnt <= 0;
126     end
127     else begin
128         data_cnt <= (data_cnt_en) ? (data_cnt + 1b1) : 5d0; //4 div * 8bit = 32 cnt;
129     end
130 end
131 assign send_over = (data_cnt == 5d31) ? 1b1 : 1b0;
132 //rising edge miso;
133 always @(posedge clk or negedge rst_n) begin
134     if (~rst_n) begin
135         master_dout_reg <= 0;
136     end
137     else begin
138         master_dout_reg <= (sck_p) ? {master_dout_reg[6:0],miso} : master_dout_reg;
139     end
140 end
141 //miso;
142 always @(posedge clk or negedge rst_n) begin
143     if (~rst_n) begin
144         mosi_cnt <= 0;
145     end
146     else begin
147         if (sck_n) begin
148             if (mosi_cnt == 3d7) begin
149                 mosi_cnt <= 0;
150             end
151             else begin
152                 mosi_cnt <= mosi_cnt + 1b1;
153             end
154         end
155         else begin
156             mosi_cnt <= mosi_cnt;
157         end
158     end
159 end
160 always @(posedge clk or negedge rst_n) begin
161     if (~rst_n) begin
162         mosi <= 1b0;
163     end
164     else begin
165         mosi <= (sck_n) ? master_din_reg[3d7-mosi_cnt] : mosi;
166     end
167 end
168 endmodule

仿真:

技术分享

综合资源使用:

技术分享

 

Fmax:

技术分享

 

以上。

 

以上是关于使用SPI接口读取从机的数据时,主机为啥要发送数据?的主要内容,如果未能解决你的问题,请参考以下文章

单片机的SPI通信怎么用

STC单片机 SPI通讯,主机不能从从机读取正确的数

spi基本概念

spi基本概念

SPI 串行Flash闪存W25Q128FV 的使用(STM32F407)_软件篇

arduino怎么用spi读从机寄存器数据