|
|
@@ -1,273 +0,0 @@
|
|
|
-//////////////////////////////////////////////////////////////////////////////////
|
|
|
-// Company : NPK TAIR
|
|
|
-// Engineer : Yuri Donskoy
|
|
|
-//
|
|
|
-// Create Date (dd/mm/yyyy) :
|
|
|
-// Design Name :
|
|
|
-// Module Name :
|
|
|
-// Project Name :
|
|
|
-// Target Devices :
|
|
|
-// Tool versions :
|
|
|
-// Description :
|
|
|
-//
|
|
|
-// Dependencies :
|
|
|
-//
|
|
|
-// Revision : 1.0 - It only send data (no miso port)
|
|
|
-// Additional Comments : MISO port need to be add. What about multiple slave select?
|
|
|
-//
|
|
|
-//////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-module SpiMaster (
|
|
|
- clk_i,
|
|
|
- rst_i,
|
|
|
-
|
|
|
- data_i,
|
|
|
- valid_i,
|
|
|
- ready_o,
|
|
|
-
|
|
|
- mosi_o,
|
|
|
- sck_o,
|
|
|
- ss_o
|
|
|
-);
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// FUNCTIONS
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
- function integer bit_num;
|
|
|
- input integer value;
|
|
|
- begin
|
|
|
- bit_num = 0;
|
|
|
- while (value > 0) begin
|
|
|
- value = value >> 1;
|
|
|
- bit_num = bit_num + 1;
|
|
|
- end
|
|
|
- end
|
|
|
- endfunction
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// PARAMETER/LOCALPARAM
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
- parameter CLK_DIVISOR_POWER = 4; //WAS 2 !! DONT FORGET TO CHANGE!
|
|
|
- parameter DATA_WIDTH = 24;
|
|
|
- parameter CPOL = 0;
|
|
|
- parameter CPHA = 0;
|
|
|
- parameter DATA_DIRECTION = "MSBT"; // MSB or LSB
|
|
|
- parameter EN_START_DELAY = "NO"; // YES or NO
|
|
|
-
|
|
|
- localparam BIT_CNT_W = bit_num(DATA_WIDTH);
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// STATE MACHINE STATES
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
- localparam SM_IDLE_S = 2'b00;
|
|
|
- localparam SM_START_S = 2'b01;
|
|
|
- localparam SM_DATA_S = 2'b10;
|
|
|
- localparam SM_STOP_S = 2'b11;
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// PORTS
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
- input clk_i;
|
|
|
- input rst_i;
|
|
|
-
|
|
|
- input [DATA_WIDTH-1:0] data_i;
|
|
|
- input valid_i;
|
|
|
- output ready_o;
|
|
|
-
|
|
|
- output reg mosi_o;
|
|
|
- output reg sck_o;
|
|
|
- output reg ss_o;
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// REG/WIRE
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
- reg [1:0] sm_curr_state;
|
|
|
- reg [1:0] sm_next_state;
|
|
|
-
|
|
|
- reg sm_clk_div_en;
|
|
|
-
|
|
|
- // Clock divider outputs
|
|
|
-
|
|
|
- wire clk_divider_redge;
|
|
|
- wire clk_divider_fedge;
|
|
|
-
|
|
|
- // Bits counter
|
|
|
-
|
|
|
- reg [BIT_CNT_W-1:0] bit_cnt_r;
|
|
|
- reg [BIT_CNT_W-1:0] bit_cnt_next;
|
|
|
-
|
|
|
- // Data buffers
|
|
|
-
|
|
|
- reg [DATA_WIDTH-1:0] tx_buffer_r;
|
|
|
- reg [DATA_WIDTH-1:0] tx_buffer_next;
|
|
|
- wire [DATA_WIDTH-1:0] tx_buffer_shifted;
|
|
|
- wire tx_curr_bit;
|
|
|
-
|
|
|
- // Output data next
|
|
|
- reg mosi_next;
|
|
|
- reg sck_next;
|
|
|
- reg ss_next;
|
|
|
-
|
|
|
- // Edges
|
|
|
-
|
|
|
- wire mosi_shift_edge;
|
|
|
-
|
|
|
- wire ss_start_edge;
|
|
|
- wire ss_stop_edge;
|
|
|
-
|
|
|
- wire sck_leading_edge;
|
|
|
- wire sck_trailing_edge;
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// INTEGER/GENVAR
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// ASSIGN
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
- 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;
|
|
|
- assign ss_start_edge = (EN_START_DELAY == "YES") ? clk_divider_fedge : clk_divider_redge;
|
|
|
- assign ss_stop_edge = (EN_START_DELAY == "YES") ? clk_divider_redge : clk_divider_fedge;
|
|
|
- assign sck_leading_edge = (EN_START_DELAY == "YES") ? clk_divider_redge : clk_divider_fedge;
|
|
|
- assign sck_trailing_edge = (EN_START_DELAY == "YES") ? clk_divider_fedge : clk_divider_redge;
|
|
|
- assign tx_buffer_shifted = (DATA_DIRECTION == "MSB") ? tx_buffer_r << 1 : tx_buffer_r >> 1;
|
|
|
- assign tx_curr_bit = (DATA_DIRECTION == "MSB") ? tx_buffer_r[DATA_WIDTH-1] : tx_buffer_r[0];
|
|
|
-
|
|
|
- assign ready_o = sm_curr_state == SM_IDLE_S;
|
|
|
-
|
|
|
-//================================================================================
|
|
|
-//
|
|
|
-// CODING
|
|
|
-//
|
|
|
-//================================================================================
|
|
|
-
|
|
|
-// Sequential logic
|
|
|
-
|
|
|
-always @(posedge clk_i or posedge rst_i) begin
|
|
|
- if (rst_i) begin
|
|
|
- sm_curr_state <= 0;
|
|
|
- tx_buffer_r <= {DATA_WIDTH{1'b0}};
|
|
|
- bit_cnt_r <= {BIT_CNT_W{1'b0}};
|
|
|
- mosi_o <= 1'b0;
|
|
|
- sck_o <= CPOL[0];
|
|
|
- ss_o <= 1'b1;
|
|
|
- end else begin
|
|
|
- sm_curr_state <= sm_next_state;
|
|
|
- tx_buffer_r <= tx_buffer_next;
|
|
|
- bit_cnt_r <= bit_cnt_next;
|
|
|
- mosi_o <= mosi_next;
|
|
|
- sck_o <= sck_next;
|
|
|
- ss_o <= ss_next;
|
|
|
- end
|
|
|
-end
|
|
|
-
|
|
|
-// Combinational logic
|
|
|
-
|
|
|
-always @(*) begin
|
|
|
- sm_next_state = SM_IDLE_S;
|
|
|
- tx_buffer_next = tx_buffer_r;
|
|
|
- mosi_next = mosi_o;
|
|
|
- sck_next = sck_o;
|
|
|
- ss_next = ss_o;
|
|
|
- sm_clk_div_en = 1'b1;
|
|
|
- bit_cnt_next = bit_cnt_r;
|
|
|
-
|
|
|
- case(sm_curr_state)
|
|
|
-
|
|
|
- SM_IDLE_S : begin
|
|
|
- if (valid_i) begin
|
|
|
- sm_next_state = SM_START_S;
|
|
|
- end else begin
|
|
|
- sm_next_state = SM_IDLE_S;
|
|
|
- end
|
|
|
- tx_buffer_next = data_i;
|
|
|
- sm_clk_div_en = 1'b0;
|
|
|
- bit_cnt_next = {BIT_CNT_W{1'b0}};
|
|
|
- end
|
|
|
-
|
|
|
- SM_START_S : begin
|
|
|
- if (ss_start_edge) begin
|
|
|
- sm_next_state = SM_DATA_S;
|
|
|
- ss_next = 1'b0;
|
|
|
- if (!CPHA[0]) begin
|
|
|
- mosi_next = tx_curr_bit;
|
|
|
- tx_buffer_next = tx_buffer_shifted;
|
|
|
- bit_cnt_next = bit_cnt_r + {{(BIT_CNT_W-1){1'b0}}, 1'b1};
|
|
|
- end
|
|
|
- end else begin
|
|
|
- sm_next_state = SM_START_S;
|
|
|
- end
|
|
|
- end
|
|
|
-
|
|
|
- SM_DATA_S : begin
|
|
|
- sm_next_state = SM_DATA_S;
|
|
|
- if (sck_leading_edge) begin
|
|
|
- sck_next = ~CPOL[0];
|
|
|
- end
|
|
|
-
|
|
|
- if (sck_trailing_edge) begin
|
|
|
- sck_next = CPOL[0];
|
|
|
- if (bit_cnt_r == DATA_WIDTH[BIT_CNT_W-1:0]) begin
|
|
|
- sm_next_state = SM_STOP_S;
|
|
|
- end
|
|
|
- end
|
|
|
-
|
|
|
- if (mosi_shift_edge) begin
|
|
|
- mosi_next = tx_curr_bit;
|
|
|
- tx_buffer_next = tx_buffer_shifted;
|
|
|
- bit_cnt_next = bit_cnt_r + {{(BIT_CNT_W-1){1'b0}}, 1'b1};
|
|
|
- end
|
|
|
-
|
|
|
- end
|
|
|
-
|
|
|
- SM_STOP_S : begin
|
|
|
- if (ss_stop_edge) begin
|
|
|
- if (CPHA[0]) begin
|
|
|
- mosi_next = tx_curr_bit;
|
|
|
- end
|
|
|
- sm_next_state = SM_IDLE_S;
|
|
|
- ss_next = 1'b1;
|
|
|
- end else begin
|
|
|
- sm_next_state = SM_STOP_S;
|
|
|
- end
|
|
|
- end
|
|
|
-
|
|
|
- endcase
|
|
|
-end
|
|
|
-
|
|
|
-// Clock divider
|
|
|
-
|
|
|
-Power2ClkDivider #(
|
|
|
- .DIVISOR_POWER (CLK_DIVISOR_POWER)
|
|
|
-) ClkDividerInst (
|
|
|
- .clk_i (clk_i),
|
|
|
- .rst_i (rst_i),
|
|
|
- .valid_i (sm_clk_div_en),
|
|
|
- .signal_o (),
|
|
|
- .rising_edge_o (clk_divider_redge),
|
|
|
- .falling_edge_o (clk_divider_fedge)
|
|
|
-);
|
|
|
-
|
|
|
-endmodule
|