As you may recall, in an earlier blog from two weeks ago, I put some focus on switch de-bounce. I used a pretty standard methodology: (1) Detect a changing edge, (2) Start a delay timer, and (3) When the delay is done, read the switch value.
I've used this methodology before in discrete hardware and in software. It's not as absolute as I would like, but it works. I got some good feedback on that blog. Paul reminded us of the dangers of static and other risky-for-an-expensive-FPGA-chip issues, as well as the potential costs of using the FPGA for de-bounce as opposed to external hardware. Both of those make a lot of sense. The cost issue has a lot of facets. First, some FPGAs are really expensive. In other cases, the logic used to de-bounce might consume enough of the programmable fabric to push you up to a larger chip.
But I just have my FPGA development boards for the moment, so I'll continue to perform my switch de-bouncing activities in programmable fabric for a while. Just keep these factors in mind when you are designing permanent hardware.
All Programmable Planet member Rfindley pointed out that the common methodology, as I used it, can cause annoying delays for users. We might describe this as a balance between "switch settling time" and "user un-settling time." I certainly get annoyed at systems that have noticeable delays in key presses. His suggestion was to take the switch value at the first pulse. Then run the delay. That way, the user gets an instant result and most or all of the delay will be used up before the user tries a key press again. I like the idea, so I'm re-visiting de-bounce from that perspective.
I've returned to my Spartan 6 LX9 board so I can observe the signals with the ChipScope virtual logic analyzer. I've simplified my prior example for clarity, down to just one switch input and one LED output (the LED doesn't blink this time).
In a stable state, the value at the input of my de-bounce circuit matches that of the output. As soon as the input state changes, I will set the output value to match and start the delay timer. During the delay period, I will ignore any additional changes on the input. That seems straightforward enough, so here's the code for my leading-edge de-bounce function (click here to see a larger, more detailed version of this image).
jandecaluwe 1/29/2013 2:29:36 PM User Rank Blogger
Re: My own take on a debounce circuit
@Garcia "I understand (correct me if necessary, please!) that MyHDl code can be directly executed (simulated?) in any Python shell, without the need of using "toVerilog", "toVHDL" or similar functionalities."
Yes - it has a simulator (class Simulation) that you use to simulate MyHDL descriptions, much like you would simulate Verilog or VHDL. As Python/MyHDL are "dynamic" languages, the run-time / simulation is very important to develop/debug your design - so you should really use this before attempting things like conversion. The conversion has taken a lot of work - but it is only there so that is straightforward to get a MyHDL design into a traditional design flow.
jandecaluwe 1/29/2013 2:20:37 PM User Rank Blogger
Re: My own take on a debounce circuit
@Karl "in blocking assignments, the last one wins"
Sorry to be picky, but that is not quite right. It is in nonblocking assignments that "the last one wins" when they are executed sequentially. What this means is that the values assigned in intermediate assignments will never ever be seen - they are simply unaccessible regardless of where you refer to the variable.
With blocking assignments, "every assignment wins" as with traditional variables: the assigned value is immediately available and accessible by referring to the variable.
jandecaluwe 1/29/2013 2:11:42 PM User Rank Blogger
Re: My own take on a debounce circuit
@Tobias "for clocked always blocks, some guys also recommend to use
lhs <= #1 rhs;
to avoid race conditions in Verilog."
For RTL level coding, this is overkill and dubious style.
Background: a long time ago (20 years), Verilog did not have nonblocking assignments (<=), but only blocking assignments (=). In that case, one way to avoid nondetermism is to add delay specs (#1) like above. (#0 would work also). This was rightly considered an ugly hack. For that reason, nonblocking assignments were introduced, as a clean way to guarantee nondeterminism in zero-delay RTL modeling.
jandecaluwe 1/29/2013 2:05:16 PM User Rank Blogger
Re: My own take on a debounce circuit
@Garcia "So HDL may be used in both hardware description and sequential general purpose programming... is this correct?"
Mm, theoretically yes, but that's not how I think about it - for true general purpose programming nothing beats a true general purpose language. Rather, it is a mistake to think that just because "hardware is concurrent", HDLs should offer concurrent semantics only. A sequential description can be a much more effective and straightforward way to describe a hardware function than a set of concurrent statements, that's all.
"I mean... can I use MyHDL for general purpose programming?"
Again, it's the other way around I think. Python is excellent for general purpose programming - MyHDL simply is one of its special purposes :-) because it is implemented as a Python package.
jandecaluwe 1/29/2013 1:56:56 PM User Rank Blogger
Re: My own take on a debounce circuit
@tomii "Did I get that right?"
I think you got it now. The easiest way to remember this, I think, is that blocking assignments behave exactly as traditional variables in programming languages. So they are the easy case - nonblocking assignments are special.
@tomii: I think you are right. There has been tons of discussion and a lot of comparing Verilog to vhdl for signal assignments etc.
As an over simplification based on the "in blocking assignments, the last one wins" the sequence of blocking assignments kind of gives the programmer a way to express logic in the style of programming languages and the simulator will show the sequence. Synthesis extracts the logic function and assigns the value to the flop.
Non-blocking assigns result in a reg/ff for each <= operator and it may take an extra clock cycle for the result to appear.
So PB_IN is input to a reg that exists in name only and actually becomes the din to the real clocked flop. -- so yes, PB_IN propagates thru the first "reg" and becomes the input to the "real" reg.
@Jan: "HDLs offer both concurrent and sequential semantics"
So HDL may be used in both hardware description and sequential general purpose programming... is this correct? (I've used GHDL for some testing...)
I've just discovered Python, and I've found a very powerfull and flexible tool with it. In this way, your MyHDL flow seems very, very interesting!!
I understand (correct me if necessary, please!) that MyHDl code can be directly executed (simulated?) in any Python shell, without the need of using "toVerilog", "toVHDL" or similar functionalities.
I mean... can I use MyHDL for general purpose programming? (in addition to hardware description)
By the way, your "MyHDL: Why Do We Need Signal Assignments?" post is very enlightening!! I hope more of these backward references in the future, as they are very interesting for APP newcomers like me.
I am using my lunch break, today, to take the Alterra class referenced above. I see that my understanding of blocking vs. non-blocking was wrong (and perhaps somewhat reversed).
Because the blocking statements wait for one another in execution, I assumed that they were needed to ensure that the flops were updated individually. I now see that I had that backwards, that by using blocking statements, it appears that the PB_IN value propagates al the way through almost immediately.
jandecaluwe 1/29/2013 11:10:45 AM User Rank Blogger
Re: My own take on a debounce circuit
@tomii "I mean, this is hardware, so everything is concurrent, right?"
No, this is not hardware - this is a Verilog description that can be synthesized to hardware. The language has a value and semantics of its own that you will have to master - no escape.
HDLs offer both concurrent and sequential semantics. In Verilog, always blocks are concurrent, but the code within them is executed sequentially. If you look at your code and my comments from this perspective, I believe things will become clear.
One solution may also become clear now - just put the shift register code below the case in the always block. This will be much closer to what you want - in behavior and therefore also after synthesis.
Another solution would be to use nonblocking assignments (<=) for all your assignments. These are still executed sequentially, but their semantics are special, so that their behavior appears concurrent. To understand the background of all this, may I refer to my blog post on the subject:
Duane has decided that the time is ripe to get his ZedBoard bolted onto his robot with a Linux distribution up and running. That was the ultimate plan anyway, so why wait?
To save this item to your list of favorite All Programmable Planet content so you can find it later in your Profile page, click the "Save It" button next to the item.
If you found this interesting or useful, please use the links to the services below to share it with other readers. You will need a free account with each service to share an item via that service.