I won't opine on whether the problem is your debouncing or not. I will just tell you how to debounce something in FPGAs (works in software too).
Conceptually, there are two simple debounce methods you can do when making a debounce block:
- On an incoming edge, immediately pass the signal state to the output and latch that output for n-cycles. Low latency since it reacts immediately, but is sensitive to induced noise.
- More immune to induced noise but higher latency is to block the incoming edge from affecting the output until the input is stable for n-amount of cycles.
The clumsy way to do this is to store all the previous N-samples in a rolling state and compare them to make sure they are all the same before passing on the input to the output. Each time you grab a new sample, you throw out the oldest sample (shifts are good for this).
Don't use that method. It takes up a lot of memory if your clock is running very fast (which it probably will be) compared to the mechanical settling time of the switch since you require many more samples for the same amount of settling time.
The more efficient way is to store only the previous sample and compare it to the current sample and if they are the same increment a counter. Then pass the input to the output only if the counter exceeds a threshold. If current and previous sample are ever different, reset the counter. That way you can compare the previous samples for the previous billion cycles if you wanted to without needing to store the previous billion samples. It goes without saying that every time you are finished comparing current and previous sample, you update the previous sample with the current sample.
And like, all signals coming into your FPGA that are not synchronized to your FPGA's clock, do not forget to run them through a chain flip-flops before doing ANYTHING (including debouncing) with them.