spi.v 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. `timescale 1ns / 1ps
  2. //////////////////////////////////////////////////////////////////////////////////
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 21:16:09 07/10/2009
  7. // Design Name:
  8. // Module Name: spi
  9. // Project Name:
  10. // Target Devices:
  11. // Tool versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //////////////////////////////////////////////////////////////////////////////////
  21. module spi(
  22. input clk,
  23. input SCK,
  24. input MOSI,
  25. inout MISO,
  26. input SSEL,
  27. output cmd_ready,
  28. output param_ready,
  29. output [7:0] cmd_data,
  30. output [7:0] param_data,
  31. output endmessage,
  32. output startmessage,
  33. input [7:0] input_data,
  34. output [31:0] byte_cnt,
  35. output [2:0] bit_cnt
  36. );
  37. reg [7:0] cmd_data_r;
  38. reg [7:0] param_data_r;
  39. // sync SCK to the FPGA clock using a 3-bits shift register
  40. reg [2:0] SCKr;
  41. always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
  42. wire SCK_risingedge = (SCKr[1:0]==2'b01); // now we can detect SCK rising edges
  43. wire SCK_fallingedge = (SCKr[1:0]==2'b10); // and falling edges
  44. // same thing for SSEL
  45. reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
  46. wire SSEL_active = ~SSELr[1]; // SSEL is active low
  47. wire SSEL_startmessage = (SSELr[1:0]==2'b10); // message starts at falling edge
  48. wire SSEL_endmessage = (SSELr[1:0]==2'b01); // message stops at rising edge
  49. assign endmessage = SSEL_endmessage;
  50. assign startmessage = SSEL_startmessage;
  51. // and for MOSI
  52. reg [1:0] MOSIr; always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
  53. wire MOSI_data = MOSIr[0];
  54. // bit count for one SPI byte + byte count for the message
  55. reg [2:0] bitcnt;
  56. reg [31:0] byte_cnt_r;
  57. reg byte_received; // high when a byte has been received
  58. reg [7:0] byte_data_received;
  59. assign bit_cnt = bitcnt;
  60. /*
  61. always @(posedge clk)
  62. begin
  63. if(~SSEL_active) begin
  64. bitcnt <= 3'b000;
  65. end
  66. else if(SCK_risingedge) begin
  67. bitcnt <= bitcnt + 3'b001;
  68. // shift received data into the register
  69. byte_data_received <= {byte_data_received[6:0], MOSI_data};
  70. end
  71. end
  72. */
  73. always @(posedge SCK) begin
  74. if(SSEL) bitcnt <= 3'b000;
  75. else begin
  76. bitcnt <= bitcnt + 3'b001;
  77. byte_data_received <= {byte_data_received[6:0], MOSI};
  78. end
  79. if(~SSEL && bitcnt==3'b111) byte_received <= 1'b1;
  80. else byte_received <= 1'b0;
  81. end
  82. //always @(posedge clk)
  83. // byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111);
  84. reg [1:0] byte_received_r;
  85. always @(posedge clk) byte_received_r <= {byte_received_r[0], byte_received};
  86. wire byte_received_sync = (byte_received_r == 2'b01);
  87. always @(posedge clk) begin
  88. if(~SSEL_active)
  89. byte_cnt_r <= 16'h0000;
  90. else if(byte_received_sync) begin
  91. byte_cnt_r <= byte_cnt_r + 16'h0001;
  92. end
  93. end
  94. reg [7:0] byte_data_sent;
  95. /*always @(posedge clk) begin
  96. if(SSEL_active) begin
  97. if(SSEL_startmessage)
  98. byte_data_sent <= 8'h5A; // dummy byte
  99. else
  100. if(SCK_fallingedge) begin
  101. if(bitcnt==3'b000)
  102. byte_data_sent <= input_data; // after that, we send whatever we get
  103. else
  104. byte_data_sent <= {byte_data_sent[6:0], 1'b0};
  105. end
  106. end
  107. end
  108. */
  109. always @(negedge SCK) begin
  110. if(~SSEL) begin
  111. if(bitcnt==3'b000)
  112. byte_data_sent <= input_data;
  113. else
  114. byte_data_sent <= {byte_data_sent[6:0], 1'b0};
  115. end
  116. end
  117. assign MISO = ~SSEL ? input_data[7-bitcnt] /*byte_data_sent[7]*/ : 1'bZ; // send MSB first
  118. reg cmd_ready_r;
  119. reg param_ready_r;
  120. reg cmd_ready_r2;
  121. reg param_ready_r2;
  122. assign cmd_ready = cmd_ready_r;
  123. assign param_ready = param_ready_r;
  124. assign cmd_data = cmd_data_r;
  125. assign param_data = param_data_r;
  126. assign byte_cnt = byte_cnt_r;
  127. always @(posedge clk) cmd_ready_r2 = byte_received_sync && byte_cnt_r == 32'h0;
  128. always @(posedge clk) param_ready_r2 = byte_received_sync && byte_cnt_r > 32'h0;
  129. // fill registers
  130. always @(posedge clk) begin
  131. if (SSEL_startmessage)
  132. cmd_data_r <= 8'h00;
  133. else if(cmd_ready_r2)
  134. cmd_data_r <= byte_data_received;
  135. else if(param_ready_r2)
  136. param_data_r <= byte_data_received;
  137. end
  138. // delay ready signals by one clock (why did I do this again...)
  139. always @(posedge clk) begin
  140. cmd_ready_r <= cmd_ready_r2;
  141. param_ready_r <= param_ready_r2;
  142. end
  143. endmodule