Projektdaten für das ESY1B Praktikum im Sommersemester 2022
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SPI_Master.sv 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //Source: https://github.com/nandland/spi-master/tree/master/Verilog/source
  3. //Description: SPI (Serial Peripheral Interface) Master
  4. // With single chip-select (AKA Slave Select) capability
  5. //
  6. // Supports arbitrary length byte transfers.
  7. //
  8. // Instantiates a SPI Master and adds single CS.
  9. // If multiple CS signals are needed, will need to use different
  10. // module, OR multiplex the CS from this at a higher level.
  11. //
  12. // Note: i_Clk must be at least 2x faster than i_SPI_Clk
  13. //
  14. // Parameters: SPI_MODE, can be 0, 1, 2, or 3. See above.
  15. // Can be configured in one of 4 modes:
  16. // Mode | Clock Polarity (CPOL/CKP) | Clock Phase (CPHA)
  17. // 0 | 0 | 0
  18. // 1 | 0 | 1
  19. // 2 | 1 | 0
  20. // 3 | 1 | 1
  21. //
  22. // CLKS_PER_HALF_BIT - Sets frequency of o_SPI_Clk. o_SPI_Clk is
  23. // derived from i_Clk. Set to integer number of clocks for each
  24. // half-bit of SPI data. E.g. 100 MHz i_Clk, CLKS_PER_HALF_BIT = 2
  25. // would create o_SPI_CLK of 25 MHz. Must be >= 2
  26. //
  27. // MAX_BYTES_PER_CS - Set to the maximum number of bytes that
  28. // will be sent during a single CS-low pulse.
  29. //
  30. // CS_INACTIVE_CLKS - Sets the amount of time in clock cycles to
  31. // hold the state of Chip-Selct high (inactive) before next
  32. // command is allowed on the line. Useful if chip requires some
  33. // time when CS is high between trasnfers.
  34. ///////////////////////////////////////////////////////////////////////////////
  35. `include "iSPI.sv"
  36. module SPI_Master_With_Single_CS
  37. #(parameter SPI_MODE = 0,
  38. parameter CLKS_PER_HALF_BIT = 2,
  39. parameter MAX_BYTES_PER_CS = 1,
  40. parameter CS_INACTIVE_CLKS = 1)
  41. (
  42. // Control/Data Signals,
  43. input i_Rst_L, // FPGA Reset
  44. input i_Clk, // FPGA Clock
  45. // TX (MOSI) Signals
  46. input [$clog2(MAX_BYTES_PER_CS+1)-1:0] i_TX_Count, // # bytes per CS low
  47. input [7:0] i_TX_Byte, // Byte to transmit on MOSI
  48. input i_TX_DV, // Data Valid Pulse with i_TX_Byte
  49. output o_TX_Ready, // Transmit Ready for next byte
  50. // RX (MISO) Signals
  51. output reg [$clog2(MAX_BYTES_PER_CS+1)-1:0] o_RX_Count, // Index RX byte
  52. output o_RX_DV, // Data Valid pulse (1 clock cycle)
  53. output [7:0] o_RX_Byte, // Byte received on MISO
  54. // SPI Interface
  55. output o_SPI_Clk,
  56. input i_SPI_MISO,
  57. output o_SPI_MOSI,
  58. output o_SPI_CS_n
  59. );
  60. localparam IDLE = 2'b00;
  61. localparam TRANSFER = 2'b01;
  62. localparam CS_INACTIVE = 2'b10;
  63. reg [1:0] r_SM_CS;
  64. reg r_CS_n;
  65. reg [$clog2(CS_INACTIVE_CLKS)-1:0] r_CS_Inactive_Count;
  66. reg [$clog2(MAX_BYTES_PER_CS+1)-1:0] r_TX_Count;
  67. wire w_Master_Ready;
  68. // Instantiate Master
  69. SPI_Master
  70. #(.SPI_MODE(SPI_MODE),
  71. .CLKS_PER_HALF_BIT(CLKS_PER_HALF_BIT)
  72. ) SPI_Master_Inst
  73. (
  74. // Control/Data Signals,
  75. .i_Rst_L(i_Rst_L), // FPGA Reset
  76. .i_Clk(i_Clk), // FPGA Clock
  77. // TX (MOSI) Signals
  78. .i_TX_Byte(i_TX_Byte), // Byte to transmit
  79. .i_TX_DV(i_TX_DV), // Data Valid Pulse
  80. .o_TX_Ready(w_Master_Ready), // Transmit Ready for Byte
  81. // RX (MISO) Signals
  82. .o_RX_DV(o_RX_DV), // Data Valid pulse (1 clock cycle)
  83. .o_RX_Byte(o_RX_Byte), // Byte received on MISO
  84. // SPI Interface
  85. .o_SPI_Clk(o_SPI_Clk),
  86. .i_SPI_MISO(i_SPI_MISO),
  87. .o_SPI_MOSI(o_SPI_MOSI)
  88. );
  89. // Purpose: Control CS line using State Machine
  90. always @(posedge i_Clk or negedge i_Rst_L)
  91. begin
  92. if (~i_Rst_L)
  93. begin
  94. r_SM_CS <= IDLE;
  95. r_CS_n <= 1'b1; // Resets to high
  96. r_TX_Count <= 0;
  97. r_CS_Inactive_Count <= CS_INACTIVE_CLKS;
  98. end
  99. else
  100. begin
  101. case (r_SM_CS)
  102. IDLE:
  103. begin
  104. if (r_CS_n & i_TX_DV) // Start of transmission
  105. begin
  106. r_TX_Count <= i_TX_Count - 1; // Register TX Count
  107. r_CS_n <= 1'b0; // Drive CS low
  108. r_SM_CS <= TRANSFER; // Transfer bytes
  109. end
  110. end
  111. TRANSFER:
  112. begin
  113. // Wait until SPI is done transferring do next thing
  114. if (w_Master_Ready)
  115. begin
  116. if (r_TX_Count > 0)
  117. begin
  118. if (i_TX_DV)
  119. begin
  120. r_TX_Count <= r_TX_Count - 1;
  121. end
  122. end
  123. else
  124. begin
  125. r_CS_n <= 1'b1; // we done, so set CS high
  126. r_CS_Inactive_Count <= CS_INACTIVE_CLKS;
  127. r_SM_CS <= CS_INACTIVE;
  128. end // else: !if(r_TX_Count > 0)
  129. end // if (w_Master_Ready)
  130. end // case: TRANSFER
  131. CS_INACTIVE:
  132. begin
  133. if (r_CS_Inactive_Count > 0)
  134. begin
  135. r_CS_Inactive_Count <= r_CS_Inactive_Count - 1'b1;
  136. end
  137. else
  138. begin
  139. r_SM_CS <= IDLE;
  140. end
  141. end
  142. default:
  143. begin
  144. r_CS_n <= 1'b1; // we done, so set CS high
  145. r_SM_CS <= IDLE;
  146. end
  147. endcase // case (r_SM_CS)
  148. end
  149. end // always @ (posedge i_Clk or negedge i_Rst_L)
  150. // Purpose: Keep track of RX_Count
  151. always @(posedge i_Clk)
  152. begin
  153. begin
  154. if (r_CS_n)
  155. begin
  156. o_RX_Count <= 0;
  157. end
  158. else if (o_RX_DV)
  159. begin
  160. o_RX_Count <= o_RX_Count + 1'b1;
  161. end
  162. end
  163. end
  164. assign o_SPI_CS_n = r_CS_n;
  165. assign o_TX_Ready = ((r_SM_CS == IDLE) | (r_SM_CS == TRANSFER && w_Master_Ready == 1'b1 && r_TX_Count > 0)) & ~i_TX_DV;
  166. endmodule // SPI_Master_With_Single_CS