SimpleSPI.v 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. module SimpleSPI
  2. #(parameter CLKS_PER_HALF_BIT = 1)
  3. (
  4. // Control/Data Signals,
  5. input reset,
  6. input clk,
  7. // TX (MOSI) Signals
  8. input [7:0] in_byte,
  9. input start,
  10. // RX (MISO) Signals
  11. output done,
  12. output reg [7:0] out_byte = 8'd0,
  13. // SPI Interface
  14. output reg spi_clk = 1'b0,
  15. input miso,
  16. output mosi
  17. );
  18. reg o_SPI_MOSI = 1'b0;
  19. reg [$clog2(CLKS_PER_HALF_BIT*2)-1:0] r_SPI_clk_Count = 0;
  20. reg r_SPI_clk = 1'b0;
  21. reg [4:0] r_SPI_clk_Edges = 1'b0;
  22. reg r_Leading_Edge = 1'b0;
  23. reg r_Trailing_Edge = 1'b0;
  24. reg r_TX_DV = 1'b0;
  25. reg [7:0] r_TX_Byte = 1'b0;
  26. reg [2:0] r_RX_Bit_Count = 1'b0;
  27. reg [2:0] r_TX_Bit_Count = 1'b0;
  28. reg o_TX_Ready = 1'b0;
  29. assign mosi = (o_TX_Ready) ? 1'bz : o_SPI_MOSI;
  30. assign done = o_TX_Ready;
  31. // Purpose: Generate SPI Clock correct number of times when DV pulse comes
  32. always @(posedge clk)
  33. begin
  34. if (reset)
  35. begin
  36. o_TX_Ready <= 1'b0;
  37. r_SPI_clk_Edges <= 1'b0;
  38. r_Leading_Edge <= 1'b0;
  39. r_Trailing_Edge <= 1'b0;
  40. r_SPI_clk <= 1'b0; // assign default state to idle state
  41. r_SPI_clk_Count <= 1'b0;
  42. r_TX_Byte <= 8'h00;
  43. r_TX_DV <= 1'b0;
  44. end
  45. else
  46. begin
  47. // Default assignments
  48. r_Leading_Edge <= 1'b0;
  49. r_Trailing_Edge <= 1'b0;
  50. r_TX_DV <= start;
  51. if (r_SPI_clk_Edges == 0)
  52. begin
  53. if (start)
  54. begin
  55. r_TX_Byte <= in_byte;
  56. o_TX_Ready <= 1'b0;
  57. r_SPI_clk_Edges <= 16; // Total # edges in one byte ALWAYS 16
  58. end
  59. else
  60. begin
  61. o_TX_Ready <= 1'b1;
  62. end
  63. end
  64. else
  65. begin
  66. o_TX_Ready <= 1'b0;
  67. if (r_SPI_clk_Count == CLKS_PER_HALF_BIT*2-1)
  68. begin
  69. r_SPI_clk_Edges <= r_SPI_clk_Edges - 1'b1;
  70. r_Trailing_Edge <= 1'b1;
  71. r_SPI_clk_Count <= 0;
  72. r_SPI_clk <= ~r_SPI_clk;
  73. end
  74. else if (r_SPI_clk_Count == CLKS_PER_HALF_BIT-1)
  75. begin
  76. r_SPI_clk_Edges <= r_SPI_clk_Edges - 1'b1;
  77. r_Leading_Edge <= 1'b1;
  78. r_SPI_clk_Count <= r_SPI_clk_Count + 1'b1;
  79. r_SPI_clk <= ~r_SPI_clk;
  80. end
  81. else
  82. begin
  83. r_SPI_clk_Count <= r_SPI_clk_Count + 1'b1;
  84. end
  85. end
  86. end // else: !if(reset)
  87. end // always @ (posedge clk)
  88. // Purpose: Generate MOSI data
  89. // Works with both CPHA=0 and CPHA=1
  90. always @(posedge clk)
  91. begin
  92. if (reset)
  93. begin
  94. o_SPI_MOSI <= 1'b0;
  95. r_TX_Bit_Count <= 3'b111; // send MSb first
  96. end
  97. else
  98. begin
  99. // If ready is high, reset bit counts to default
  100. if (o_TX_Ready)
  101. begin
  102. r_TX_Bit_Count <= 3'b111;
  103. end
  104. // Catch the case where we start transaction and CPHA = 0
  105. else if (r_SPI_clk_Edges == 5'd16)
  106. begin
  107. o_SPI_MOSI <= r_TX_Byte[7];
  108. r_TX_Bit_Count <= 3'b110;
  109. end
  110. else
  111. if (r_Trailing_Edge)
  112. begin
  113. r_TX_Bit_Count <= r_TX_Bit_Count - 1'b1;
  114. o_SPI_MOSI <= r_TX_Byte[r_TX_Bit_Count];
  115. end
  116. end
  117. end
  118. // Purpose: Read in MISO data.
  119. always @(posedge clk)
  120. begin
  121. if (reset)
  122. begin
  123. out_byte <= 8'h00;
  124. r_RX_Bit_Count <= 3'b111;
  125. end
  126. else
  127. begin
  128. if (o_TX_Ready) // Check if ready is high, if so reset bit count to default
  129. begin
  130. r_RX_Bit_Count <= 3'b111;
  131. end
  132. else if (r_Leading_Edge)
  133. begin
  134. out_byte[r_RX_Bit_Count] <= miso; // Sample data
  135. r_RX_Bit_Count <= r_RX_Bit_Count - 1'b1;
  136. end
  137. end
  138. end
  139. // Purpose: Add clock delay to signals for alignment.
  140. always @(posedge clk)
  141. begin
  142. if (reset)
  143. begin
  144. spi_clk <= 1'd0;
  145. end
  146. else
  147. begin
  148. spi_clk <= r_SPI_clk;
  149. end // else: !if(reset)
  150. end // always @ (posedge clk)
  151. endmodule // SPI_Master