SpiMaster.v 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. //////////////////////////////////////////////////////////////////////////////////
  2. // Company : NPK TAIR
  3. // Engineer : Yuri Donskoy
  4. //
  5. // Create Date (dd/mm/yyyy) :
  6. // Design Name :
  7. // Module Name :
  8. // Project Name :
  9. // Target Devices :
  10. // Tool versions :
  11. // Description :
  12. //
  13. // Dependencies :
  14. //
  15. // Revision : 1.0 - It only send data (no miso port)
  16. // Additional Comments : MISO port need to be add. What about multiple slave select?
  17. //
  18. //////////////////////////////////////////////////////////////////////////////////
  19. module SpiMaster (
  20. clk_i,
  21. rst_i,
  22. data_i,
  23. valid_i,
  24. ready_o,
  25. mosi_o,
  26. sck_o,
  27. ss_o
  28. );
  29. //================================================================================
  30. //
  31. // FUNCTIONS
  32. //
  33. //================================================================================
  34. function integer bit_num;
  35. input integer value;
  36. begin
  37. bit_num = 0;
  38. while (value > 0) begin
  39. value = value >> 1;
  40. bit_num = bit_num + 1;
  41. end
  42. end
  43. endfunction
  44. //================================================================================
  45. //
  46. // PARAMETER/LOCALPARAM
  47. //
  48. //================================================================================
  49. parameter CLK_DIVISOR_POWER = 4; //WAS 2 !! DONT FORGET TO CHANGE!
  50. parameter DATA_WIDTH = 24;
  51. parameter CPOL = 0;
  52. parameter CPHA = 0;
  53. parameter DATA_DIRECTION = "MSBT"; // MSB or LSB
  54. parameter EN_START_DELAY = "NO"; // YES or NO
  55. localparam BIT_CNT_W = bit_num(DATA_WIDTH);
  56. //================================================================================
  57. //
  58. // STATE MACHINE STATES
  59. //
  60. //================================================================================
  61. localparam SM_IDLE_S = 2'b00;
  62. localparam SM_START_S = 2'b01;
  63. localparam SM_DATA_S = 2'b10;
  64. localparam SM_STOP_S = 2'b11;
  65. //================================================================================
  66. //
  67. // PORTS
  68. //
  69. //================================================================================
  70. input clk_i;
  71. input rst_i;
  72. input [DATA_WIDTH-1:0] data_i;
  73. input valid_i;
  74. output ready_o;
  75. output reg mosi_o;
  76. output reg sck_o;
  77. output reg ss_o;
  78. //================================================================================
  79. //
  80. // REG/WIRE
  81. //
  82. //================================================================================
  83. reg [1:0] sm_curr_state;
  84. reg [1:0] sm_next_state;
  85. reg sm_clk_div_en;
  86. // Clock divider outputs
  87. wire clk_divider_redge;
  88. wire clk_divider_fedge;
  89. // Bits counter
  90. reg [BIT_CNT_W-1:0] bit_cnt_r;
  91. reg [BIT_CNT_W-1:0] bit_cnt_next;
  92. // Data buffers
  93. reg [DATA_WIDTH-1:0] tx_buffer_r;
  94. reg [DATA_WIDTH-1:0] tx_buffer_next;
  95. wire [DATA_WIDTH-1:0] tx_buffer_shifted;
  96. wire tx_curr_bit;
  97. // Output data next
  98. reg mosi_next;
  99. reg sck_next;
  100. reg ss_next;
  101. // Edges
  102. wire mosi_shift_edge;
  103. wire ss_start_edge;
  104. wire ss_stop_edge;
  105. wire sck_leading_edge;
  106. wire sck_trailing_edge;
  107. //================================================================================
  108. //
  109. // INTEGER/GENVAR
  110. //
  111. //================================================================================
  112. //================================================================================
  113. //
  114. // ASSIGN
  115. //
  116. //================================================================================
  117. assign mosi_shift_edge = (CPHA[0] == 1'b1) && (EN_START_DELAY != "YES") || (CPHA[0] == 1'b0) && (EN_START_DELAY == "YES") ? clk_divider_fedge : clk_divider_redge;
  118. assign ss_start_edge = (EN_START_DELAY == "YES") ? clk_divider_fedge : clk_divider_redge;
  119. assign ss_stop_edge = (EN_START_DELAY == "YES") ? clk_divider_redge : clk_divider_fedge;
  120. assign sck_leading_edge = (EN_START_DELAY == "YES") ? clk_divider_redge : clk_divider_fedge;
  121. assign sck_trailing_edge = (EN_START_DELAY == "YES") ? clk_divider_fedge : clk_divider_redge;
  122. assign tx_buffer_shifted = (DATA_DIRECTION == "MSB") ? tx_buffer_r << 1 : tx_buffer_r >> 1;
  123. assign tx_curr_bit = (DATA_DIRECTION == "MSB") ? tx_buffer_r[DATA_WIDTH-1] : tx_buffer_r[0];
  124. assign ready_o = sm_curr_state == SM_IDLE_S;
  125. //================================================================================
  126. //
  127. // CODING
  128. //
  129. //================================================================================
  130. // Sequential logic
  131. always @(posedge clk_i or posedge rst_i) begin
  132. if (rst_i) begin
  133. sm_curr_state <= 0;
  134. tx_buffer_r <= {DATA_WIDTH{1'b0}};
  135. bit_cnt_r <= {BIT_CNT_W{1'b0}};
  136. mosi_o <= 1'b0;
  137. sck_o <= CPOL[0];
  138. ss_o <= 1'b1;
  139. end else begin
  140. sm_curr_state <= sm_next_state;
  141. tx_buffer_r <= tx_buffer_next;
  142. bit_cnt_r <= bit_cnt_next;
  143. mosi_o <= mosi_next;
  144. sck_o <= sck_next;
  145. ss_o <= ss_next;
  146. end
  147. end
  148. // Combinational logic
  149. always @(*) begin
  150. sm_next_state = SM_IDLE_S;
  151. tx_buffer_next = tx_buffer_r;
  152. mosi_next = mosi_o;
  153. sck_next = sck_o;
  154. ss_next = ss_o;
  155. sm_clk_div_en = 1'b1;
  156. bit_cnt_next = bit_cnt_r;
  157. case(sm_curr_state)
  158. SM_IDLE_S : begin
  159. if (valid_i) begin
  160. sm_next_state = SM_START_S;
  161. end else begin
  162. sm_next_state = SM_IDLE_S;
  163. end
  164. tx_buffer_next = data_i;
  165. sm_clk_div_en = 1'b0;
  166. bit_cnt_next = {BIT_CNT_W{1'b0}};
  167. end
  168. SM_START_S : begin
  169. if (ss_start_edge) begin
  170. sm_next_state = SM_DATA_S;
  171. ss_next = 1'b0;
  172. if (!CPHA[0]) begin
  173. mosi_next = tx_curr_bit;
  174. tx_buffer_next = tx_buffer_shifted;
  175. bit_cnt_next = bit_cnt_r + {{(BIT_CNT_W-1){1'b0}}, 1'b1};
  176. end
  177. end else begin
  178. sm_next_state = SM_START_S;
  179. end
  180. end
  181. SM_DATA_S : begin
  182. sm_next_state = SM_DATA_S;
  183. if (sck_leading_edge) begin
  184. sck_next = ~CPOL[0];
  185. end
  186. if (sck_trailing_edge) begin
  187. sck_next = CPOL[0];
  188. if (bit_cnt_r == DATA_WIDTH[BIT_CNT_W-1:0]) begin
  189. sm_next_state = SM_STOP_S;
  190. end
  191. end
  192. if (mosi_shift_edge) begin
  193. mosi_next = tx_curr_bit;
  194. tx_buffer_next = tx_buffer_shifted;
  195. bit_cnt_next = bit_cnt_r + {{(BIT_CNT_W-1){1'b0}}, 1'b1};
  196. end
  197. end
  198. SM_STOP_S : begin
  199. if (ss_stop_edge) begin
  200. if (CPHA[0]) begin
  201. mosi_next = tx_curr_bit;
  202. end
  203. sm_next_state = SM_IDLE_S;
  204. ss_next = 1'b1;
  205. end else begin
  206. sm_next_state = SM_STOP_S;
  207. end
  208. end
  209. endcase
  210. end
  211. // Clock divider
  212. Power2ClkDivider #(
  213. .DIVISOR_POWER (CLK_DIVISOR_POWER)
  214. ) ClkDividerInst (
  215. .clk_i (clk_i),
  216. .rst_i (rst_i),
  217. .valid_i (sm_clk_div_en),
  218. .signal_o (),
  219. .rising_edge_o (clk_divider_redge),
  220. .falling_edge_o (clk_divider_fedge)
  221. );
  222. endmodule