Forum Discussion
11 Replies
- Altera_Forum
Honored Contributor
Sure, I've written a few of these. They aren't that complicated. You should try hammering one out on your own first. It is quite educational that way.
If you run into trouble with your code, feel free to ask for help. (Posting your code is helpful for us to debug) - Altera_Forum
Honored Contributor
A related concept is estimating the clock frequency of your 'other' clock relative to your reference. For example, lets say you have a 50MHz on-board clock. Think about how you would use that to estimate the frequency of the other clock source.
As Kosh suggests, have a crack at it, and come back with code and questions. Cheers, Dave - Altera_Forum
Honored Contributor
Here is some code for discussing.
Simulation works fine, but I am not sure if there are any pitfalls.entity CLOCK_CHECK1 is generic ( gi_MAX_CNT : integer := 3 ); port ( i_NCLR : in std_logic ; -- global /clr i_CLK_REF : in std_logic ; -- reference clock i_CLK_TBC : in std_logic ; -- clk 2 b checked o_MISS_CLK : out std_logic -- ); end CLOCK_CHECK1 ; architecture A_CLOCK_CHECK1 of CLOCK_CHECK1 is signal s2_NRES_CLK_H : std_logic_vector(1 downto 0) ; signal s2_NRES_CLK_L : std_logic_vector(1 downto 0) ; signal si_CNT1 : integer range 0 to gi_MAX_CNT ; begin SYNC1: process(i_CLK_REF,i_NCLR,i_CLK_TBC) begin if i_NCLR = '0' or i_CLK_TBC = '0' then s2_NRES_CLK_L <= (others => '0') ; elsif i_CLK_REF'event and i_CLK_REF = '1' then s2_NRES_CLK_L <= s2_NRES_CLK_L(0) & '1' ; end if; if i_NCLR = '0' or i_CLK_TBC = '1' then s2_NRES_CLK_H <= (others => '0') ; elsif i_CLK_REF'event and i_CLK_REF = '1' then s2_NRES_CLK_H <= s2_NRES_CLK_H(0) & '1' ; end if; end process SYNC1; CNT1: process(i_CLK_REF,i_NCLR,s2_NRES_CLK_H(1),s2_NRES_CLK_L(1)) begin if i_NCLR = '0' or (s2_NRES_CLK_H(1) = '0' and s2_NRES_CLK_L(1) = '0') then si_CNT1 <= 0 ; elsif i_CLK_REF'event and i_CLK_REF = '1' then if si_CNT1 < gi_MAX_CNT then si_CNT1 <= si_CNT1 + 1 ; end if; end if; end process CNT1; REG1: process(i_CLK_REF,i_NCLR) begin if i_NCLR = '0' then o_MISS_CLK <= '0' ; elsif i_CLK_REF'event and i_CLK_REF = '1' then if si_CNT1 = gi_MAX_CNT then o_MISS_CLK <= '1' ; else o_MISS_CLK <= '0' ; end if; end if; end process REG1; end A_CLOCK_CHECK1 ; - Altera_Forum
Honored Contributor
It looks like you have a reasonable idea by making use of counters for your detection. My concern with the current design is that it uses 2 clock inputs to the same process. Timing issues can (and most likely will) occur resulting in potentially incorrect behavior. While I know that it is perfectly acceptable to have more item in the sensitivity list (in the right situation), I would suggest trying to restrict yourself to a reset signal and a single clock (per process). Multiple processes (as you have done) are just fine.
Something else that may help you generate code would be to draw out the design you want to implement using D-flip flops (with 1 clock and 1 reset). Once you have done this, it shouldn't be too bad to write your VHDL to match your diagram. - Altera_Forum
Honored Contributor
--- Quote Start --- Here is some code for discussing. Simulation works fine, but I am not sure if there are any pitfalls. --- Quote End --- Try synthesis too. A simulator will let you do anything that is valid in the language. A synthesis tool will generate additional warnings related to whether design is practical in hardware. When you have multiple clocks, you need to be concerned about clock domain crossing logic. For example, lets say you have a way of reading the counters from the 50MHz domain, eg., you have a Qsys system in that domain. Here's some suggestions; 1) Generate an enable pulse in the 50MHz domain, eg., use a counter to generate a signal that goes high for say 100ms and then low. Or just manually assert a signal high and then low, and have a counter that counts how long you managed to assert the signal. This works nicely, as in software you can simply code; - write to enable register (set the enable bit) - delay 100ms - write to enable register (clear the enable bit) - read the counter to see how many 50MHz clocks the pulse was asserted 2) Synchronize the enable pulse across to the other clock domain. 3) Use the synchronized pulse to enable a counter in the second clock domain. That counter is clocked by your external clock source. 4) (Optional) Using the enable pulse, generate a handshake back into the other clock domain. So long as you read the two counters when the enable pulse is deasserted, you do not need to worry about clock domain crossing logic for the counter with the external clock source. As Kosh comments, sketch out the circuit components, and a timing diagram, then get it working in Modelsim, and try a synthesis test in Quartus. Cheers, Dave - Altera_Forum
Honored Contributor
Synthesis works fine, too.
Maybe I must explain the code. There is just one clock, that is used as "clock", the reference clock. The clock to be observed is used for asynchronous resetting only. First, there are two synchronizing stages clocked by the reference clock to detect if the clock to be observed is stuck at 0 or stuck at 1. The counter counts if there is no action on the clock to be observed. And finally a flag is set, if the counter reaches its maximum value. So I haven't done a lot of asynchronous resetting yet, I am looking for a way to verify this, beyond simulation and just running it. - Altera_Forum
Honored Contributor
--- Quote Start --- The clock to be observed is used for asynchronous resetting only. --- Quote End --- That is not a good choice. An Asynchronous reset must still meet reset recovery and removal timing requirements. That is why a reset synchronizer is recommended on your reset input into each and every clock domain. Cheers, Dave - Altera_Forum
Honored Contributor
--- Quote Start --- The clock to be observed is used for asynchronous resetting only. --- Quote End --- And it passes a traditional reset synchronizer to obtain reset recovery time. - Altera_Forum
Honored Contributor
--- Quote Start --- And it passes a traditional reset synchronizer to obtain reset recovery time. --- Quote End --- Huh? I can't parse this. In your code above, you are using i_CLK_TBC as the reset in a process clocked by i_CLK_REF. You do not have any logic that synchronizes i_CLK_TBC to i_CLK_REF. If i_CLK_TBC and i_CLK_REF are similar frequencies, then there is no way you can use a synchronizer. The solution is to use something slower than the clocks and synchronize that. That 'something' can be a counter enable control. That same enable can be synchronized between the two clock domains, i.e., generated in one clock domain and synchronized into the other. You then enable two counters in the two clock domains, disable the counters, and read their counts. From the two counts, you can estimate clock frequency. Cheers, Dave - Altera_Forum
Honored Contributor
A diagram is attached to clarify code.
--- Quote Start --- If i_CLK_TBC and i_CLK_REF are similar frequencies, then there is no way you can use a synchronizer. --- Quote End --- Why? Assume it is the same clock, then the second flipflop in the synchronizer stage is never set. In my opinion faster clocks are no problem, as long as the low time of the clock to be observed satisfies reset pulse width. And for slower clocks the generic of the counter must be increased.