How do I generate an I²C clock with these specs? - vhdl

I2C clock specifications the clock from fpga is 100MHz and I need to run it at 400kHz, so in order to make 400kHz clock, I divided 100MHz/(2^8)=390625(close to 400kHz)(please tell me a more optimal way for clock dividers) here 8 is the no. of bits, so I made a counter(8 downto 0) and took its 8th(index) bit as my clock for the i2c communication process(vhdl).
please guide me as to how I can generate the required clock.
thank you
signal count:std_logic_vector(8 downto 0);
signal sign:std_logic;
process(clk,rst)
begin
if rst='1' then
count<=(others=>'0');
elsif rising_edge(clk) and rst='0' then
count<=count+1;
end if;
sign<=count(8);
end process;

You can just divide the clk by 250 to get a 400kHz clk. Something along the lines of:
signal count : integer range 0 to 250;
signal clk400 : std_logic;
process (clk100, rst)
begin
if rst ='1' then
count <= 0;
clk400 <= '0';
elsif rising_edge(clk100) then
count <= count +1;
if count = 249 then
count <= 0;
clk400 <= not clk400;
end if;
end if;
end process;
Or, depending on you FPGA and tools, you could use a PLL.

Related

VHDL - Using output of one entitiy as input of another

I am trying to make a basic distance indicating module using ultrasonic sensor. When I dumped the code for the same into my FPGA board(Helium V1.1 developed by IIT-B) all the LEDs in the board started glowing since the clock frequency was too high. So now I am using a frequency divider to reduce my clock speed but I am not getting how to use the output of my frequency divider code as an input to my main code. Can someone help me since this is the first time I am working on FPGA and I dont quite understand VHDL yet?
Code for frequency divider
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity Clock_Divider is
port ( clk,reset: in std_logic;
clock_out: out std_logic);
end Clock_Divider;
architecture bhv of Clock_Divider is
signal count: integer:=1;
signal tmp : std_logic := '0';
begin
process(clk,reset)
begin
if(reset='1') then
count<=1;
tmp<='0';
elsif(clk'event and clk='1') then
count <=count+1;
if (count = 25000) then
tmp <= NOT tmp;
count <= 1;
end if;
end if;
clock_out <= tmp;
end process;
end bhv;
Code to measure distance using ultrasonic:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity ultrasonic is
port(
CLOCK: in std_logic;
LED: out std_logic_vector(7 downto 0);
TRIG: out std_logic;
ECHO: in std_logic
);
end ultrasonic;
architecture rtl of ultrasonic is
signal microseconds: std_logic;
signal counter: std_logic_vector(17 downto 0);
signal leds: std_logic_vector(7 downto 0);
signal trigger: std_logic;
begin
process(CLOCK)
variable count0: integer range 0 to 7;
begin
if rising_edge(CLOCK) then
if count0 = 5 then
count0 := 0;
else
count0 := count0 + 1;
end if;
if count0 = 0 then
microseconds <= not microseconds;
end if;
end if;
end process;
process(microseconds)
variable count1: integer range 0 to 262143;
begin
if rising_edge(microseconds) then
if count1 = 0 then
counter <= "000000000000000000";
trigger <= '1';
elsif count1 = 10 then
trigger <= '0';
end if;
if ECHO = '1' then
counter <= counter + 1;
end if;
if count1 = 249999 then
count1 := 0;
else
count1 := count1 + 1;
end if;
end if;
end process;
process(ECHO)
begin
if falling_edge(ECHO) then
if counter < 291 then
leds <= "11111111";
elsif counter < 581 then
leds <= "11111110";
elsif counter < 871 then
leds <= "11111100";
elsif counter < 1161 then
leds <= "11111000";
elsif counter < 1451 then
leds <= "11110000";
elsif counter < 1741 then
leds <= "11100000";
elsif counter < 2031 then
leds <= "11000000";
elsif counter < 2321 then
leds <= "10000000";
else
leds <= "00000000";
end if;
end if;
end process;
LED <= leds;
TRIG <= trigger;
end rtl;
I am using Quartus for simulating these codes.
welcome to the HDL languages :)
For simulation clock_out is missing from the sensitivity list process(...)
For synthesis/implementation you might need to check all processes as they should be dependent on your clock signal. I've learned it's considered bad practice to use rising/falling edge on other signals than clock signals.
You probably want to go for a pattern something like:
...
-- entity declaration
s : in std_logic;
...
-- architecture declaration
signal s_d : std_logic;
begin
...
process(clk)
begin
if rising_edge(clk) then
-- s_d is s one clock cycle delayed
s_d <= s;
-- detect s transition from 0 to 1 == rising edge
if s = '1' and s_d = '0' then
-- Code dependent on rising edge s
end if;
end if;
end process;
NOTE: s may be an internal signal and is not needed to come from entity. If s is a strobe (1 clock cycle long generated with the same clock) s_d is not needed as there is no need to detect the edge, just the signal state.

Would like someone to double check code for 8bit up counter with enable

I am a novice coder and don't know if what I did was correct so I would appreciate if someone could double check it for me.
So im trying to make an 8-bit up counter with an active-low count enable control signal. The counter should advance to the next count if cten = 0 and stops at the current count if cten = 1. The counter resets into a state that outputs binary 0 and progresses upward on each clock edge when counting is enabled until it reaches 255. It locks in the state producing output 255. I also tried to change the clock to 1Hz clock from a 50MHz clock the is on a FPGA board that will be used to run some instructions (with there being no more than 255 instructions, hence wanting to lock at that number) based off the count value of int_q.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity counter is
port(
clk, rst, cten: in std_logic;
q: out std_logic_vector(7 downto 0)
);
end entity counter;
architecture moore of counter is
signal d,int_q: std_logic_vector(7 downto 0);
signal cnt: integer range 0 to 25000;
signal clk1Hz: std_logic;
begin
-- drive internal Q signal to output signal
q <= int_q;
-- next-state logic: add 1 unless 255, lock at 255
d <= int_q+1 when int_q < 255;
d <= int_q when int_q = 255;
process(clk)
begin
if rising_edge(clk) then
cnt <= cnt+1;
if cnt = 25000 then
clk1Hz <= not clk1Hz;
cnt <= 0;
end if;
end if;
end process;
-- register process
process(all)
begin
if rising_edge(clk1Hz) then
if rst ='1' then int_q <= "00000000";
elsif cten = '0' then int_q <= int_q+1;
else int_q <= int_q;
end if;
end if;
end process;
end architecture moore;
Several issues:
If rst is unasserted on the rising edge of clk1Hz, then int_q will remain in an unknown state.
clk1Hz is never initialized, so the not operation does nothing.
cnt is never initialized, so incrementing it does nothing.
int_q is being driven in 2 places: both inside and outside a process.
signal d is unused, did you want to connect it to q?
You're only counting to 25_000, but if your source clock is 50 MHz, you need to count to 25_000_000.
If you want a synchronous reset, (which given the name "Moore", I bet this is homework), it's good practice to create a new process specifically to internally synchronize that async reset signal to the system clock, maybe through a 2FF synchronizer for one idea.
If I understood the question correctly, this should get you in the ballpark:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity counter is
port(
clk, rst, cten: in std_logic;
q: out std_logic_vector(7 downto 0)
);
end entity counter;
architecture moore of counter is
signal int_q: std_logic_vector(7 downto 0);
signal cnt: integer range 0 to 25_000_000;
signal clk1Hz: std_logic;
begin
-- indicate when at 255
q <= '1' when int_q = 255 else '0';
process(rst, clk)
begin
if rst = '1' then
-- need to assign initial values
clk1Hz <= '0';
cnt <= 0;
elsif rising_edge(clk) then
if cnt = 25_000_000 then
clk1Hz <= not clk1Hz;
cnt <= 0;
else
cnt <= cnt+1;
end if;
end if;
end process;
-- register process
process(rst, clk1Hz)
begin
if rst = '1' then
int_q <= (others => '0');
elsif rising_edge(clk1Hz) then
if cten = '0' then
int_q <= int_q+1; -- rolls over
end if;
end if;
end process;
end architecture moore;
If you want to map this in an FPGA you cannot generate a clock like you do. Clocks are very special signals with strict electrical requirements. If you need a 1Hz frequency clock and the frequency of your master clock is 50MHz there are basically two options:
Use a clock manager/generator hard macro of your FPGA if it has some, and configure it to generate a 1Hz clock from your master clock. Explicitly pass the output through a clock buffer if your tools don't do it automatically.
Do not generate a 1Hz clock, use an enable signal that you assert high once every 50M clock periods. Or use a rescaler and increment your counter only when the rescaler reaches a predefined value.
As the first option depends on your FPGA, your tools, etc. let's investigate the second:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity counter is
generic(freqHz: positive := 50000000);
port(clk, rst, cten: in std_ulogic;
q: out std_ulogic_vector(7 downto 0));
end entity counter;
architecture moore of counter is
signal rescaler: integer range 0 to freqHz - 1;
signal cnt: integer range 0 to 255;
begin
q <= std_ulogic_vector(to_unsigned(cnt, 8));
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
rescaler <= freqHz - 1;
cnt <= 0;
elsif cnt /= 255 then
if rescaler /= 0 then
rescaler <= rescaler - 1;
else
rescaler <= freqHz - 1;
cnt <= cnt + 1;
end if;
end if;
end if;
end process;
end architecture moore;
Remarks:
Use ieee.std_logic_unsigned or ieee.numeric_std but not both. And as noted by #JHBonarius, do not use ieee.std_logic_unsigned at all. It is not standard and deprecated. Use ieee.numeric_std_unsigned, instead.
I added a generic parameter (freqHz) with a default value such that you can easily adapt to different clock frequencies.
The 50Mhz to 1Hz rescaler is decremented instead of incremented because a hardware zero detector is frequently slightly smaller and faster than an arbitrary value detector.
If you do not know the difference between std_logic and std_ulogic, always use std_ulogic, never std_logic (and use std_ulogic_vector instead of std_logic_vector, u_unsigned instead of unsigned...) One day or another you will really need std_logic and this day you will understand the difference, and why you should (almost) never use it. And do not listen to people who tell you that std_logic is more standard or better supported by the tools or whatever. They are wrong. The only exception is your teacher or your boss: even if they are wrong, it might be better to obey.

Is the use of rising_edge on non-clock signal bad practice? Are there alternatives?

I am working on a VHDL design and I have it working, but the code is pretty ugly and the fact that it seems that I am trying to work around the language's design to accomplish my goal makes me feel like something is wrong. I'm pretty new to VHDL, but I have been working on smaller chunks of the project for nearly a month so I have the general idea. However, This part is a bit more complex.
I need a process that will create a one clock period long pulse (LOAD_PULSE) after the rising edge of a signal (END_ADC), but not until 4 clocks has passed from the latest rising edge of that signal (END_ADC) OR the falling edge of a second signal (LVAL).
To accomplish the wait period, I have built a timer module that counts microseconds and periods, here:
entity uS_generator is
generic(
Frequency : integer := 66 -- Frequency in MHz
);
Port (
CLK : in STD_LOGIC;
RESET : in STD_LOGIC;
T_CNT : out integer range Frequency downto 1 := 1;
uS_CNT : out integer range 65535 downto 0 := 0
);
end uS_generator;
architecture behavior of uS_generator is
signal T_CNT_INT : integer range Frequency downto 1 := 1; -- Counter for 1 uS
signal uS_CNT_INT : integer range 65535 downto 0 := 0;
begin
COUNT: process(CLK, RESET)
begin
if RESET = '1' then
T_CNT_INT <= 1;
uS_CNT_INT <= 0;
elsif rising_edge(CLK) then
if T_CNT_INT = (Frequency - 1) then -- Increment one clock early so last rising edge sees one uS elapsed.
uS_CNT_INT <= uS_CNT_INT + 1;
T_CNT_INT <= T_CNT_INT + 1;
if uS_CNT_INT = 65535 then
uS_CNT_INT <= 0;
end if;
elsif T_CNT_INT = Frequency then
T_CNT_INT <= 1;
else
T_CNT_INT <= T_CNT_INT + 1;
end if;
end if;
end process COUNT;
T_CNT <= T_CNT_INT;
uS_CNT <= uS_CNT_INT;
end behavior;
The processes I'm using for the pulse generation portion of the design are as follows:
loadPulseProc: process(PIXEL_CLK, END_ADC, RESET)
begin
if RESET = '1' then
PULSE_FLAG <= '0';
LOAD_PULSE <= '0';
elsif rising_edge(END_ADC) then
PULSE_FLAG <= '1';
end if;
if rising_edge(PIXEL_CLK) then
if PULSE_FLAG = '1' and END_ADC = '1' and LVAL <= '0' and ADC_TMR_T >= 4 and LVAL_TMR_T >= 4 then
LOAD_PULSE <= '1', '0' after PIXEL_CLK_T;
PULSE_FLAG <= '0';
end if;
end if;
end process loadPulseProc;
ADCTimerProc: process(END_ADC, RESET)
begin
if RESET = '1' then
ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if rising_edge(END_ADC) then
ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if falling_edge(END_ADC) then
ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
end process ADCTimerProc;
LVALTimerProc: process(LVAL, RESET)
begin
if RESET = '1' then
LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if rising_edge(LVAL) then
LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
if falling_edge(LVAL) then
LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
end if;
end process LVALTimerProc;
PIXEL_CLK_T is the period of the clock, 15.152 ns.
This design works, simulation shows that it does as I require, but only after significant hassle avoiding errors due to using multiple rising_edge of falling_edge calls by separating them into separate if statements that really should be together. As far as I've read using rising_edge and falling_edge seems to be reserved for clocks only, so is this just bad practice? How can avoid this behavior but still create the same output?
Thanks!
Yes, rising_edge()/falling_edge() should only be used for clock signal. While it works in simulation it can cause problems and unintended hardware in synthesis.
Synthesis tools infer a clock from the function's argument and place such signals/wires on special tracks in the FPGAs (assuming you are targeting an FPGA for your design). The tool will further infer special clock buffers and warn if your input clock pin is not a clock capable pin.
Introducing several clocks can lead to asynchronous designs and make it vulnerable for cross clock faults.
Detecting a rising or falling edge on a signal is done by an edge detection circuit like the following which compares the signal in the previous clock cycle to the current value.
Needed signals:
signal mySignal_d : std_logic := '0';
signal mySignal_re : std_logic;
Needed logic:
mySignal_d <= mySignal when rising_edge(Clock);
mySignal_re <= not mySignal_d and mySignal;
This first line translates to an 1-bit D-flipflop (You could also use a process). The second lines generates a one cycle strobe signal when mySignal changes from low to high. I'm using *_d to indicate a delayed signal of the original input and *_re for rising edge.
The generated signal is still synchronous to Clock.

Synthesizable wait statement in VHDL

I am writing a VHDL code to control AD7193 via SPI communication. ADC is controlled and configured via number of con-chip registers, DOUT/RDY (SPI_miso) goes low to indicate the completion of conversion. These are the code and timing characteristics (Please see Here) of AD7193.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity MainADC is port (
clk : in std_logic; -- OSC 50MHz
rst : in std_logic; -- Reset clock
sclk : out std_logic; -- out clock
cs : out std_logic; -- Chip select
spi_mosi: out std_logic; -- Write register
start : in std_logic; -- Start Conversion
spi_miso: in std_logic); -- Read register/Single channel, 24 bits
end MainADC;
architecture Behavior of MainADC is
signal outclk : std_logic;
signal clk_sel : std_logic; -- Clock Control
signal CommMode: std_logic_vector(7 downto 0) :="00001000"; -- Communications register==> next stage: Mode Register
signal Mode : std_logic_vector(23 downto 0) := "001010000000000001100000"; -- Single conversion mode
signal CommRead: std_logic_vector(7 downto 0) := "01011000"; -- Communications register==> next stage: Read Data
begin
cs <= '0'; -- Hardwired low
process(clk, rst) -- Clock_gen 500KHz
variable cnt : integer range 0 to 500 :=1;
begin
if (rst='1') then
cnt := 0;
outclk <= '0';
elsif (clk = '1' and clk'event) then
cnt := cnt + 1;
if (cnt = 50) then
cnt := 0;
outclk <= not outclk;
end if;
end if;
end process;
process(clk_sel)
begin
if (clk_sel='0') then
sclk <= '1'; --Clock Idle High
else
sclk <= outclk; --Provide Clock Cycles
end if;
end process;
process (outclk) -- SPI Comm
variable i : integer :=0;
variable data_temp: std_logic_vector(23 downto 0) :=(others=>'0');
begin
if (start = '0') then
clk_sel <= '0';
i:=0;
else
if falling_edge(outclk) then
i:=i+1;
if (i>=0 and i<=7) then -- Communications register==> next stage: Mode Register (8 bits)
clk_sel <= '1';
CommMode(7 downto 1) <= CommMode(6 downto 0);
CommMode(0) <= CommMode(7);
spi_mosi <= CommMode(7);
elsif (i=8) then
clk_sel <= '0'; --Clock Idle High
elsif (i>=9 and i<=32) then -- Single conversion mode (24 bits)
clk_sel <= '1';
Mode(23 downto 1) <= Mode(22 downto 0);
Mode(0) <= Mode(23);
spi_mosi <= Mode(23);
elsif (i=33) then
clk_sel <= '0'; --Clock Idle High
wait until (spi_miso'event and spi_miso='0'); --Wait for Ready Read Signal (DOUT/DRY)
elsif (i>=34 and i<= 41) then -- Communications register==> next stage: Read Data
clk_sel <= '1';
CommRead(7 downto 1) <= CommRead(6 downto 0);
CommRead(0) <= CommRead(7);
spi_mosi <= CommRead(7);
elsif (i=42) then
clk_sel <= '0'; --Clock Idle High
elsif (i>=43 and i<= 66) then
clk_sel <= '1';
data_temp(23 downto 0) := data_temp(22 downto 0) & spi_miso; --Read Data
elsif (i>=66 and i<=566) then -- Waiting for ADC Power Up after Conversion (~1ms)
clk_sel <= '0'; --Clock Idle High
elsif (i=567) then
i:=0;
end if;
end if;
end if;
end process;
end Behavior;
As far as I know Wait Until statement supports for vhdl synthesis, but I received this error: "Error (10441): VHDL Process Statement error at Main ADC.vhd(53): Process Statement cannot contain both a sensitivity list and a Wait Statement". How can I solve this error? Is there any other way to hold counter and waiting for DOUT/RDY event to know when conversion is complete for read data? Any opinions are appreciated! Thank you.
The error message is due to a VHDL language semantic restriction.
The wait until implies you're using spi_miso as a clock, and it looks like you're requiring a flip flop to toggle as a result of i counter reaching 33, before progressing to 34.
The error about the sensititvity list item (outclock) and the wait statement is telling you you can't use two different clocks in this process.
If there is no metastability issue with outclk, instead of waiting don't increment i unless spio_miso = 0 when i = 33. You could also evaluate i before incrementing it (the equivalent of making i a signal).
This may deserve simulation before synthesis. There may be other issues lurking in there.
Your VHDL analyzes with a couple of changes:
if falling_edge(outclk) then
if ( i /= 33 or spi_miso = '0' ) then
i:= i + 1;
end if;
if (i>=0 and i<=7) then -- Communications register==> next stage: Mode Register (8 bits)
clk_sel <= '1';
CommMode(7 downto 1) <= CommMode(6 downto 0);
CommMode(0) <= CommMode(7);
spi_mosi <= CommMode(7);
elsif (i=8) then
clk_sel <= '0'; --Clock Idle High
elsif (i>=9 and i<=32) then -- Single conversion mode (24 bits)
clk_sel <= '1';
Mode(23 downto 1) <= Mode(22 downto 0);
Mode(0) <= Mode(23);
spi_mosi <= Mode(23);
-- elsif (i=33) then
-- clk_sel <= '0'; --Clock Idle High
-- wait until (spi_miso'event and spi_miso='0'); --Wait for Ready Read Signal (DOUT/DRY)
elsif (i>=34 and i<= 41) then -- Communications register==>
(And I normally wouldn't put parentheses around an if statement expression.)

Signal led cannot be synthesized, bad synchronous description?

I have created a frequency divider, and I want to test it using a FPGA board. To test it I want to make a led flicker with the divided frequency, if a switch is on. The problem is that I do't know how to change the value of the led if clock is not on rising edge.
Here is the exact error I get:
line 51: Signal led cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
-->
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity divizor1 is
Port (clk : in STD_LOGIC;
--clk_out : out STD_LOGIC;
btn : in STD_LOGIC;
led : out STD_LOGIC
);
end entity divizor1;
architecture divizor_frecv of divizor1 is
signal cnt : std_logic_vector (24 downto 0);
signal clock :std_logic;
signal bec : std_logic;
begin
process(clk)
begin
if rising_edge(clk) then
cnt<=cnt +1;
end if;
if (cnt = "1111111111111111111111111") then
--clk_out <= '1';
clock <= '1';
else
-- clk_out <= '0';
clock <= '0';
end if;
end process;
process (clock, btn)
begin
if btn = '1' then
if clock'event and clock = '1' then
led <= '1';
else
led <= '0';
end if;
end if;
end process;
end divizor_frecv;
The error message appears to be complaining that you are using the output of the cnt counter as a clock.
Instead you could use it as a toggle enable and clk as the clock:
--process (clock, btn)
process (clk, btn)
begin
-- if btn = '0' then
if btn = '1' then -- reset led
led <= '0'; -- or '1' which ever turns it off
-- if clock'event and clock = '1' then
elsif clock = '1' and rising_edge(clk) then -- clock as enable
-- led <= '1';
led <= not led;
-- else
-- led <= '0';
end if;
-- end if;
end process;
The state of btn made a convenient reset to provide an initial value for led to be able to use not led. This either requires the port signal led be made mode inout or you need a proxy variable or signal which is assigned to led so the not led works (so led can be read). A default value for cnt would also help simulation.
I cheated and made your counter cnt shorter and set the clock to 4 MHz to illustrate:
The simulation was done using ghdl and gtkwave.
process (clock, btn)
begin
if btn = '1' then
if clock'event and clock = '1' then
led <= '1';
else
led <= '0';
end if;
end if;
end process;
At a first glance, I would have guessed the button was a clock enable here. However, the else part is connected to the clock. So you've asked for led to go high at the rising clock edge and low at all other times; given that the clock edge is an instant, this doesn't make much sense (it would always be low). I expect you want to update led based on some other state on the clock edge, for instance:
process (clock)
begin
if clock'event and clock = '1' then
led <= btn;
end if;
end process;
If all you wanted was for the LED to indicate the clock pulses (which may well be too fast to detect) you could just route clock directly to led. Your divider is already producing very short pulses (usually we aim for 50% duty cycle, this has 0.000003%).

Resources