OpenCores
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/trunk
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/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
/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
 
/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
/rtl/ws2812_ctl.bin Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
rtl/ws2812_ctl.bin Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rtl/ws2812_ctl.pcf =================================================================== --- rtl/ws2812_ctl.pcf (nonexistent) +++ 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: rtl/ws2812_ctl.v =================================================================== --- rtl/ws2812_ctl.v (nonexistent) +++ 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: rtl/ws2812_ctl_tb.v =================================================================== --- rtl/ws2812_ctl_tb.v (nonexistent) +++ 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: rtl/ws2812_sequence.v =================================================================== --- rtl/ws2812_sequence.v (nonexistent) +++ 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: rtl/ws2812_sequence_tb.v =================================================================== --- rtl/ws2812_sequence_tb.v (nonexistent) +++ 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: src/FPGA_NeoPixel/FPGA_NeoPixel.h =================================================================== --- src/FPGA_NeoPixel/FPGA_NeoPixel.h (nonexistent) +++ 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: src/strandtest/strandtest.ino =================================================================== --- src/strandtest/strandtest.ino (nonexistent) +++ 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: src/README.mk =================================================================== --- src/README.mk (nonexistent) +++ src/README.mk (revision 3) @@ -0,0 +1 @@ +Just copy FPGA_NeoPixel in your Arduino library folder Index: Readme.md =================================================================== --- Readme.md (nonexistent) +++ 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.

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.