summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-11-15 09:50:36 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2016-11-15 09:50:36 (GMT)
commita893fbf5d707d2958ed22eac768b654473dec410 (patch)
treea4e7b018421f4d2c51466e874dddd4bb43f6ec72
parent58001a2749e4c18f8167c808c384a5255c0bb125 (diff)
downloadabc80-npled.zip
abc80-npled.tar.gz
abc80-npled.tar.bz2
abc80-npled.tar.xz
neopixel: simplify the design by offsetting pulsesnpled
It makes the design quite a bit simpler to not try to synchronize all the pulse starts together. Futhermore, it reduces the number of I/O pins toggling at the same time, which is good for noise reduction. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--neopixel.v83
1 files changed, 27 insertions, 56 deletions
diff --git a/neopixel.v b/neopixel.v
index 008abd8..a0ac49b 100644
--- a/neopixel.v
+++ b/neopixel.v
@@ -41,11 +41,14 @@ module neopixel (
output reg [31:0] npout
);
+ // Code assumes pulse0 < pulse1
+ parameter pulse0 = 8;
+ parameter pulse1 = 20;
+
// Pipeline stages:
// A - generate address for config/status RAM
// B - generate address for SRAM, advance staus RAM
- // D - process and latch output
- // E - pulse shaping
+ // pulse shaping (delay line for data)
reg g_enable; // Global enable, latched on word boundaries
@@ -53,8 +56,6 @@ module neopixel (
// 32 channels x 24 bits
reg [9:0] a_ctr;
reg [9:0] b_ctr;
- reg [9:0] d_ctr;
- reg [9:0] e_ctr;
wire [9:0] a_ctr_p1 = a_ctr + 1'b1;
@@ -63,8 +64,6 @@ module neopixel (
begin
a_ctr <= 10'd0;
b_ctr <= 10'd1;
- d_ctr <= 10'd2;
- e_ctr <= 10'd3;
g_enable <= 1'b0;
end
else
@@ -81,8 +80,6 @@ module neopixel (
end
b_ctr <= a_ctr;
- d_ctr <= b_ctr;
- e_ctr <= d_ctr;
end // else: !if(~rst_n)
// A stage, counter fed to RAMs
@@ -132,9 +129,6 @@ module neopixel (
wire [7:0] b_stat_pctr = b_stat_q[23:16];
wire [8:0] b_stat_cctr = b_stat_q[32:24];
- // Output: are we in chain reset?
- reg b_in_rst;
-
// Channel is enabled if plen > 0 or global disable
wire b_ena = |b_conf_plen & g_enable;
@@ -174,63 +168,40 @@ module neopixel (
end // else: !if( ~b_ena )
end // always @ (*)
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- b_in_rst <= 1'b1;
- else
- b_in_rst <= ~b_ena | b_stat_cctr[8];
+ // Output: are we in chain reset?
+ wire b_in_rst = ~b_ena | b_stat_cctr[8];
// b_ctr[7:5] is inverted as bit order is bigendian
assign ram_a = { b_stat_addr, ~b_ctr[7:5] };
- // D stage, data out from SRAM, parallel out
- reg [31:0] d_in_rst;
- reg [31:0] d_data;
-
- reg [1:0] pulse;
-
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- begin
- d_in_rst <= ~32'b0;
- d_data <= 32'bx;
- pulse <= 2'b0;
- end
- else
- begin
- d_in_rst[d_ctr[4:0]] <= b_in_rst;
- d_data[d_ctr[4:0]] <= ram_q;
- pulse[0] <= (d_ctr[4:0] < 5'd8);
- pulse[1] <= (d_ctr[4:0] < 5'd20);
- end
-
- // E stage, pulse generation (all channels loaded in parallel)
+ // Pulse generation. We can start the pulse even before the data
+ // arrives from SRAM, as we will already know if we are in reset!
- reg [31:0] e_in_rst;
- reg [31:0] e_data;
-
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- begin
- e_in_rst <= ~32'b0;
- e_data <= 32'bx;
- end
- else if (&e_ctr[4:0])
- begin
- // Parallel load of all channels
- e_in_rst <= d_in_rst;
- e_data <= d_data;
- end
+ // Shift register to delay data for pulse generation
+ reg [pulse0-2:0] data_q;
+ always @(posedge clk)
+ data_q <= { ram_q, data_q[pulse0-2:1] };
+ // Output pulse generation
genvar i;
generate
for (i = 0; i < 32; i = i + 1)
begin: gen_npout
always @(negedge rst_n or posedge clk)
- if (~rst_n)
+ if ( ~rst_n )
npout[i] <= 1'b0;
else
- npout[i] <= ~e_in_rst[i] & pulse[e_data[i]];
- end
+ begin
+ case ( b_ctr[4:0] )
+ (i & 5'h1f):
+ npout[i] <= ~b_in_rst;
+ ((i+pulse0) & 5'h1f):
+ npout[i] <= npout[i] & data_q[0];
+ ((i+pulse1) & 5'h1f):
+ npout[i] <= 1'b0;
+ endcase // case ( b_ctr[4:0] )
+ end // else: !if( ~rst_n )
+ end // block: gen_npout
endgenerate
+
endmodule // neopixel