I was trying to develop a simple ws2812b LED driver with FPGA in VHDL.
I have implemented it as a state machine. One of the states is responsible for pulling the output line low. This is the code snippet:
ELSIF state = 1 THEN -- send bit low
--determine byte 0 or 1
STRIP_OUT <= '0';
IF LED_COLOR(bitIndex) = '1' THEN
waiter <= ONE_LOW_NS;
ELSE
waiter <= ZERO_LOW_NS;
END IF;
--is there more to send?
IF bitIndex + 1 > 23 AND ledIdx >= N_LEDS THEN --latch
bitIndex <= 0;
state <= 2; --latch state
ledIdx <= 1;
ELSE
IF bitIndex + 1> 23 THEN
bitIndex <= 0;
ledIdx <= ledIdx + 1;
ELSE
bitIndex <= bitIndex + 1;
END IF;
state <= 0; --next bit high state
END IF;
The reasoning is simple. If you have to send the low part of the bit, set the waiter (a counter that just decreases -clock_period in nanoseconds each clock pulse) to the time of the low state corresponding to 1 or 0 output.
If all color bits are sent (so the current bit index is 23) then just set the bit index to zero and change state to the "latch" signal. Otherwise increment the bit index or the led index if there are more LED's.
Now the aforementioned snippet works, but I made it by trial and error. The first version of code I had is this:
ELSIF state = 1 THEN -- send byte low
--determine byte 0 or 1
STRIP_OUT <= '0';
IF LED_COLOR(bitIndex) = '1' THEN
waiter <= ONE_LOW_NS;
ELSE
waiter <= ZERO_LOW_NS;
END IF;
bitIndex <= bitIndex + 1;
--is there more to send?
IF bitIndex > 23 AND ledIdx >= N_LEDS THEN --latch
bitIndex <= 0;
state <= 2;
ledIdx <= 1;
ELSE
IF bitIndex > 23 THEN
bitIndex <= 0;
ledIdx <= ledIdx + 1;
END IF;
state <= 0; --next bit high state
END IF;
The only difference is, it first increments the bit index, and then if it would mean sending 25'th bit (which is out of bounds), it sets it back to zero and goes into the latch state.
The problem with this code is, that it kind of overlaps, sends the first bit of the sequence again totalling to 25 bits sent (checked with simulator), as if it never incremented the bitIndex signal and it went to state 0 (send high) instead of 2 (latch).
This "experiment" would lead me to believe, that setting a signal in a single clock affects it's state on the next clock only or with some delay which is unknown to me (but it still happens in the simulator which technically has no delays). Is that by any means true?