eric2013 发表于 2020-3-9 10:01:38

Verilog SPI Master和Slave

https://alchitry.com/blogs/tutorials/serial-peripheral-interface-spi



slave

module spi_slave(
    input clk,
    input rst,
    input ss,
    input mosi,
    output miso,
    input sck,
    output done,
    input din,
    output dout
);

reg mosi_d, mosi_q;
reg ss_d, ss_q;
reg sck_d, sck_q;
reg sck_old_d, sck_old_q;
reg data_d, data_q;
reg done_d, done_q;
reg bit_ct_d, bit_ct_q;
reg dout_d, dout_q;
reg miso_d, miso_q;

assign miso = miso_q;
assign done = done_q;
assign dout = dout_q;

always @(*) begin
    ss_d = ss;
    mosi_d = mosi;
    miso_d = miso_q;
    sck_d = sck;
    sck_old_d = sck_q;
    data_d = data_q;
    done_d = 1'b0;
    bit_ct_d = bit_ct_q;
    dout_d = dout_q;

    if (ss_q) begin                           // if slave select is high (deselcted)
      bit_ct_d = 3'b0;                        // reset bit counter
      data_d = din;                           // read in data
      miso_d = data_q;                     // output MSB
    end else begin                            // else slave select is low (selected)
      if (!sck_old_q && sck_q) begin          // rising edge
      data_d = {data_q, mosi_q};       // read data in and shift
      bit_ct_d = bit_ct_q + 1'b1;         // increment the bit counter
      if (bit_ct_q == 3'b111) begin         // if we are on the last bit
          dout_d = {data_q, mosi_q};   // output the byte
          done_d = 1'b1;                      // set transfer done flag
          data_d = din;                     // read in new byte
      end
      end else if (sck_old_q && !sck_q) begin // falling edge
      miso_d = data_q;                   // output MSB
      end
    end
end

always @(posedge clk) begin
    if (rst) begin
      done_q <= 1'b0;
      bit_ct_q <= 3'b0;
      dout_q <= 8'b0;
      miso_q <= 1'b1;
    end else begin
      done_q <= done_d;
      bit_ct_q <= bit_ct_d;
      dout_q <= dout_d;
      miso_q <= miso_d;
    end

    sck_q <= sck_d;
    mosi_q <= mosi_d;
    ss_q <= ss_d;
    data_q <= data_d;
    sck_old_q <= sck_old_d;

end

endmodule

Master

module spi #(parameter CLK_DIV = 2)(
    input clk,
    input rst,
    input miso,
    output mosi,
    output sck,
    input start,
    input data_in,
    output data_out,
    output busy,
    output new_data
);

localparam STATE_SIZE = 2;
localparam IDLE = 2'd0,
    WAIT_HALF = 2'd1,
    TRANSFER = 2'd2;

reg state_d, state_q;

reg data_d, data_q;
reg sck_d, sck_q;
reg mosi_d, mosi_q;
reg ctr_d, ctr_q;
reg new_data_d, new_data_q;
reg data_out_d, data_out_q;

assign mosi = mosi_q;
assign sck = (~sck_q) & (state_q == TRANSFER);
assign busy = state_q != IDLE;
assign data_out = data_out_q;
assign new_data = new_data_q;

always @(*) begin
    sck_d = sck_q;
    data_d = data_q;
    mosi_d = mosi_q;
    ctr_d = ctr_q;
    new_data_d = 1'b0;
    data_out_d = data_out_q;
    state_d = state_q;

    case (state_q)
      IDLE: begin
      sck_d = 4'b0;            // reset clock counter
      ctr_d = 3'b0;            // reset bit counter
      if (start == 1'b1) begin   // if start command
          data_d = data_in;      // copy data to send
          state_d = WAIT_HALF;   // change state
      end
      end
      WAIT_HALF: begin
      sck_d = sck_q + 1'b1;                  // increment clock counter
      if (sck_q == {CLK_DIV-1{1'b1}}) begin// if clock is half full (about to fall)
          sck_d = 1'b0;                        // reset to 0
          state_d = TRANSFER;                  // change state
      end
      end
      TRANSFER: begin
      sck_d = sck_q + 1'b1;                           // increment clock counter
      if (sck_q == 4'b0000) begin                     // if clock counter is 0
          mosi_d = data_q;                           // output the MSB of data
      end else if (sck_q == {CLK_DIV-1{1'b1}}) begin// else if it's half full (about to fall)
          data_d = {data_q, miso};               // read in data (shift in)
      end else if (sck_q == {CLK_DIV{1'b1}}) begin    // else if it's full (about to rise)
          ctr_d = ctr_q + 1'b1;                         // increment bit counter
          if (ctr_q == 3'b111) begin                  // if we are on the last bit
            state_d = IDLE;                           // change state
            data_out_d = data_q;                        // output data
            new_data_d = 1'b1;                        // signal data is valid
          end
      end
      end
    endcase
end

always @(posedge clk) begin
    if (rst) begin
      ctr_q <= 3'b0;
      data_q <= 8'b0;
      sck_q <= 4'b0;
      mosi_q <= 1'b0;
      state_q <= IDLE;
      data_out_q <= 8'b0;
      new_data_q <= 1'b0;
    end else begin
      ctr_q <= ctr_d;
      data_q <= data_d;
      sck_q <= sck_d;
      mosi_q <= mosi_d;
      state_q <= state_d;
      data_out_q <= data_out_d;
      new_data_q <= new_data_d;
    end
end

endmodule

fengxin32 发表于 2021-1-11 22:54:24

:lol✌,太好了,我正在发愁CPLD上的SPI呢!
页: [1]
查看完整版本: Verilog SPI Master和Slave