blob: 6caa57ccc3872d37004cbac43d577e83d028bbd6 [file] [log] [blame]
`timescale 1 ns / 1 ns
module bfm_ws281x #(
parameter PORT_ID = 0,
parameter MODE = 0) (
input logic reset_n,
input logic clk,
input logic enb,
input logic rxd
);
//---------------------------------------------------
// Parameter decleration
//---------------------------------------------------
parameter WS2811_LS = 0;
parameter WS2811_HS = 1;
parameter WS2812_HS = 2;
parameter WS2812S_HS = 3;
parameter WS2812B_HS = 4;
parameter WS281X_LS_PERIOD = 2500 ; // 400Khz - 2.5us
parameter WS281X_HS_PERIOD = 1250 ; // 800Khz - 1.25us
parameter WS2811_LS_TOH = 500 ;// 0.5us - 500ns
parameter WS2811_LS_T1H = 1200 ;// 1.2us - 1200ns
parameter WS2811_HS_TOH = 250 ;// 0.25us - 250ns
parameter WS2811_HS_T1H = 600 ;// 0.6us - 600ns
parameter WS2812_HS_TOH = 350 ;// 0.35us - 350ns
parameter WS2812_HS_T1H = 700 ;// 0.7us - 700ns
parameter WS2812S_HS_TOH = 350 ;// 0.35us - 350ns
parameter WS2812S_HS_T1H = 700 ;// 0.7us - 700ns
parameter WS2812B_HS_TOH = 350 ;// 0.35us - 350ns
parameter WS2812B_HS_T1H = 900 ;// 0.9us - 900ns
parameter WS281X_TOLERENCE = 150 ; // 150ns
parameter WS281X_RST = 50000 ;// 50us - 50000ns
parameter WS281X_PERIOD = (MODE == WS2811_LS) ? WS281X_LS_PERIOD :
(MODE == WS2811_HS) ? WS281X_HS_PERIOD :
(MODE == WS2812_HS) ? WS281X_HS_PERIOD :
(MODE == WS2812S_HS) ? WS281X_HS_PERIOD :
(MODE == WS2812B_HS) ? WS281X_HS_PERIOD : WS281X_LS_PERIOD;
parameter WS281X_TOH = (MODE == WS2811_LS) ? WS2811_LS_TOH :
(MODE == WS2811_HS) ? WS2811_HS_TOH :
(MODE == WS2812_HS) ? WS2812S_HS_TOH :
(MODE == WS2812S_HS) ? WS2812S_HS_TOH :
(MODE == WS2812B_HS) ? WS2812B_HS_TOH : WS2811_LS_TOH;
parameter WS281X_T1H = (MODE == WS2811_LS) ? WS2811_LS_T1H :
(MODE == WS2811_HS) ? WS2811_HS_T1H :
(MODE == WS2812_HS) ? WS2812S_HS_T1H :
(MODE == WS2812S_HS) ? WS2812S_HS_T1H :
(MODE == WS2812B_HS) ? WS2812B_HS_T1H : WS2811_LS_T1H;
//---------------------------------------------------------
// FSM State
//---------------------------------------------------------
parameter STATE_RESET = 3'b000;
parameter STATE_WAIT_POS_EDGE = 3'b001;
parameter STATE_WAIT_NEG_EDGE = 3'b010;
parameter STATE_DATA0_LOW = 3'b011;
parameter STATE_DATA1_LOW = 3'b100;
//---------------------------------------------------
// Variable decleration
//---------------------------------------------------
logic [15:0] rx_wcnt ;
logic [15:0] clk_cnt ;
logic [7:0] bit_cnt ;
logic [15:0] check_sum ;
logic [23:0] led_data ;
time neg_edge_time ;
time pos_edge_time ;
time time_ref ;
logic [2:0] state ;
always @(negedge rxd) begin
neg_edge_time = $time;
end
always @(posedge rxd) begin
pos_edge_time = $time;
end
always @ (posedge clk) begin
if(reset_n == 0) begin
rx_wcnt = 0; // rx word count
bit_cnt = 0; // bit count
clk_cnt = 0; // clock edge count
check_sum = 0;
state = STATE_RESET;
time_ref = $time;
led_data = 0;
end else begin
if(enb == 0) begin
state = STATE_RESET;
end else begin
case(state)
STATE_RESET: begin
if(rxd == 0) begin
if(($time - time_ref) > WS281X_RST) begin
$display("STATUS-WS281X-%0d: RESET PHASE DETECTED",PORT_ID);
state = STATE_WAIT_POS_EDGE;
end
end else begin
time_ref = $time;
$display("ERROR-WS281X-%0d: Out of Spec Positive Pulse Width Detected at Reset Phase : %t",PORT_ID,$time);
#1000;
$stop;
end
end
STATE_WAIT_POS_EDGE: begin
if(rxd == 1) begin
state = STATE_WAIT_NEG_EDGE;
end
end
STATE_WAIT_NEG_EDGE: begin
if(rxd == 0) begin
if(((neg_edge_time-pos_edge_time) > (WS281X_TOH-WS281X_TOLERENCE)) &&
((neg_edge_time-pos_edge_time) < (WS281X_TOH+WS281X_TOLERENCE))) begin
// Check of the Width Match with Data-0: High Pulse width
state = STATE_DATA0_LOW;
end else if(((neg_edge_time-pos_edge_time) > (WS281X_T1H-WS281X_TOLERENCE)) &&
(neg_edge_time-pos_edge_time) < (WS281X_T1H+WS281X_TOLERENCE)) begin
// Check of the Width Match with Data-1: High Pulse width
state = STATE_DATA1_LOW;
end else begin
$display("ERROR-WS281X-%0d: Out of Spec Positive Pulse Width Detected : %t",PORT_ID,neg_edge_time-pos_edge_time);
#1000;
$stop;
end
end else if(($time-pos_edge_time) > (WS281X_T1H+WS281X_TOLERENCE)) begin
$display("ERROR-WS281X-%0d: Out of Spec Positive Pulse Width Detected : %t",PORT_ID,$time);
#1000;
$stop;
end
end
// Check Data low period for DATA-0
STATE_DATA0_LOW: begin
if(rxd == 1) begin
if(((pos_edge_time-neg_edge_time) > (WS281X_PERIOD-WS281X_TOH-WS281X_TOLERENCE)) &&
((pos_edge_time-neg_edge_time) < (WS281X_PERIOD-WS281X_TOH+WS281X_TOLERENCE))) begin
// Check of the Width Match with Data-0: Neg Pulse width
led_data = led_data << 1; // Data is zero
bit_cnt = bit_cnt+1;
if(bit_cnt == 24) begin
bit_cnt = 0;
rx_wcnt = rx_wcnt+1;
$display("STATUS-WS281X-%0d: Word Cnt: %d Green: %x Red: %x Blue: %x",PORT_ID,rx_wcnt,led_data[23:16],led_data[15:8],led_data[7:0]);
check_sum = check_sum+{led_data[23:16],led_data[15:8],led_data[7:0]};
end
state = STATE_WAIT_POS_EDGE;
end else begin
$display("ERROR-WS281X-%0d: Data-0 => Out of Spec Negative Pulse Width Detected : %t",PORT_ID,pos_edge_time-neg_edge_time);
#1000;
$stop;
end
end else begin
if((($time-neg_edge_time) > (WS281X_PERIOD-WS281X_TOH+WS281X_TOLERENCE))) begin
led_data = led_data << 1; // Data is zero
bit_cnt = bit_cnt+1;
if(bit_cnt != 24) begin
$display("ERROR-WS281X-%0d: Partial Data Detected , Rx Count: %d Bit count: %d",PORT_ID,rx_wcnt,bit_cnt);
#1000;
$stop;
end
rx_wcnt = rx_wcnt+1;
$display("STATUS-WS281X-%0d: Word Cnt: %d Green: %x Red: %x Blue: %x",PORT_ID,rx_wcnt,led_data[23:16],led_data[15:8],led_data[7:0]);
check_sum = check_sum+{led_data[23:16],led_data[15:8],led_data[7:0]};
time_ref = $time;
state = STATE_RESET;
end
end
end
// Check Data low period for DATA-1
STATE_DATA1_LOW: begin
if(rxd == 1) begin
if(((pos_edge_time-neg_edge_time) > (WS281X_PERIOD-WS281X_T1H-WS281X_TOLERENCE)) &&
((pos_edge_time-neg_edge_time) < (WS281X_PERIOD-WS281X_T1H+WS281X_TOLERENCE))) begin
// Check of the Width Match with Data-0: Neg Pulse width
led_data = (led_data << 1) | 1'b1; // Data is high
bit_cnt = bit_cnt+1;
if(bit_cnt == 24) begin
bit_cnt = 0;
rx_wcnt = rx_wcnt+1;
$display("STATUS-WS281X-%0d: Word Cnt: %d Green: %x Red: %x Blue: %x",PORT_ID,rx_wcnt,led_data[23:16],led_data[15:8],led_data[7:0]);
check_sum = check_sum+{led_data[23:16],led_data[15:8],led_data[7:0]};
end
state = STATE_WAIT_POS_EDGE;
end else begin
if((($time-neg_edge_time) > (WS281X_PERIOD-WS281X_T1H+WS281X_TOLERENCE))) begin
led_data = (led_data << 1) | 1'b1; // Data is Hih
bit_cnt = bit_cnt+1;
if(bit_cnt != 24) begin
$display("ERROR-WS281X-%0d: Partial Data Detected , Rx Count: %d Bit count: %d",PORT_ID,rx_wcnt,bit_cnt);
#1000;
$stop;
end
rx_wcnt = rx_wcnt+1;
$display("STATUS-WS281X-%0d: Word Cnt: %d Green: %x Red: %x Blue: %x",PORT_ID,rx_wcnt,led_data[23:16],led_data[15:8],led_data[7:0]);
check_sum = check_sum+{led_data[23:16],led_data[15:8],led_data[7:0]};
time_ref = $time;
state = STATE_RESET;
end
end
end
end
endcase
end
end
end
endmodule