realazing a watch

M

Manfred Balik

Please can someone help me:

I have realized a watch viewing nanoseconds and seconds from a 31.611 MHz
clock (it's the only one in the design).
For high precision I count in femtoseconds - out of them, I calculate
nanoseconds and seconds.

Unfortunately the code I wrote is to slow in the Altera APEX 20KE I use

Please can someone help me to improve the code
Thanks, Manfred


LIBRARY ieee;
USE ieee.std_logic_1164.all;

ENTITY timestamp_counter IS
PORT
(
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
time_sec : OUT STD_LOGIC_VECTOR(0 to 30);
time_nanosec : OUT STD_LOGIC_VECTOR(0 to 29)
);
END timestamp_counter;

ARCHITECTURE timestamp_counter_architecture OF timestamp_counter IS

CONSTANT clock_cycle_femtosec : integer := 31_634_558; -- 1 clock cycle in
femto seconds
-- 31.611 MHz == 31,634 557 590 712 ... ns
-- => Error: -4.09288E-16 s/cycle
-- = -1.2938E-8 s/sec
-- = -7.7628E-7 s/min
-- = -4.65768E-5 s/h
-- = -1.1178432E-3 s/day
-- = -0,408012768 s/year (-0,4091306112 s/leap year ;-))

FUNCTION int2slvect(int_value : INTEGER; size : INTEGER) RETURN
std_logic_vector;
FUNCTION int2slvect(int_value : INTEGER; size : INTEGER) RETURN
std_logic_vector IS
VARIABLE result : std_logic_vector(0 TO size-1);
BEGIN
FOR i IN 0 TO size-1 LOOP
IF ((int_value/(2**i)) REM 2) = 0 THEN
result(i) := '0';
ELSE
result(i) := '1';
END IF;
END LOOP;
RETURN result;
END int2slvect;

BEGIN

timestamp_counter_process : PROCESS (clk,reset) IS
VARIABLE sec: integer RANGE 0 TO 2_147_483_647;
VARIABLE nanosec: integer RANGE 0 TO 1_000_000_050;
VARIABLE femtosec: integer RANGE 0 TO 33_000_000;
VARIABLE read_timespec_prev: std_logic;
BEGIN
IF reset = '1' THEN
sec := 0;
nanosec := 0;
femtosec := 0;
read_timespec_prev := '0';
timespec_sec <= (OTHERS => '0');
timespec_nanosec <= (OTHERS => '0');
time_sec <= (OTHERS => '0');
time_nanosec <= (OTHERS => '0');
ELSIF clk'event AND clk = '1' THEN
femtosec := femtosec + clock_cycle_femtosec;
IF femtosec > 31_999_999 THEN
nanosec := nanosec + 32;
femtosec := femtosec - 32_000_000;
ELSIF femtosec > 30_999_999 THEN
nanosec := nanosec + 31;
femtosec := femtosec - 31_000_000;
END IF;
IF nanosec > 999_999_999 THEN
sec := sec + 1;
nanosec := nanosec - 1_000_000_000;
END IF;
time_sec <= int2slvect(sec,31);
time_nanosec <= int2slvect(nanosec,30);
END IF;
END PROCESS timestamp_counter_process;

END timestamp_counter_architecture;
 
M

Mike Treseler

Manfred said:
I have realized a watch viewing nanoseconds and seconds from a 31.611 MHz
clock (it's the only one in the design).

25 bit tick counter: 2**25 = 33,554,432
6 bit seconds counter with clock enable: 2**6 = 64
6 bit minutes counter with clock enable: 2**6 = 64
etc. etc.

At tick count 31,611,000 enable a seconds count
and a synchronous clear of ticks.

At seconds count= 60, enable a minutes count
and a synchronous clear of seconds.

etc, etc.

-- Mike Treseler
 
N

Neo

I dont understand this question. How can you measure time in
nanoseconds and femtosseconds when the clock freq itself is just
31MHz.

Neo
 
H

Hal Murray

I dont understand this question. How can you measure time in
nanoseconds and femtosseconds when the clock freq itself is just
31MHz.

Just multiply by the right scale factor. Or add N rather than 1
each time the clock ticks.

Suppose I had a clock running at 100 MHz and I wanted time in
ns. Just add 10 each time the clock ticks.
 
H

Hal Murray

I have realized a watch viewing nanoseconds and seconds from a 31.611 MHz
clock (it's the only one in the design).
For high precision I count in femtoseconds - out of them, I calculate
nanoseconds and seconds.

You can make big adders/counters go as fast as you want. google for
carry-save-adder or carry-save-counter

If all you want is seconds, I'd make a big adder and bump it by X each
clock tick. The top bits would be seconds. Adjust X to give the right
answer. Pick the number of fractional bits to match the accuracy of
your crystal.

If you need seconds and nanoseconds things get more complicated. Are
you feeding a display? If so, it might be simplest overall to count/add
in decimal rather then binary. If you only need 10ths/100ths of a second,
I'd probably use a binary adder for the lower bits and a decimal
counter for the rest.

Note that with carry-save you have the possibility for things to get
out of phase. It will "count" 1.9 1.0 2.0. There is a carry pending
on the middle case, but you can't see it. It only lasts 1 clock tick.

You can fix that by adding a pipeline (delay) stage on the lower
digit. (and more delay stages as needed) Or ignore that if it
doesn't matter for your application. (If you are just driving
a display, your eye will never notice.)


ELSIF clk'event AND clk = '1' THEN
femtosec := femtosec + clock_cycle_femtosec;
IF femtosec > 31_999_999 THEN
nanosec := nanosec + 32;
femtosec := femtosec - 32_000_000;
ELSIF femtosec > 30_999_999 THEN
nanosec := nanosec + 31;
femtosec := femtosec - 31_000_000;
END IF;
IF nanosec > 999_999_999 THEN
sec := sec + 1;
nanosec := nanosec - 1_000_000_000;
END IF;

That looks like software rather than hardware. What do you expect
it to synthise into? I suggest designing the hardware (or at least
sketching it out) with pencil and paper. Then write the VHDL to
get what you want.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,405
Messages
2,571,539
Members
48,796
Latest member
shadowoftheunknown
Top