URL
https://opencores.org/ocsvn/neopixel_fpga/neopixel_fpga/trunk
Subversion Repositories neopixel_fpga
Compare Revisions
- This comparison shows the changes necessary to convert path
/neopixel_fpga
- from Rev 2 to Rev 3
- ↔ Reverse comparison
Rev 2 → Rev 3
/trunk/rtl/Makefile
0,0 → 1,51
PIN_DEF = ws2812_ctl.pcf |
DEVICE = hx8k |
|
all: $(PROJ).rpt $(PROJ).bin |
|
%.blif: %.v |
yosys -p 'synth_ice40 -top $(PROJ) -json $(PROJ).json -blif $@' $< |
|
%.asc: $(PIN_DEF) %.blif |
nextpnr-ice40 -r --$(DEVICE) --package cb132 --json $(PROJ).json --asc $(PROJ).asc --opt-timing --pcf $(PIN_DEF) |
|
%.bin: %.asc |
icepack $< $@ |
|
%.rpt: %.asc |
icetime -d $(DEVICE) -mtr $@ $< |
|
%_tb: %_tb.v %.v |
iverilog -o $@ $^ |
|
%_tb.vcd: %_tb |
vvp -N $< +vcd=$@ |
|
%_syn.v: %.blif |
yosys -p 'read_blif -wideports $^; write_verilog $@' |
|
%_syntb: %_tb.v %_syn.v |
iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` |
|
%_syntb.vcd: %_syntb |
vvp -N $< +vcd=$@ |
|
sim: $(PROJ)_tb.vcd |
|
postsim: $(PROJ)_syntb.vcd |
|
prog: $(PROJ).bin |
iceprog $< |
|
burn: $(PROJ).bin |
iceFunprog $< |
|
sudo-prog: $(PROJ).bin |
@echo 'Executing prog as root!!!' |
sudo iceprog $< |
|
clean: |
rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin $(PROJ).json |
|
.SECONDARY: |
.PHONY: all prog clean |
/trunk/rtl/ram_sync.v
0,0 → 1,40
/* |
* FpgaNeoPixel - A spi to ws2812 machine |
* |
* Copyright (C) 2020 Hirosh Dabui <hirosh@dabui.de> |
* |
* Permission to use, copy, modify, and/or distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* |
*/ |
module ram_sync(clk, addr, din, dout, we); |
parameter ADDRESS_LINES = 1024; |
parameter DATA_WIDTH = 24; |
|
input clk; |
input [$clog2(ADDRESS_LINES)-1:0] addr; |
input [DATA_WIDTH-1:0] din; |
output reg[DATA_WIDTH-1:0] dout; |
|
input we; |
|
reg [DATA_WIDTH-1:0] mem [(ADDRESS_LINES)-1:0]; |
|
always @(posedge clk) begin |
if (we) |
mem[addr] <= din; |
|
dout <= mem[addr]; |
end |
|
endmodule |
|
/trunk/rtl/simple_spi_slave.v
0,0 → 1,58
/* |
* FpgaNeoPixel - A spi to ws2812 machine |
* |
* Copyright (C) 2020 Hirosh Dabui <hirosh@dabui.de> |
* |
* Permission to use, copy, modify, and/or distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* |
*/ |
module spi_slave(resetn, clk, sck, mosi, miso, cs, done, rx_data); |
input clk; |
input resetn; |
|
input cs; |
input sck; |
input mosi; |
output miso; |
output reg done = 0; |
output reg[31:0] rx_data = 0; |
|
reg [4:0] bit_counter = 0; |
reg [2:0] rx_done_ccd = 0; |
reg [31:0] r_rx = 0; |
reg rx_done = 0; |
|
assign miso = 0; |
|
always @(posedge clk) rx_done_ccd <= {rx_done_ccd[1:0], rx_done}; |
|
always @(posedge clk) |
begin |
if (rx_done_ccd[2:1] == 2'b01) begin |
done <= 1; |
rx_data <= r_rx; |
end else |
done <= 0; |
end |
|
always @(posedge sck) |
begin |
if (cs) begin |
bit_counter <= 0; |
end else begin |
r_rx <= {r_rx[30:0], mosi}; |
bit_counter <= bit_counter + 1; |
rx_done <= (bit_counter == 31); |
end |
end |
endmodule |
/trunk/rtl/ws2812_ctl.bin
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
trunk/rtl/ws2812_ctl.bin
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/rtl/ws2812_ctl.pcf
===================================================================
--- trunk/rtl/ws2812_ctl.pcf (nonexistent)
+++ trunk/rtl/ws2812_ctl.pcf (revision 3)
@@ -0,0 +1,22 @@
+set_io --warn-no-port cs B14
+set_io --warn-no-port sck C12
+set_io --warn-no-port mosi C14
+set_io --warn-no-port miso D12
+set_io --warn-no-port ready E12
+set_io --warn-no-port clk P7
+set_io --warn-no-port dout D14
+set_io --warn-no-port resetn A3 /* A5 */
+set_io --warn-no-port leds[0] C10
+set_io --warn-no-port leds[1] A10
+set_io --warn-no-port leds[2] D7
+set_io --warn-no-port leds[3] D6
+set_io --warn-no-port leds[4] A7
+set_io --warn-no-port leds[5] C7
+set_io --warn-no-port leds[6] A4
+set_io --warn-no-port leds[7] C4
+set_io --warn-no-port lcol[0] A12
+set_io --warn-no-port lcol[1] D10
+set_io --warn-no-port lcol[2] A6
+set_io --warn-no-port lcol[3] C5
+set_io --warn-no-port spkp M12
+set_io --warn-no-port spkm M6
Index: trunk/rtl/ws2812_ctl.v
===================================================================
--- trunk/rtl/ws2812_ctl.v (nonexistent)
+++ trunk/rtl/ws2812_ctl.v (revision 3)
@@ -0,0 +1,164 @@
+/*
+ * FpgaNeoPixel - A spi to ws2812 machine
+ *
+ * Copyright (C) 2020 Hirosh Dabui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+`include "simple_spi_slave.v"
+`include "ram_sync.v"
+`include "ws2812_sequence.v"
+
+module ws2812_ctl(clk, resetn, dout, sck,
+ mosi, miso, cs, ready);
+input clk;
+input resetn;
+output dout;
+
+input cs;
+input sck;
+input mosi;
+output miso;
+output reg ready;
+
+reg [9:0] ram_addr;
+reg [9:0] rx_word_counter;
+reg [23:0] ram_din;
+wire [23:0] ram_dout;
+reg ram_we = 0;
+
+reg [23:0] din;
+reg enable = 0;
+wire done;
+
+wire spi_done;
+reg [23:0] spi_rx_data;
+wire [31:0] rx_data;
+
+// fifo write states
+localparam SYSTEM_CLOCK_FREQ = 12_000_000;
+localparam S_RESET = 0;
+localparam S_WAIT4_SPI_DATA = 1;
+localparam S_STORE_FIFO_DATA = 2;
+localparam S_PREPARE_FIFO = 3;
+
+// fifo read and burst states
+localparam S_CHECK4_FIFO_DATA = 4;
+localparam S_GET_FIFO_DATA = 5;
+localparam S_BURST_WS2812_SEQ = 6;
+localparam S_SEQ_DONE = 7;
+
+reg [2:0] state = S_RESET;
+
+spi_slave spi_slave_i(.resetn(resetn), .clk(clk), .sck(sck),
+ .mosi(mosi), .miso(miso), .cs(cs),
+ .done(spi_done), .rx_data(rx_data));
+
+ram_sync #(.ADDRESS_LINES(1024), .DATA_WIDTH(24))
+ ram_sync_i(.clk(clk), .addr(ram_addr),
+ .din(ram_din), .dout(ram_dout), .we(ram_we));
+
+ws2812_sequence #(.SYSTEM_CLOCK_FREQ(SYSTEM_CLOCK_FREQ))
+ ws2812_sequence_i(.clk(clk),
+ .din(din),
+ .resetn(resetn),
+ .enable(enable),
+ .dout(dout),
+ .done(done)
+ );
+
+always @(posedge clk)
+ ready <= ~( &(~ram_addr) && state == S_WAIT4_SPI_DATA);
+
+always @(posedge clk) begin
+ if (~resetn) begin
+ state <= S_RESET;
+ end else begin
+ case (state)
+
+ S_RESET: begin
+ enable <= 0;
+ rx_word_counter <= 0;
+ ram_addr <= 0;
+ ram_we <= 0;
+ spi_rx_data <= 0;
+ state <= S_WAIT4_SPI_DATA;
+ end
+
+ S_WAIT4_SPI_DATA: begin
+ if (spi_done) begin
+ spi_rx_data <= rx_data[23:0];
+ if (rx_data == 32'h dead_beaf) begin
+ rx_word_counter <= ram_addr;
+ ram_addr <= 0;
+ state <= S_CHECK4_FIFO_DATA;
+ end else begin
+ state <= S_STORE_FIFO_DATA;
+ end
+ end else
+ state <= S_WAIT4_SPI_DATA;
+ end
+
+ S_STORE_FIFO_DATA: begin
+ ram_we <= 1;
+ ram_din <= spi_rx_data;
+ state <= S_PREPARE_FIFO;
+ end
+
+ S_PREPARE_FIFO: begin
+ ram_we <= 0;
+ ram_addr <= ram_addr + 1;
+ state <= S_WAIT4_SPI_DATA;
+ end
+
+ S_CHECK4_FIFO_DATA: begin
+ ram_we <= 0;
+ enable <= 0;
+ if (ram_addr == (rx_word_counter)) begin
+ spi_rx_data <= 0;
+ rx_word_counter <= 0;
+ ram_addr <= 0;
+ ram_we <= 0;
+ state <= S_WAIT4_SPI_DATA;
+ end else
+ state <= S_GET_FIFO_DATA;
+ end
+
+ S_GET_FIFO_DATA: begin
+ din <= ram_dout;
+ state <= S_BURST_WS2812_SEQ;
+ end
+
+ S_BURST_WS2812_SEQ: begin
+ enable <= 1;
+ state <= S_SEQ_DONE;
+ end
+
+ S_SEQ_DONE: begin
+ enable <= 0;
+ if (done) begin
+ ram_addr <= ram_addr + 1;
+ state <= S_CHECK4_FIFO_DATA;
+ end else
+ state <= S_SEQ_DONE;
+ end
+
+ default: begin
+ state <= S_RESET;
+ end
+ endcase
+ end end
+
+endmodule
+
Index: trunk/rtl/ws2812_ctl_tb.v
===================================================================
--- trunk/rtl/ws2812_ctl_tb.v (nonexistent)
+++ trunk/rtl/ws2812_ctl_tb.v (revision 3)
@@ -0,0 +1,128 @@
+/*
+ * FpgaNeoPixel - A spi to ws2812 machine
+ *
+ * Copyright (C) 2020 Hirosh Dabui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+`include "ws2812_sequence.v"
+module testbench;
+localparam CLK_HZ = 12_000_000;
+reg clk;
+reg resetn;
+wire dout;
+
+reg cs;
+reg sck;
+reg mosi;
+wire miso;
+wire ready;
+
+
+reg [4095:0] vcdfile;
+always #5 clk = (clk === 1'b0);
+
+always #40 sck = (sck === 1'b0);
+
+ws2812_ctl uut(
+ .clk(clk),
+ .resetn(reset),
+ .dout(dout),
+ .sck(sck),
+ .mosi(mosi),
+ .miso(miso),
+ .cs(cs),
+ .ready(ready),
+ );
+
+ initial begin
+ if ($value$plusargs("vcd=%s", vcdfile)) begin
+ $dumpfile(vcdfile);
+ $dumpvars(0, testbench);
+ end
+ end
+
+ integer i = 0;
+ integer j = 0;
+ reg [31:0] data = 0;
+ initial begin
+ cs = 1;
+ sck = 1;
+ resetn = 0;
+ #200 resetn = 1;
+ repeat(5)@(posedge sck);
+
+ for (i = 0; i < 10; i = i + 1)
+ begin
+/*
+ cs = 0;
+ data = 32'hdeadbeaf;
+ for (j = 0; j < 32; j = j+1)
+ begin
+ mosi = data[31-j];
+ repeat(1)@(posedge sck);
+ end
+ cs = 1;
+ repeat(2)@(posedge sck);
+*/
+ cs = 0;
+ data = 32'h80_000001;
+ for (j = 0; j < 32; j = j+1)
+ begin
+ mosi = data[31-j];
+ repeat(1)@(negedge sck);
+ end
+ cs = 1;
+
+ repeat(2)@(posedge sck);
+
+ /*
+ cs = 0;
+ data = 32'h00_000002;
+ for (j = 0; j < 32; j = j+1)
+ begin
+ mosi = data[31-j];
+ repeat(1)@(posedge sck);
+ end
+ cs = 1;
+
+ repeat(2)@(posedge sck);
+
+ cs = 0;
+ data = 32'h00_000003;
+ for (j = 0; j < 32; j = j+1)
+ begin
+ mosi = data[31-j];
+ repeat(1)@(posedge sck);
+ end
+ cs = 1;
+*/
+
+ repeat(2)@(posedge sck);
+
+ cs = 0;
+ data = 32'hdeadbeaf;
+ for (j = 0; j < 32; j = j+1)
+ begin
+ mosi = data[31-j];
+ repeat(1)@(negedge sck);
+ end
+ cs = 1;
+ repeat(1000)@(posedge sck);
+ end
+
+
+ $finish;
+ end
+endmodule
Index: trunk/rtl/ws2812_sequence.v
===================================================================
--- trunk/rtl/ws2812_sequence.v (nonexistent)
+++ trunk/rtl/ws2812_sequence.v (revision 3)
@@ -0,0 +1,176 @@
+/*
+ * FpgaNeoPixel - A spi to ws2812 machine
+ *
+ * Copyright (C) 2020 Hirosh Dabui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+`ifndef WS2812_DATA_SEQUENCE_H
+`define WS2812_DATA_SEQUENCE_H
+module ws2812_sequence(clk, resetn, enable, din, dout, done);
+ /*
+ * e.g. 12 MHz = 83,33ns = 0.083us cycles
+ *
+ * 0,45 us => 450 ns
+ *
+ * T0H = 0,4 us = 400 ns ~ cycles * 5 = 416.65 ns
+ * T0L = 0.85 us = 850 ns ~ cycles * 10 = 833.3 ns
+ *
+ * T0H + T0L = 1250 ns ~ 1249.95 ns
+ *
+ * T1H = 0.8us = 800 ns ~ cycles * 10 = 833.3 ns
+ * T1L = 0.45us = 450 ns ~ cycles * 5 = 416.65 ns
+ *
+ * T0H + T0L = 1250 ns ~ 1249.95 ns
+ *
+ * RES above 50 us = 50000ns ~ cycles * 610 = 50831 ns
+ * +/- 150 ns
+ *
+ * with 12 MHz = 1249.95 = +/- 0.05 ns
+ *
+ * ______
+ * | T0H |__T0L___|
+ *
+ * ______
+ * | T1H |__T1L___|
+ *
+ * |____Treset ____|
+ *
+ */
+ localparam GRB_WIDTH = 24;
+
+ parameter SYSTEM_CLOCK_FREQ = 12_000_000;
+ parameter T0H_TIME = 0.4e-6; // 400 ns
+ parameter T0L_TIME = 0.85e-6; // 850 ns
+ localparam CLK_HZ = $itor(SYSTEM_CLOCK_FREQ);
+ localparam CLK_CYCLE = (1/CLK_HZ);
+
+ localparam T0H_CYCLES = $rtoi((T0H_TIME)/CLK_CYCLE+0.5);//5;
+ localparam T0L_CYCLES = $rtoi((T0L_TIME)/CLK_CYCLE+0.5);//10;
+
+ localparam T1H_CYCLES = T0L_CYCLES;
+ localparam T1L_CYCLES = T0H_CYCLES;
+
+ localparam SEQUENCE_CYCLE = T0H_CYCLES + T0L_CYCLES;
+
+ localparam TRESET_CYCLES = $rtoi((50e-6)/CLK_CYCLE+0.5);//610; // ~ 50us
+
+ localparam CYCLE_BITS = $clog2(SEQUENCE_CYCLE);
+
+ input clk;
+ input resetn;
+ input enable;
+
+ /* |G7|...|G0|R7|...|R0|B7|..|B0| */
+ input wire [GRB_WIDTH -1:0] din;
+
+ output reg dout = 1'b0;
+ output reg done = 1'b0;
+
+ reg [GRB_WIDTH - 1:0] data_in = 0;
+ reg [CYCLE_BITS-1:0] dout_cycle_cnt = 0;
+ reg [$clog2(GRB_WIDTH-1):0] dout_bit_cycle_cnt = 0;
+ reg dbit = 0;
+
+
+ // states
+ localparam S_RESET = 0;
+ localparam S_IDLE = 1;
+ localparam S_SEQUENCE_OUT = 2;
+
+ localparam S_TXH_DATA_SEQUENCE = 3;
+ localparam S_TXL_DATA_SEQUENCE = 4;
+
+ reg [2:0] state = S_RESET;
+
+ initial begin
+ $display("CLK_HZ: ", CLK_HZ);
+ $display("CLK_CYCLE: ", CLK_CYCLE);
+ $display("T0H_CYCLES: ", T0H_CYCLES);
+ $display("T0L_CYCLES: ", T0L_CYCLES);
+ $display("SEQUENCE_CYCLE: ", SEQUENCE_CYCLE);
+ $display("CYCLE_BITS: ", CYCLE_BITS);
+ $display("$clog2(GRB_WIDTH): ", $clog2(GRB_WIDTH));
+ $display("TRESET_CYCLES: ", TRESET_CYCLES);
+ end
+
+ always @(posedge clk) begin
+ if (~resetn) begin
+ done <= 0;
+ dout <= 0;
+ state <= S_RESET;
+ end else begin
+ case (state)
+
+ S_RESET: begin
+ state <= S_IDLE;
+ end
+
+ S_IDLE: begin
+ done <= 0;
+ dout_bit_cycle_cnt <= 0;
+ dout_cycle_cnt <= 0;
+ dout <= 0;
+ if (enable) begin
+ data_in <= din;
+ state <= S_SEQUENCE_OUT;
+ end else
+ state <= S_IDLE;
+ end
+
+ S_SEQUENCE_OUT: begin
+ dout_bit_cycle_cnt <= dout_bit_cycle_cnt + 1;
+ if (dout_bit_cycle_cnt == GRB_WIDTH) begin
+ done <= 1;
+ state <= S_IDLE;
+ end else begin
+ dout_cycle_cnt <= 1;
+ data_in <= {data_in[GRB_WIDTH -2: 0], 1'b0};
+ dbit <= data_in[GRB_WIDTH -1];
+ state <= S_TXH_DATA_SEQUENCE;
+ end
+ end
+
+ S_TXH_DATA_SEQUENCE: begin
+ dout_cycle_cnt <= dout_cycle_cnt + 1;
+ if (dout_cycle_cnt < (dbit ? T1H_CYCLES[CYCLE_BITS-1:0] : T0H_CYCLES[CYCLE_BITS-1:0])) begin
+ dout <= 1;
+ state <= S_TXH_DATA_SEQUENCE;
+ end
+ else begin
+ dout_cycle_cnt <= 1;
+ state <= S_TXL_DATA_SEQUENCE;
+ end
+ end
+
+ S_TXL_DATA_SEQUENCE: begin
+ dout_cycle_cnt <= dout_cycle_cnt + 1;
+ if ((dout_cycle_cnt < (dbit ? T1L_CYCLES[CYCLE_BITS-1:0] -1: T0L_CYCLES[CYCLE_BITS-1:0] -1))) begin
+ dout <= 0;
+ state <= S_TXL_DATA_SEQUENCE;
+ end
+ else
+ state <= S_SEQUENCE_OUT;
+ end
+
+ // fall-through reset
+ default: begin
+ state <= S_RESET;
+ end
+ endcase
+ end
+end
+
+endmodule
+`endif
Index: trunk/rtl/ws2812_sequence_tb.v
===================================================================
--- trunk/rtl/ws2812_sequence_tb.v (nonexistent)
+++ trunk/rtl/ws2812_sequence_tb.v (revision 3)
@@ -0,0 +1,53 @@
+/*
+ * FpgaNeoPixel - A spi to ws2812 machine
+ *
+ * Copyright (C) 2020 Hirosh Dabui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+`include "ws2812_sequence.v"
+
+module testbench;
+localparam CLK_HZ = 12_000_000;
+reg clk;
+wire dout;
+wire done;
+reg reset;
+
+
+reg [4095:0] vcdfile;
+always #5 clk = (clk === 1'b0);
+ws2812_sequence uut(.clk(clk),
+ .din(24'h000001),
+ .resetn(reset),
+ .enable(1'b1),
+ .dout(dout),
+ .done(done)
+ );
+
+ initial begin
+ if ($value$plusargs("vcd=%s", vcdfile)) begin
+ $dumpfile(vcdfile);
+ $dumpvars(0, testbench);
+ end
+ end
+
+ initial begin
+ reset = 0;
+ repeat (2) @(posedge clk);
+ reset = 1;
+ repeat (2000) @(posedge clk);
+ $finish;
+ end
+endmodule
Index: trunk/src/FPGA_NeoPixel/FPGA_NeoPixel.h
===================================================================
--- trunk/src/FPGA_NeoPixel/FPGA_NeoPixel.h (nonexistent)
+++ trunk/src/FPGA_NeoPixel/FPGA_NeoPixel.h (revision 3)
@@ -0,0 +1,89 @@
+/*
+ * FpgaNeoPixel - A spi to ws2812 machine
+ *
+ * Copyright (C) 2020 Hirosh Dabui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+#ifndef FPGA_NEOPIXEL_H
+#define FPGA_NEOPIXEL_H
+#include
+#include
+class FPGA_NeoPixel : public Adafruit_NeoPixel {
+
+ public:
+ explicit FPGA_NeoPixel(uint16_t n, uint16_t pin = 6 /* is not needed */,
+ neoPixelType type = NEO_GRB + NEO_KHZ800) : Adafruit_NeoPixel(n, pin, type) {};
+
+ void begin() {
+ pinMode(READY_PIN, INPUT_PULLUP);
+ pinMode(RESETN_PIN, OUTPUT);
+ digitalWrite(SS, HIGH);
+
+ delay(1);
+
+ SPI.begin();
+ SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0));
+
+ digitalWrite(RESETN_PIN, 0);
+ delay(200);
+ digitalWrite(RESETN_PIN, 1);
+ delay(1000);
+
+ Adafruit_NeoPixel::begin();
+ }
+
+ void show() {
+ if (!pixels) return;
+
+ wait_asic();
+
+ uint16_t i = numBytes; // Loop counter
+ uint8_t *p = pixels; // pointer to next byte
+
+ for (uint16_t n = 0; n < numBytes / 3; n++) {
+ grb(*p++, *p++, *p++);// brg
+ }
+ sync();
+ }
+
+ private:
+ void wait_asic() {
+ for (;;) {
+ int val = digitalRead(READY_PIN);
+ if (val == 0) break;
+ }
+ }
+
+ inline void grb(uint8_t b, uint8_t r, uint8_t g) {
+ digitalWrite(SS, LOW);
+ SPI.transfer(0);
+ SPI.transfer(g);
+ SPI.transfer(r);
+ SPI.transfer(b);
+ digitalWrite(SS, HIGH);
+ }
+
+ /* asic show leds and empty your fifo*/
+ inline void sync() {
+ digitalWrite(SS, LOW);
+ SPI.transfer(0xde);
+ SPI.transfer(0xad);
+ SPI.transfer(0xbe);
+ SPI.transfer(0xaf);
+ digitalWrite(SS, HIGH);
+ }
+};
+#endif // FPGA_NEOPIXEL_H
+
Index: trunk/src/strandtest/strandtest.ino
===================================================================
--- trunk/src/strandtest/strandtest.ino (nonexistent)
+++ trunk/src/strandtest/strandtest.ino (revision 3)
@@ -0,0 +1,164 @@
+/*
+ * FpgaNeoPixel - A spi to ws2812 machine
+ *
+ * Modified for FpgaNeoPixel by Hirosh Dabui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// just overwrite show from Adafruit_NeoPixel to use it
+// i have use strandtest.ino, just copy class FPGA_NeoPixel in your Adafruit_NeoPixel code
+// and instantiate FPGA_NeoPixel
+
+#define READY_PIN 49
+#define RESETN_PIN 47
+#define LED_PIN 6 // this pin is not needed
+ // but i don't wanted to touch Adafruit_NeoPixel code deeper
+
+#include
+
+#define LED_COUNT 60
+
+
+FPGA_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
+
+// Argument 1 = Number of pixels in NeoPixel strip
+// Argument 2 = Arduino pin number (most are valid)
+// Argument 3 = Pixel type flags, add together as needed:
+// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
+// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
+// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
+// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
+// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
+
+
+// setup() function -- runs once at startup --------------------------------
+
+void setup() {
+ // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
+ // Any other board, you can remove this part (but no harm leaving it):
+#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
+ clock_prescale_set(clock_div_1);
+#endif
+ // END of Trinket-specific code.
+
+ strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
+ strip.show(); // Turn OFF all pixels ASAP
+ strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
+}
+
+
+// loop() function -- runs repeatedly as long as board is on ---------------
+
+void loop() {
+#if 0
+ // just set some pixel for testing
+ strip.setPixelColor(0,255,0,0);
+ strip.setPixelColor(59,0,0,255);
+ strip.show();
+ return;
+#else
+ // Fill along the length of the strip in various colors...
+ colorWipe(strip.Color(255, 0, 0), 50); // Red
+ colorWipe(strip.Color( 0, 255, 0), 50); // Green
+ colorWipe(strip.Color( 0, 0, 255), 50); // Blue
+
+ // Do a theater marquee effect in various colors...
+ theaterChase(strip.Color(127, 127, 127), 50); // White, half brightness
+ theaterChase(strip.Color(127, 0, 0), 50); // Red, half brightness
+ theaterChase(strip.Color( 0, 0, 127), 50); // Blue, half brightness
+
+ rainbow(10); // Flowing rainbow cycle along the whole strip
+ theaterChaseRainbow(50); // Rainbow-enhanced theaterChase variant
+#endif
+}
+
+
+// Some functions of our own for creating animated effects -----------------
+
+// Fill strip pixels one after another with a color. Strip is NOT cleared
+// first; anything there will be covered pixel by pixel. Pass in color
+// (as a single 'packed' 32-bit value, which you can get by calling
+// strip.Color(red, green, blue) as shown in the loop() function above),
+// and a delay time (in milliseconds) between pixels.
+void colorWipe(uint32_t color, int wait) {
+ for(int i=0; i RGB
+ strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
+ }
+ strip.show(); // Update strip with new contents
+ delay(wait); // Pause for a moment
+ firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
+ }
+ }
+}
Index: trunk/src/README.mk
===================================================================
--- trunk/src/README.mk (nonexistent)
+++ trunk/src/README.mk (revision 3)
@@ -0,0 +1 @@
+Just copy FPGA_NeoPixel in your Arduino library folder
Index: trunk/Readme.md
===================================================================
--- trunk/Readme.md (nonexistent)
+++ trunk/Readme.md (revision 3)
@@ -0,0 +1,48 @@
+
+
+FPGA Neopixel Device
+====================
+I was really impressed with the Adafruit Neopixel demo. The rainbow effect looks so nice :).
+It cost me around 5 minutes to setup the environment for the Adafruit Neopixel.
+While studying the Adafruit Neopixel implementation and the datasheet of the ws2812,
+some things immediately stood out: Assembly for each soc, disabling interrupts to get the
+right timings for each soc shape, etc.
+
+Now I have a reason to buy an oscilloscope to the see the output of the 1-wire.
+I experiemented with my own assembly implementation counting the machinecode cycles of
+ATmega328 to setup ws2812 leds over one wire. The protocol has heavy time constraints +-150ns and the the data of
+leds has to transmit one after another (https://cdn-shop.adafruit.com/datasheets/WS2812.pdf).
+Here is an example of a 36 foot long neopixel strip https://www.youtube.com/watch?v=I-lR19_kigs.
+The conclusion is that it makes no sense for me, since it is not portable.
+To disable interrupts in impeded environments with sensitive application is not ideal.
+There are some exceptions, such as the Rasperry Pi which has a real-time implementation
+by using PWM with supported DMA (https://learn.adafruit.com/neopixels-on-raspberry-pi/overview).
+Keeping timings conditions on a ATmega328 is feasible but on a CORTEX-A without HW-Support
+running a sensitive application with caches, disabling interrupts is a bit extreme.
+So I started my FPGA hobby project and dove right into FPGA programing and verilog.
+My approach is using a SPI to collect 24-RGBs-Strips-Data and a SYNC from a impeded SoC.
+Another approach I came up with is to reuse the Adafruit-Neopixel-Library.
+I attached my FPGA_NeoPixel.h file. Technically it inherits from Adafruit_NeoPixel and overwrites
+the void show() with SPI-Code so you are able to use the methods from Adafruit_Neopixel to set
+leds or calculate color spaces. I have tested it on an Arduiono-Nano but it is easy to
+port the Libs to other SoCs. The only things that matter are the SPI and Neopixel managment.
+
+The implementation is based on an iceFun (ice40-hx8k, https://www.robot-electronics.co.uk/icefun.html). It is easy to port it to another FPGA,
+you only have to specify the frequency and pins. The current implementation is using a 16K-Fifo (ice40-hk8),
+maybe you can even try to control an 16k strip with it ;)
+A short video shows the result https://www.youtube.com/watch?v=bKlIKz7Y1Lk of my implementation.
+
+A FPGA has many I/Os just extend it to many 1-wire-outputs to handle more strips in parallel.
+I will make my fpga project available on github and if you find the time to take a
+look and tinker with it, I would be grateful for any feedback.
+Some background why I started this project.
+
+I searched for an open source command based verilog compiler and I found
+Icarus Verilog (http://iverilog.icarus.com/) + gtkwave from Stephen Williams.
+In this context I found verilator which is awesome. (https://www.veripool.org/)
+Probably by accident I found the icestorm project by Mr.
+Cliffword and I was so impressed by yosys and arachne-pnr/nextpnr because Synthesis is a domain
+of some companies like synopsis, cadence, mentor graphics with very expensiv license costs.
+In my opinion Mr. Cliffword changed the rules in circuit design (http://opencircuitdesign.com/).
+I am very greatful to him. Now we have compilers for programming languages,
+operating systems and circuit design tools FOSS like - it is so amazing.