Files
2024-10-28 13:14:49 +08:00

263 lines
6.1 KiB
Verilog

`timescale 1 ns / 1 ps
module ads1299_spi#
(
parameter CLK_PERIOD = 10 ,
parameter CLK_DIV = 3 , // max: 255
parameter DATA_WIDTH = 8 , // max: 255
parameter NO_OF_SLAVES = 1
)
(
input clk ,
input rst_n ,
input [ 8-1:0] t_cs_n ,
input [ DATA_WIDTH-1:0] t_tdata ,
input t_tlast ,
output reg t_tready ,
input t_tvalid ,
output reg [ DATA_WIDTH-1:0] r_tdata ,
output reg r_tlast ,
output reg r_tvalid ,
output [NO_OF_SLAVES-1:0] cs ,
output sclk ,
output mosi ,
input miso
);
//*****************************************************************************
// localparam definition
//*****************************************************************************
localparam CNT_POS = CLK_DIV-1 ;
localparam CNT_NEG = CLK_DIV*2-1 ;
localparam T_SCCS = 2000/CLK_PERIOD ;
localparam T_SCH = 600/CLK_PERIOD ;
localparam IDLE = 4'd0;
localparam TRANS_ST = 4'd1;
localparam SCCS_ST = 4'd2;
localparam CSH_ST = 4'd3;
//*****************************************************************************
// Internal register and wire declarations
//*****************************************************************************
reg [ 4-1:0] cstate ;
reg [ 4-1:0] nstate ;
reg [DATA_WIDTH-1:0] tx_data ;
reg [DATA_WIDTH-1:0] rx_data ;
reg clk_en ;
reg [ 9-1:0] cnt ;
reg sck_pos ;
reg sck_neg ;
reg [ 8-1:0] trans_cnt ;
reg [ 8-1:0] slv_n ;
reg [NO_OF_SLAVES-1:0] cs_r ;
reg sclk_r ;
reg [NO_OF_SLAVES-1:0] cs_release ;
reg [ 8-1:0] t_sccs_cnt ;
reg [ 8-1:0] t_sch_cnt ;
reg read_flag ;
//*****************************************************************************
always@( posedge clk or negedge rst_n ) begin
if( !rst_n ) cstate <= IDLE;
else cstate <= nstate;
end
always@( * ) begin
case ( cstate )
IDLE:
if ( t_tvalid )
nstate <= TRANS_ST;
else
nstate <= IDLE;
TRANS_ST:
if( (trans_cnt == 0) && sck_neg )
nstate <= (cs_release[slv_n])? SCCS_ST : IDLE;
else
nstate <= TRANS_ST;
SCCS_ST:
if ( t_sccs_cnt == T_SCCS - 1 )
nstate <= CSH_ST;
else
nstate <= SCCS_ST;
CSH_ST:
if ( t_sch_cnt == T_SCH - 1 )
nstate <= IDLE;
else
nstate <= CSH_ST;
default:
nstate <= IDLE;
endcase
end
always @ ( posedge clk or negedge rst_n ) begin
if ( !rst_n )
t_tready <= 1'b0;
else if ( nstate == IDLE )
t_tready <= 1'b1;
else if ( cstate == IDLE && nstate == IDLE )
t_tready <= 1'b1;
else
t_tready <= 1'b0;
end
always @ ( posedge clk or negedge rst_n ) begin
if ( !rst_n ) begin
slv_n <= 0;
end else if ( cstate == IDLE || nstate == IDLE ) begin
slv_n <= t_cs_n;
end
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
cs_release <= 1'b0;
else if ( t_tvalid && t_tready && t_tlast )
cs_release[slv_n] <= 1'b1;
else if ( t_tvalid && t_tready )
cs_release[slv_n] <= 1'b0;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
cs_r <= {NO_OF_SLAVES{1'b1}};
else if ( cstate == TRANS_ST )
cs_r[slv_n] <= 1'b0;
else if ( nstate == CSH_ST )
cs_r[slv_n] <= cs_release[slv_n];
end
always @ ( posedge clk or negedge rst_n ) begin
if ( !rst_n ) begin
tx_data <= 0;
end else if ( t_tready && t_tvalid ) begin
tx_data <= t_tdata;
end
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
clk_en <= 0;
else if ( ((cstate == IDLE) && (nstate == TRANS_ST)) || ((cstate == TRANS_ST) && (nstate != SCCS_ST)) )
clk_en <= 1'b1;
else if ( nstate == SCCS_ST || nstate == IDLE )
clk_en <= 1'b0;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt <= 0;
else if ( !clk_en )
cnt <= 0;
else if ( cnt == CLK_DIV*2-1 )
cnt <= 0;
else
cnt <= cnt + 1;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
sck_pos <= 0;
else if ( clk_en && (cnt == CNT_POS) )
sck_pos <= 1;
else
sck_pos <= 0;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
sck_neg <= 0;
else if ( clk_en && (cnt == CNT_NEG) )
sck_neg <= 1;
else
sck_neg <= 0;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
sclk_r <= 0;
else if ( sck_pos && nstate == TRANS_ST )
sclk_r <= 1'b1;
else if ( sck_neg )
sclk_r <= 1'b0;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
trans_cnt <= DATA_WIDTH;
else if ( cstate == IDLE )
trans_cnt <= DATA_WIDTH;
else if ( sck_pos && (trans_cnt != 0) )
trans_cnt <= trans_cnt - 1'b1;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
rx_data <= 0;
else if ( sck_neg )
rx_data[trans_cnt] <= miso;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n )
read_flag <= 1'b0;
else if ( cstate == TRANS_ST && nstate != TRANS_ST )
read_flag <= 1'b1;
else
read_flag <= 1'b0;
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n ) begin
r_tvalid <= 1'b0;
r_tdata <= 0;
r_tlast <= 1'b0;
end else if ( read_flag ) begin
r_tvalid <= 1'b1;
r_tdata <= rx_data;
r_tlast <= cs_release[slv_n];
end else begin
r_tvalid <= 1'b0;
r_tlast <= 1'b0;
end
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n ) begin
t_sccs_cnt <= 0;
end else if ( cstate != SCCS_ST ) begin
t_sccs_cnt <= 0;
end else begin
t_sccs_cnt <= t_sccs_cnt + 1'b1;
end
end
always @ ( posedge clk or negedge rst_n ) begin
if( !rst_n ) begin
t_sch_cnt <= 0;
end else if ( cstate != CSH_ST ) begin
t_sch_cnt <= 0;
end else begin
t_sch_cnt <= t_sch_cnt + 1'b1;
end
end
//*****************************************************************************
// Wire assignment
//*****************************************************************************
assign cs = cs_r;
assign sclk = sclk_r;
assign mosi = (trans_cnt==DATA_WIDTH)? 1'b0:tx_data[trans_cnt];
endmodule