I had originally thought that this project would not be so difficult to implement. Once I “got” the concepts I was able to create the animated colors. The following code includes lines from Vivonomicon.
// Cause yosys to throw an error when we implicitly declare nets // `default_nettype none // Project entry point module top ( input CLK, input BTN_N, BTN1, BTN2, BTN3, output LED1, LED2, LED3, LED4, LED5, output P1B1, ); // Neopixel state machine. reg [2:0] state; reg [1:0] npxc; reg [12:0] lpxc; reg [7:0] bits; reg [7:0] led_num; reg [24:0] test_color = 24'b000000010000000100000000; reg [1:0] isiton; reg [24:0] color_run1 = 24'b000000001000000000000000; reg [24:0] color_run2 = 24'b000000001000000000010000; reg [24:0] color_run3 = 24'b000000001000000010000000; reg [24:0] color_run4 = 24'b000000000000000010000000; reg [24:0] color_run5 = 24'b100000000000000010000000; reg [24:0] color_run6 = 24'b100000000000000000000000; reg [24:0] color_run7 = 24'b100000001000000000000000; reg [24:0] color_temp = 24'b000000001000000000000000; reg [32:0] running_it = 0; assign LED1 = 1'b0; assign LED2 = 1'b0; assign LED3 = 1'b0; assign LED4 = 1'b0; assign LED5 = 1'b0; assign P1B1 = isiton; always @(posedge CLK) begin // Process the state machine; states 0-3 are the four WS2812B 'ticks', // each consisting of 83.33 * 4 ~= 333.33 nanoseconds. Four of those // ticks are then ~1333.33 nanoseconds long, and we can get close to // the ideal 1250ns period. // A '1' is 3 high periods followed by 1 low period (999.99/333.33 ns) // A '0' is 1 high period followed by 3 low periods (333.33/999.99 ns) if (state == 0 || state == 1 || state == 2 || state == 3) begin // run this for 3 times then increase state npxc = npxc + 1; if (npxc == 0) begin state = state + 1; end end // end of states 0, 1, 2, OR 3 if (state == 4) // increases bits then if 24 set to 0 and increase state to 5, if <24 state = 0 begin bits = bits + 1; if (bits == 24) begin bits = 0; state = state + 1; end else begin state = 0; end end // end of state 4 if (state == 5) // go to the next pixel on the strip. if it is at the end state = 6, otherwise state = 0 begin led_num = led_num + 1; case (led_num) 1: test_color = color_run1; 2: test_color = color_run2; 3: test_color = color_run3; 4: test_color = color_run4; 5: test_color = color_run5; 6: test_color = color_run6; 7: test_color = color_run7; default: test_color = 24'b000000000000000000000000; endcase if (led_num == 10) begin led_num = 0; state = state + 1; end else begin state = 0; end end // end of state 5 if (state == 6) // This is a 12 bit counter sending 0 out the serial indicating reset of the strip begin // it lasts for >80µs meaning that the end of the pixel numbers has been reached lpxc = lpxc + 1; if (lpxc == 0) begin state = 0; end end // end of state 6 // Set the correct pin state. if (test_color & (1 << bits)) // if the current bit of test_color is 1, or ON, serial is high begin if (state == 0 || state == 1 || state == 2) // run three cycles of high for pixel ON begin isiton <= 1; end else if (state == 3 || state == 6) // run one cycle of low for pixel ON begin isiton <= 0; end end // end of testing the & bit is 1. If the current bit is 0, or OFF, serial is low. else begin if (state == 0) // run one cycle of high for pixel OFF begin isiton <= 1; end else if (state == 1 || state == 2 || state == 3 || state == 6) // run three cycles of low for pixel off begin isiton <= 0; end end // end of testing the & bit is 0 end // end of the always main program // make another always module to change the colors in a cycle always @(posedge CLK) begin running_it++; if (running_it == 1000000) begin running_it = 0; color_temp = color_run1; color_run1 = color_run2; color_run2 = color_run3; color_run3 = color_run4; color_run4 = color_run5; color_run5 = color_run6; color_run6 = color_run7; color_run7 = color_temp; end // end of the running_it and reset end // end of the always that cycles the color_run stuff endmodule
There might be better ways of implementing the result, but I think I did pretty well as a beginner in FPGA land.
Now that I have this completed I might be able to add a different power source for the 5v on the WS2812B strip. Then I should be able to add more strips by using the other PMOD pins. This Icebreaker has three PMODs built on it. That would be 24 strips. It would make for a great animation.
In the mean time I could add the dip-switch PMOD and use the switches to determine the speed that the cycling lights run. At first I thought of using a potentiometer to control the speed. I have some, probably too many. The dip-switch module is sitting out right by where I have been coding.
Company is coming for the weekend and I am going to have to clear up this space. Luckily, I am going to be sleeping in the trailer. I can move all of my stuff out there. I’ll have to come back into the house to get more parts, as needed.
Later that night
Before going to fiddle lessons I wanted to see if I could indeed add the dip-switch PMOD. I ended up adding some code to the existing which is displayed above. Up in the reg area I added
reg [32:0] speeder = 2000000;
In the last always block I changed the 1000000 to speeder, and then added another always block.
// another always block to change the speed with DIP-switch PMOD on the A section always @(posedge CLK) begin if (!P1A1) speeder = 2000000; if (P1A1) speeder = 1000000; if (P1A1 & P1A2) speeder = 800000; if (P1A1 & P1A2 & P1A3) speeder = 600000; if (P1A1 & P1A2 & P1A3 & P1A4) speeder = 400000; end // end of the always block for speed
Turning on the dip-switches in order together will change the value of the variable speeder. It works well, but I have to mind where I put my fingers while toggling the dip-switches.