Sequentially syncrhronous

Sorry, Guys. We're not quite done yet with the quadrature encoder. I tried to rewrite it as a synchronous process. The behavioral sim shows it working as intended. The post-route sim and onboard test don't work. 'debouncing' never changes state in the sim. The leds don't sequence when I twist the magic knob.

Can someone please look at the following and comment? I suspect it may be a mistiming on setting a_prev and b_prev. a_prev and b_prev are the sampled states of 'a' and 'b' during the previous clock. The intended function is that we test for a change in 'a'. If it's an active-edge change, it updates the count according the direction indicated by 'b'. The other edge of 'a' simply debounces to skip the noise. The next change in 'b' cancels the debounce.

In general, is it always this difficult and fraught with peril? I write >2000 lines/month in C++ with only minor misspelling mishaps. These 50 lines have caused me more gray hairs than many whole systems.

Also, is there a way to tell XST to not treat reset as a clock? I haven't fully read up on configuration, having spent way too much time on this little time waster.

Last, .... is this really worth pursuing? I've been programming for 25 years, and know that the greatest leassons come after the greatest pain. But there's also good pain, and just senseless injury. Is this not a suitable first Zen parable to contemplate? I'm goaded forward by the belief that there's a good lesson on synchronous systems lurking as the punchline.

(If it matters, the target is a Spartan-3A DSP starter kit board. ISE 10.1 tools.)

Thanks. Mike.

===================================================== library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;

------------------ entity q_decode is Port ( a : in STD_LOGIC; b : in STD_LOGIC; clk : in STD_LOGIC; rst : in STD_LOGIC; leds : out std_logic_vector(7 downto 0)); end q_decode;

architecture Behavioral of q_decode is signal debouncing : STD_LOGIC := '0'; signal a_prev, b_prev : STD_LOGIC := '0'; signal a_start : STD_LOGIC := '0'; signal count : std_logic_vector(3 downto 0) := "1001"; begin process (clk, rst, a, b) begin if (rst = '1') then a_start

Reply to
MikeWhy
Loading thread data ...

g

This is always a symptom of a timing problem. In your particular case I suspect the timing of 'a' and 'b' relative to clk is not meeting the setup/hold time requirements of the device (from your report file). The signals 'a' and 'b' should be brought into only one flop, the output of that flop should be fed into a second flop, the output of that second flop can then be reliably used wherever you currently have 'a' and 'b'.

lines

Hardware design (even if written in a software like language such as VHDL or Verilog) is not the same as software. You can be well skilled in the one discipline and at the same time be unskilled in the other.

What makes you think that it is using reset as a clock?

ut

The punchline might be static timing analysis. Signals don't just 'happen' when you want them to, you need to guarantee by design that they arrive at the proper time relative to the clock.

Kevin Jennings

Reply to
KJ

I like Ray's process here:

formatting link
I've added an entity here:
formatting link
RTL view looks good, but untested.

How long did your first significant C++ project take?

-- Mike Treseler

Reply to
Mike Treseler

Instead of posting code and asking us to look at it, why don't you debug the simulation??? That is what simulations are for. If you said it worked in pre and post layout simulation, but failed on real hardware, then it would be a sticky problem that could justify asking help. But if it is failing in simulation, you can dig in and see exactly why it is failing.

I am very surprised that this is working in pre-layout sim and failing in post. That is usually a timing problem and I can't imagine that you have any timing problems. Although the synchronization issue that KJ mentioned is very valid.

To simplify reading your code you might want to break out the different functions. Debounce is normally something done separate from the state machine you are implementing. So put it in a separate process and use a separate signal to drive the decoder process. Then you have a nice clean signal you can look at to see if the debounce process is working correctly.

I am also not too sure of your decoder algorithm. It is a bit hard to read because of the number of indents and the formatting in this forum, but it looks like nothing is done with b transitions unless they are preceded by an a transition. I don't think that is an optimal approach for a decoder, but maybe this is because you want to handle higher speeds. But if you are getting transitions faster than the bounce settles, I don't think the encoder can be decoded. So none of this is clear to me.

Rick

Reply to
rickman

This very well could be a timing issue but another possible cause of this could be the writing of simulatable code but not synthesizable code. Looking at the code, I see the signals a and b in the sensitivity list of the process which could cause the else statement to get evaluated asynchronously in simulation however for synthesis, the sensitivity list is likely ignored (generally with a warning) and thus processed differently. I suggest removing the a and b signals from the sensitivity list and see if the behavioral simulation still works. My guess is that may reveal your issue however if that does not, then I do suggest looking more closely at the synthesis logs as well as timing analysis to ensure it is not another synthesis mis-match issue or timing issue.

It is all what you are used to. I can not write C++ worth a lick so it would likely take me a long time to write a program using it however I feel I am very proficient with VHDL and Verilog.

I imagine you are referring to XST using a global buffer for the reset signal. In general this should not cause any issues and many times can be the right thing to do but if you want to go to prevent that behavior, tell XST you want an IBUF on the reset signal by adding the following attribute:

attribute BUFFER_TYPE : string; attribute BUFFER_TYPE of rst: signal is "IBUF";

This will force it to use a regular I/O instead of a global buffer.

Hope this helps and do not get too discouraged. If you are just learning, I could also suggest you try Verilog over VHDL. I am not trying to start the holy wars of languages but many do feel it is less of a leap from C to Verilog than VHDL. Again, I am not trying to start a language debate so please leave do not let my statement start one.

-- Brian

Reply to
Brian Philofsky

Having 'a' and 'b' in the sensitivity list is not the problem. The structure of the code is process(...) begin if (rst =3D '1') then ...assignements here elsif (clk'event and clk =3D '1') then ...assignements here end if; end process;

There are no assignments to anything outside of the if statement. That if statement is of the form for flops with async presets/resets. Having 'extra' signals in the sensitivity list will not result in any difference between simulation and synthesis. If it does, then contact the synthesis tool provider and submit a bug report.

KJ I suggest removing the a and b signals from the

50 lines

't

. But

le

Reply to
KJ

This is always a symptom of a timing problem. In your particular case I suspect the timing of 'a' and 'b' relative to clk is not meeting the setup/hold time requirements of the device (from your report file). The signals 'a' and 'b' should be brought into only one flop, the output of that flop should be fed into a second flop, the output of that second flop can then be reliably used wherever you currently have 'a' and 'b'.

===================

'a' and 'b' are driven by a hand turned rotary encoder.

I tried buffering them into flops with concurrent statements, a_next and b_next, and used a_next and b_next internally. This caused 'a' and 'b' to not get routed at all, along with all logic associated with them. The circuit was reduced to only those parts lighting the leds.

What makes you think that it is using reset as a clock?

====== The synthesis report:

Number of GCLKs: 2 out of 24 8%

...

Clock Information:

------------------

-----------------------------------+------------------------+-------+ Clock Signal | Clock buffer(FF name) | Load |

-----------------------------------+------------------------+-------+ sys_rst_pin | IBUF+BUFG | 1 | sys_clk_pin | BUFGP | 7 |

-----------------------------------+------------------------+-------+

Asynchronous Control Signals Information:

----------------------------------------

-------------------------------------------------------------+---------------------------+-------+ Control Signal | Buffer(FF name) | Load |

-------------------------------------------------------------+---------------------------+-------+ sys_rst_pin | IBUF | 5 | Inst_q_decode/a_prev_and0000(Inst_q_decode/a_prev_and00001:O)| NONE(Inst_q_decode/b_prev)| 2 | Inst_q_decode/a_prev_and0001(Inst_q_decode/a_prev_and00011:O)| NONE(Inst_q_decode/b_prev)| 2 |

-------------------------------------------------------------+---------------------------+-------+

I suppose if I understood what that said, a_prev_andxxxxx are the cause of my difficulties.

Reply to
MikeWhy

A fair comment; I often give similar advice.

I removed the rst handling, and now it simulates post-route, but still fails in hardware. Could it be the ports? They're configured LVTTL with PULLDOWN. The encoder switches are normally-open, grounded, and pulled to VCC when they close.

What's really troubling is that something so apparently simple can be unstable. I wasn't asking for debug help so much, but help identifying what constructs are stable when synthesized and which are prone for trouble. I also wasn't expecting trouble.

The synthesis report now says this: "No asynchronous control signals found in this design." The only change was to remove rst.

Examining the post-route sim gives no hint where it can be going wrong, or what might be borderline. Debounce is a flipflop with clock-enable, presumably gated to flop state appropriately. I was concerned about the c-e relationship to storing the state for comparison in the next clock cycle, but assignment to a_prev and b_prev occur after the clock-enable. It all looks as intended.

It turns out that debouncing _is_ the state machine. It drives the counter up or down 1 count, which in turn drives the lookup decoder. It was easier, and I thought just as clear, to write the single line increment/decrement inline.

On the clock rising edge: Check for state change on 'a' if we're not debouncing. If 'a' changed state, ignore further changes (debouncing). If the change is a rising edge on 'a', 'b' is the direction of movement. Increment or decrement the count accordingly. Otherwise, we're already debouncing. Clear debounce on the next 'b' change.

It would be more clear to restructure it explicitly as a FSM with the 2 states. I will do so.

Reply to
MikeWhy

ls

.
t
e
,

Is somebody trying to re-invent the wheel? Haven't we been through this in a seemingly endless thread? Didn't I point out two perfect and compact solutions? How much effort do we intend to waste on such a clearly-defined non- problem ? Peter Alfke

Reply to
Peter Alfke

Most likely...but also most likely not in order to invent a better wheel but to learn.

Yes

Others posted solutions as well, don't take all the credit.

If you feel that you're wasting your time, then perhaps you should choose not to do that.

KJ

Reply to
KJ

========= It isn't so much the reinvention of the wheel, Peter, but learning to hammer and chisel the stone round. It should have been a short exercise, but there are timing conflicts where I expected none. Doesn't it behoove the student to find the flaws in his thinking and approach?

I thank you for your elegant solution, which I have put away for later study.

I don't know what I'm doing wrong, and why my solution is so susceptible to problems. Hence, the questions.

Regards, Mike.

Reply to
MikeWhy

Then your code must have been suspect.

You should NEVER drive the Quad pins, into anything other than sampling FF's (unless you are trying an async design :)

Only the outputs of sampled signals should be in your state flows.

-------------------------------------------------------------+---------------------------+-------+

-------------------------------------------------------------+---------------------------+-------+

-------------------------------------------------------------+---------------------------+-------+

Strange looking report, - Try re-targeting to a CPLD, and look at the report equations. CPLD reports are more readable as they have wider-and terms, and less tool generated nodes.

So, they are a good way to make sure you, and the tools, are on the 'same page'!

-jg

Reply to
Jim Granville

This only counts once per 4 quadrants, or one quarter of the possible count rate. I presume that was your intention ?

-jg

Reply to
Jim Granville

To me, both examples look to have an error, in confusing an edge with a direction.

See Peter/Ken's Tested example, for separate rotary_event, rotary_right code.

-jg

Reply to
Jim Granville

Timing analysis is not about how often things change, but when do they change relative to whatever it is that samples them. You have three asynchronous inputs to your design (rst, a, b). What that means is that if I were to ask you when does rst change in relationship to the clock your answer would be I dunno (or something more grammatically correct). The same would be true for 'a' and 'b'.

The problem is you then use these signals directly as inputs into logic that gets clocked. The propogation delay from the input pin through whatever logic there is to EACH flip flop will be different so when the clock comes along some of the flops will see the 'new' value others will miss it. On the next clock cycle, since some of the flops may have changed state, the net result of the logic may be different. That's why you need to synchronize everything to the clock first and then only use the synchronized signals. In your case, make some new signals like rst_sync, a_sync and b_sync where you bring rst, a and b in and perform no logic at all, just clock them into a flop (i.e. with a clocked process).

Now change your logic to use a_sync instead of 'a', b_sync instead of 'b' and rst_sync instead of 'rst'. This means lines like this... if (rst = '1') then if (a /= a_prev) then etc.

will change to this... if (rst_sync = '1') then if (a_sync /= a_prev) then etc.

Make sure that the ONLY place you use 'rst', 'a', or 'b' is to generate 'rst_sync', 'a_sync' and 'b_sync'. Reset the temptation to violate this anywhere for any reason.

Simulate and make sure things still function.

Well, for starters you can't buffer them into flops with concurrent statements unless you did this. rst_sync > fully read up on configuration, having spent way too much time on this

This is not a concern. It is simply saying that it's using a buffer to drive the reset signal because it has a lot of internal loads, just like the clock does. It's unfortunate that it says 'clock buffer' when it means something more like 'big honkin buffer that can drive a lot of loads'.

Kevin Jennings

Reply to
KJ

Not only is the a and b not a problem, the a in the sensitivity list is *required* for proper simulation unless the simulator has the smarts to fix problems with the sensitivity list.

Notice that there are assignments in the if (rst ='1') clause that have a on the right hand side. Since this is not in the clocked portion of the process, this is a concurrent assignment and the process must run when either rst or a change.

If the reset signal is being run on a global clock line, it is because your code does not allow the GSR to be used (a global net dedicated to the reset function). You are resetting to a signal value instead of a fixed value, so the set/reset signals have to be brought out to the routing matrix to accommodate that. It is actually preferred to use the clock nets for such a reset since your reset likely has a high fanout and it will not be able to meet a fast timing spec any other way. This also saves a lot of routing resources if you have spare clock lines.

But

Can you say what your clock rate is? For the most part, speeds of below 25 MHz are pretty easy to meet. Speeds of 100 MHz are a lot tougher. Speeds in the middle depend on the logic and the density. As you get above about 70% or 80% full, it gets harder to meet faster timing.

The one problem that most newbies have, especially if they come from a software orientation, is thinking of HDL as software. HDL stands for Hardware Description Language and that is how it works. It describes hardware. If you try to write it like software, you most likely won't care for the hardware that results, if it produces hardware at all. Every construct I write I picture in terms of the hardware it will generate as well as the behavior it has.

Rick

Reply to
rickman

Yeah, that was what I saw too. A quad decoded should be able to increment on *each* edge of each signal. Both rising and falling edges have meaning and the direction is always indicated by the combination of edge direction and state of the other signal.

I see the best approach as two state machines. One is the debouncer of *each* signal, a and b which also produces outputs for "edge of" each signal. The other is the quad decoder that has to consider the inputs a, b, a edge and b edge. Your combined state machine seems awkward and I'm not even sure it works. If you turn past a rising edge on a, and then reverse, the same spot on the encoder will produce a falling edge on a which is ignored. It won't produce a rising edge on a until you turn it back half a cycle. If you don't reach that half a cycle before reversing again and pass the same rising edge of a it will count up a second time! This is just plain wrong! Consider that the decoder has to distinguish eight different combinations. There are four different points in time and two directions.

a __1____2__++3++++4++__1____2__++3++++4++__1__ b __1__++2++++3++__4____1__++2++++3++__4____1__

View the above in a fixed width font. See how there are four distinguishable states? You need to detect the four states of the encoder. In any given state you will see a transition on one of the two signals. Which signal transitions tells you which direction you are headed.

The point of a quad encoder is to make the presence and direction of changes clearly distinguishable. In fact, unless the bouncing is fast compared to your clock rate, you don't even need to debounce the encoder. If you get two rising edges and a falling edge between, it should count up twice and down once and automatically debounce! Do use a single FF for each signal a and b before you use them in the FSM. An async signal may be seen in different states by the multiple FFs in a FSM. That will result in very bad behavior. Metastability can also be an issue, but I expect this just won't be apparent in your case. Still, even passing the signal through one FF will virtually eliminate metastability for clock rates below 25 MHz unless you really push the logic. Metastability is removed by the slack time between FFs.

I need to do my own work, but it is boring me at the moment. I'm just not quite interested enough to try to figure out the other problems in your code... :^( I was not in on the other thread I guess you started, but it looks like there was no shortage of suggestions of how to write this better. If you were here, I would be happy to discuss this with you, but writing is just not as much fun. (you wouldn't know by the length of this post...)

Sometimes computer coding is a bit like writing (literary, that is). Trying to fix something that is inherently bad does not really teach anything. Instead there are times you need to toss out what you have done and consider the work of others. If someone has given you code or pseudo-code that should work, then you might want to try implementing that. I bet when you have something that works and you understand it, you can better see the issues with your code.

Rick

Reply to
rickman

Now that I have looked at it, this seems so frigging simple that I am going to try to write it on the fly!

right_way : process (clk, rst) begin if (rst = '1') then old_a

Reply to
rickman

XST complained that they were missing from the sensitivity list and warned that it was proceeding as though they were there. So I added them.

Aha. Thanks. That was lucid enough to understand.

I missed the import of this the first time through. I'll make note of it for the future. It added the clock buffer even when I used a GPIO line, not just the sys_rst_pin which has special attributes in the config file.

125 MHz. One of the timing reports said the circuit should be able to get 300+ MHz. Alas. It wasn't circuit I intended.

I understand race conditions as they apply to multithreaded software. I imagine the root problem I have isn't too very different here. Slowing down one side to avoid contention isn't the same as preventing it.

Reading the simulation traces was very educational. Debounce is a ff. Upstream logic gates the clock enable to cause it to flop state. I can see how the brief strobe can be missed if the actual gate timing differs from the sim by just a tiny amount. About all I can say at this point is I learned 10 times more this way than if it had all just worked when I typed it in.

I took time away from the keyboard tonight to re-read code from Pong Chu's newbie VHDL book, to find where I had gone astray. There's light at the end of this tunnel. I absolutely have it backwards and inside out on how to protect the synchronous states. It is, as you say, a software habit that doesn't apply.

Reply to
MikeWhy

:) I've said that more than once, on just this alone.

I didn't give much thought to actually taking best advantage of the encoder resolution. The encoder is a hand knob with detents. Reading just one transition per detent serves this exercise better, to demonstrate proper debouncing. However, I can see room for a third try, but likely not for a few weeks or months. At which point, it should be entirely trivial. ;)

Reply to
MikeWhy

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.