clk divider

S

Schmigz

I am trying to write a clock divider that will be used for input from
a serial port that is outputting data at 115200 baud. This means I
would need a clk that runs at 115.2 kHz. My on board clk is currently
running at 50 MHz (oscillator). One option is to add another clk to
my design using a second oscillator but I would prefer to find another
option since this will drive up costs. Is there an easy way to divide
50 MHz downto 115.2 kHz using VHDL?
 
A

Anders Hellerup Madsen

Schmigz said:
I am trying to write a clock divider that will be used for input from
a serial port that is outputting data at 115200 baud. This means I
would need a clk that runs at 115.2 kHz. My on board clk is currently
running at 50 MHz (oscillator). One option is to add another clk to
my design using a second oscillator but I would prefer to find another
option since this will drive up costs. Is there an easy way to divide
50 MHz downto 115.2 kHz using VHDL?

If you can live with a frequency of 115207 Hz, then you can use a
counter to generate the clock signal. That's pretty easy.

50 MHz gives a cycle time of 20 ns, 115.2 KHz gives aprox. a cycle time
of 8680 ns. A cycle of the ouput clock needs to be 434 times longer than
the input clock, so the output clock can be generated in this way:

process(clk,reset)
begin
if (reset = '0') then
clk_o <= '0';
cnt <= 0;
elsif (rising_edge(clk)) then
if (cnt = 217) then
cnt <= 0;
clk_o <= not clk_o;
else
cnt <= cnt + 1;
end if;
end if;
end process;

I just wrote this of the top of my head, so odds are it's full of
errors. And anyway it doesn't give exactly the right frequency, but if
you need that, then I think you will have to use DLL's or some other
stuff to generate it.

-- Anders
 
J

jussi l

hi,

the ration between the two frequencies is pretty close to 434 if I
calculated correctly. So, keep the baud clock low for say 216 clock cycles
and high for 217 cycles. Then repeat. Addtional accuracy can be gained by
letting every mth clock cycle have 216-218 cycles of the fast clock. So,
basically, all you need is a few counters and a little control...

regards,
juza
 
V

Vladislav Vasilenko

jussi said:
hi,

the ration between the two frequencies is pretty close to 434 if I
calculated correctly. So, keep the baud clock low for say 216 clock cycles
and high for 217 cycles. Then repeat. Addtional accuracy can be gained by
letting every mth clock cycle have 216-218 cycles of the fast clock. So,
basically, all you need is a few counters and a little control...

regards,
juza

It depends on the COM port scills.
Many COM ports operate well when the
frequency error is in range 1-3 %.
Therefore take it easy to keep this frequency precisely.

A.Ser.
 
S

Schmigz

I would like to thank everyone who helped me out. I ended combining
some of the suggestions into my final solution. Here is my final
code. Works well. I actually like this solution because the clock
input is not finalized yet. We have an ideal clock of 50 Mhz so that
is the timing I used, but if for some reason it changes, I only have
to change the two comparison values.

cts is the Clear to Send bit from the serial and ser_in is the data
line.

if(clk'event and clk='1') then
if(cts = '1') then
case cur_s is

when IDLE_S =>
if(ser_in = '0') then
cur_s <= READ_S;
ser_rd_en <= '1';
cnt <= "000000001";
bit_cnt <= "0001";
end if;

when READ_S =>
if(ser_rd = '1') then
case bit_cnt is

when "0001" =>
if(ser_in = '1') then -- Should be start bit
error <= '1'; -- If not set error
end if;

when "0010" =>
ser_buf(0) <= ser_in;

when "0011" =>
ser_buf(1) <= ser_in;

when "0100" =>
ser_buf(2) <= ser_in;

when "0101" =>
ser_buf(3) <= ser_in;

when "0110" =>
ser_buf(4) <= ser_in;

when "0111" =>
ser_buf(5) <= ser_in;

when "1000" =>
ser_buf(6) <= ser_in;

when "1001" =>
ser_buf(7) <= ser_in;
if(tmpcolor = "00") then

when "1010" =>
cur_s <= IDLE_S;
if(ser_in = '0') then -- Should be stop bit
error <= '1'; -- If not set error
end if;


when others =>
cur_s <= IDLE_S;

end case;

bit_cnt <= bit_cnt + '1';

end if;
end case;

-- 50Mhz clk / 115200 baud rate = 434.028
-- Generates high pulse for a single read
-- Every 217 clocks, resets after 434
if(ser_rd_en ='1') then
cnt <= cnt + '1';
if(cnt = "011011001") then -- High for clock 217
ser_rd <= '1';
elsif(cnt > "110110010") then -- Reset after 434
ser_rd <= '0';
cnt <= "000000001";
else
ser_rd <= '0';
end if;
end if;
end if;
 
R

Ray Andraka

Use a phase accumulator approach rather than a divider. That way, you can
set the exact frequency. It will introduce some jitter with a peak
deviation of 1/2 your master clock period. The phase accumulator
(sometimes described as a direct digital synthesizer) is simply a
registered adder with one input coming from its output and the other set
to a constant increment value. The adder output represents a fraction of
a cycle of your desired oscillator. For a square wave output, you use
just the MSB of the output as your clock or as a clock enable. The width
of the adder determines the frequency resolution. The output frequency is

Fo= Fc * N/ (2^bits)

In the case of generating a 115.2Khz clock from a 50 MHz master:

Lets assume you want 0.1% accuracy, which is to say 115.2KHz +/- 115 Hz.
You need enough bits to have at least 230Hz resolution, so

230 = 50,000,000 * 1/(2^bits) tells us we need 18 bits in the
accumulator. 18 bits gives us a frequency resolution of 191 Hz.

Now, find the constant N that provides the 115.2KHz
115200 = 50M * N/2^18 ===> N=604.

plugging that back in you get an output frequency of 115203.9Hz. If you
needed more accuracy, you could increase the width of the accumulator.

signal accum:unsigned(17 downto 0);
begin
process(clk,reset)
if reset='1' then
accum<=(others=>'0');
elsif rising_edge(clk) then
accum<= accum+to_unsigned(604,18);
end if;
end process;
baud_clk<= accum(accum'left);




Now if you want to change the baud rate, all you need to do is change the
constant. The baud_clock is proportional to the constant. The output
taken from the msb of the accumulator is a square wave with approximately
50% duty cycle (there is a little bit of jitter +/- a half master clock
cycle) if the constant results in a non-integer division of the master
clock. That little bit of jitter is quite acceptable for serial comms.
I am trying to write a clock divider that will be used for input from
a serial port that is outputting data at 115200 baud. This means I
would need a clk that runs at 115.2 kHz. My on board clk is currently
running at 50 MHz (oscillator). One option is to add another clk to
my design using a second oscillator but I would prefer to find another
option since this will drive up costs. Is there an easy way to divide
50 MHz downto 115.2 kHz using VHDL?

--
--Ray Andraka, P.E.
President, the Andraka Consulting Group, Inc.
401/884-7930 Fax 401/884-7950
email (e-mail address removed)
http://www.andraka.com

"They that give up essential liberty to obtain a little
temporary safety deserve neither liberty nor safety."
-Benjamin Franklin, 1759
 

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
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top