Interfacing output to a DAC - VHDL - vhdl

I am trying to interface the output of my FPGA onto a DAC. I am using the PmodDA2 DAC. The trouble I am having is working out how to output the data from a 16bit register into 1 bit per clock cycle.
I have studied the timing diagram and understand that CS needs to send a pulse before data transmission begins.
I have tried using the necessary resets and other features as applicable within my design as a whole.
I tried implementing a count to cycle between 0 to 16/17 and when it was at the beginning it would set CS to high and begin transmission. However I did not believe this would be at all the correct way to do it.
architecture Behavioral of DAC is
signal count : integer range 0 to 15;
signal selected : std_logic;
signal data_storage : std_logic_vector(15 downto 0);
begin
process(D_DAC, CE_DAC, RES_DAC, RES_DAC, data_storage)
begin
if RES_DAC = '1' then
data_storage <= "0000000000000000";
end if;
if rising_edge(CLK_DAC) then
if CE_DAC = '1' then
data_storage <= D_DAC;
end if;
end if;
end if;
end process ;
CS_DAC <= CE_DAC;
SCLK_DAC <= CLK_DAC;
DATA1_DAC <= data_storage;
end Behavioral;
I'm getting myself very confused over this.
I'd appreciate any help.
************************EDIT************************
I have had another go at implementing the counter...
process(D_DAC, CE_DAC, CLK_DAC, RES_DAC, data_storage)
begin
if RES_DAC = '1' then
data_storage <= "0000000000000000";
cound <= 0;
selected <= '0';
elsif rising_edge(CLK_DAC) then
if CE_DAC = '1' then
if count = 0 then
selected <= '1';
end if;
if selected = 1 then
if count = 15 then
count <= 0;
selected <= '0';
else
count <= count + 1;
data_storage <= D_DAC;
end if;
end if;
end if;
end if;
end process ;
CS_DAC <= CE_DAC;
SCLK_DAC <= CLK_DAC;
DATA1_DAC <= data_storage;
end Behavioral;

Related

Delay in Simulation of Output with regard to Input

I am making a MultiLevel Car Parking system module with consist of common entry and exit, The idea is that, when I get input stimulus from signal car entry or car exit, It will check the car's Type and then the output should display the level reserved for the particular type where, the car should go, If the slots reserves for particular type is full then the display should output as such. The code gets stimulated through the output gets displayed only after the next clock cycle after the input stimulus is given.
I have tried using a different if-else block for counting operations and also with different process using a flag, and tried to change it to different if-else blocks, but it's still the same. I am beginner to vhdl the execution of statements is quite confusing, and online search is of little help, please help me where did I go wrong?
library ieee;
use ieee.std_logic_1164.all;
use ieee.Numeric_std.all;
use work.Parking_Package.all;
entity CarPark is
port( clk :in std_logic;
rst : in std_logic;
car_in : in std_logic;
Car_out : in std_logic;
Ent_car_type : car_type;
Ext_car_type : car_type;
Status : out level
);
end CarPark;
architecture behave of CarPark is
signal count : counter;
begin
SLOT_CHECKING: process(rst,clk)
begin
if(rst= '1')then
count <= (others => 0);
Status <= FULL;
elsif(rising_edge(clk))then
if(car_in )then
case(Ent_car_type)is
when Admin =>
if(count(Admin) < 5) then
Status <= L1;
count(Admin) <= count(Admin) +1;
else
Status <= FULL;
end if;
when Staff =>
if(count(Staff) < 5) then
Status <= L2;
count(Staff) <= count(Staff) + 1;
else
Status <= FULL;
end case;
end if;
elsif(car_out)then
case(Ext_car_type)is
when Admin =>
if(count(Admin) >0) then
Status <= L1a;
count(Admin) <= count(Admin) - 1;
else
count(Admin)<= 0;
end if;
when Staff =>
if(count(Staff) >0) then
Status <= L2a;
count(Staff) <= count(Staff) - 1;
else
count(Staff) <= 0;
end if;
end process;
end behave;
The user defined packages is given below
library ieee;
use ieee.std_logic_1164.all;
use ieee.Numeric_std.all;
package Parking_Package is
type car_type is (Admin, Staff);
type level is (L1, L2a, FULL);
type counter is array (Staff downto Admin) of integer range 0 to 22;
end Parking_Package;
package body Parking_Package is
end Parking_Package;
After initializing using reset, I give input of car_in as 1 and
car_type as Admin, The output gets displayed as L1 in the Next Clock
and if I force the value of car_type as staff, The corresponding output is simulated in the next clock cycle.
![ScreenShot Simulation] https://imgur.com/a/B6cqADn
Firstly, some comments :
Your application (MultiLevel Car Parking) is not very adapted to VHDL language. It's too high level. Your coding style is a bit object oriented (type and variable names).
There are syntax errors in your code (I assume you already know it because You achieve to have a simulation screen).
The behavior that you expect on the first clock cycle implies that your output will be the product of combinational logic. It's better to have outputs directly from flip flops.
Then the code that you can use to have the expected behavior with 2 process (One purely sequential, the other purely combinational) :
signal current_count : counter;
signal next_count : counter;
signal current_status : level;
signal next_status : level;
begin
SEQ : process(rst_tb, clk_tb)
begin
if (rst_tb = '1') then
current_count <= (others => 0);
current_status <= FULL;
elsif (rising_edge(clk_tb)) then
current_count <= next_count;
current_status <= next_status;
end if;
end process;
SLOT_CHECKING : process(current_count, current_status, car_in, car_out, Ent_car_type, Ext_car_type)
begin
next_count <= current_count;
next_status <= current_status;
if (car_in = '1') then
case (Ent_car_type) is
when Admin =>
if (current_count(Admin) < 5) then
next_status <= L1;
next_count(Admin) <= current_count(Admin) + 1;
else
next_status <= FULL;
end if;
when Staff =>
if (current_count(Staff) < 5) then
next_status <= L2;
next_count(Staff) <= current_count(Staff) + 1;
else
next_status <= FULL;
end if;
end case;
elsif (car_out = '1') then
case (Ext_car_type) is
when Admin =>
if (current_count(Admin) > 0) thenremarques
next_status <= L1a;
next_count(Admin) <= current_count(Admin) - 1;
else
next_count(Admin) <= 0;
end if;
when Staff =>
if (current_count(Staff) > 0) then
next_status <= L2a;
next_count(Staff) <= current_count(Staff) - 1;
else
next_count(Staff) <= 0;
end if;
end case;
end if;
end process;
count <= next_count ;
Status <= next_status ;
Warning, with this code the outputs are directly from combinational logic : It's not recommended but it is the only way to get the behavior you expect.
If this application is only a practise, I advice you too to take another example more adapted to VHDL : filter, SPI communication, processing unit, ...

Using of loop statements and delays inside the states in fsm

I'm trying to write vhdl code for a spartan-6 xc6slx45t for generating multiple frequencies in single channel.. That is:
242.72khz with 20 cycles
23.6khz with 1 cycle
243.90khz with 6 cycles
then 23.4 khz with 386 cycles
all in single output. I just tried with one frequency here and got some issues with delays in codes..
I mentioned each states with different no.of cycles here.. But what I need is for example: when state S0 =>242.72khz with 20 cycles and then a delay in between two states, and next state S1 => 23.6khz with one cycle and then again a delay and next state and so on..)
Here i attached my code. Please help me with developing the code..
Thanks in advance...
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY FSM_Example IS
PORT (
clk, reset, en : IN std_logic;
output : INOUT std_logic
);
END FSM_Example;
ARCHITECTURE Behavioral OF FSM_Example IS
TYPE state_type IS (S0, S1, S2, S3);
SIGNAL cur_state, next_state : state_type;
SIGNAL count : INTEGER RANGE 0 TO 5000;
SIGNAL i : INTEGER RANGE 0 TO 400;
SIGNAL cnt : INTEGER RANGE 0 TO 400;
BEGIN
state_memory : PROCESS (clk, reset)
BEGIN
IF (reset = '1') THEN
cur_state <= S0;
ELSIF (clk = '1' AND clk'event) THEN
IF (count = 4240 - 1) THEN
count <= 0;
cur_state <= next_state;
ELSE
count <= count + 1;
END IF;
END IF;
END PROCESS state_memory;
PROCESS (count)
BEGIN
IF (count < 1480) THEN
output <= '1';
ELSE
output <= '0';
END IF;
END PROCESS count;
PROCESS (en, cur_state)
BEGIN
CASE cur_state IS
WHEN S0 =>
loop0 : FOR i IN 0 TO 6 LOOP
EXIT loop0 WHEN i = 7;
cnt(i + 1) <= cnt(i) + 1;
IF (en = '1' AND en'event) THEN
ELSIF (i < 6) THEN
next_state <= S1;
ELSE
next_state <= S0;
END IF;
END LOOP;
WHEN S1 =>
loop1 : FOR i IN 0 TO 1 LOOP
EXIT loop1 WHEN i = 2;
i <= i + 1;
IF (en = '1' AND en'event) THEN
ELSIF (i < 1) THEN
next_state <= S2;
ELSE
next_state <= S1;
END IF;
END LOOP;
WHEN S2 =>
loop2 : FOR i IN 0 TO 20 LOOP
EXIT loop2 WHEN i = 21;
i <= i + 1;
IF (en = '1' AND en'event) THEN
ELSIF (i < 20) THEN
next_state <= S3;
ELSE
next_state <= S2;
END IF;
END LOOP;
WHEN S3 =>
loop3 : FOR i IN 0 TO 386 LOOP
EXIT loop3 WHEN i = 387;
i <= i + 1;
IF (en = '1' AND en'event) THEN
ELSIF (i < 386) THEN
next_state <= S0;
ELSE
next_state <= S3;
END IF;
END LOOP;
END CASE;
END PROCESS;
END Behavioral;
You are trying to write synthesize code. Then you cannot use wait for x ns. The FPGA does not know how to wait for x nanoseconds. It does not know what a nanosecond is.
But more of your code does not seem synthesizable. You should read-up on how to write VHDL for synthesis on FPGAs
What an FPGA does have (normally) is a clock crystal input and also . From the frequency of the clock input, you can derive how many clock cycles would be in a time period. Then you should implement a counter and insert intermediate wait-states, where the fsm waits until a specific value of the counter is reached.
E.g. If the clock input is 100 MHz, each clock pulse is 10 ns long ==> 10 clock pulses is 100 ns long. If you need smaller time step, you need to increase the clock frequency using a PLL/DCM/MMCM/etc. but you cannot do this indefinitely, as the FPGA does not support very high clock frequencies.

VHDL : Signal s Cannot be Synthesised

line 62: Signal s 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;
entity clock is
Port ( start : in STD_LOGIC;
reset : in STD_LOGIC;
CLOCK : in STD_LOGIC;
setH, setM, setS : in STD_LOGIC;
alarmH, alarmM, alarmS : in STD_LOGIC;
Alarm_On : in STD_LOGIC;
Buzzer_Stop : in STD_LOGIC;
BUZZER : out STD_LOGIC;
hh, mm, ss : out INTEGER);
end clock;
architecture Behavioral of clock is
signal h, m, s : INTEGER range 0 to 60 := 0;
signal hA, mA, sA : INTEGER range 0 to 60 := 0;
signal clk : std_logic :='0';
signal count : integer :=1;
begin
Frequency_Reducer : process(CLOCK) --Reducing Frequency From 40MHz to 1Hz
begin
if rising_edge(CLOCK) then
count <= count + 1;
if(count = 20000000) then
clk <= not clk;
count <=1;
end if;
end if;
end process;
Clock_Logic : process(start, reset, clk)
begin
if reset = '1' then
h <= 00;
m <= 00;
s <= 0;
end if;
if start = '1' then
if rising_edge(clk) then --Clock Logic Start
s <= s + 1;
end if;
end if;
if s = 60 then
s <= 0;
m <= m + 1;
end if;
if m = 60 then
m <= 0;
h <= h + 1;
end if;
if h = 24 then
h <= 0;
end if; --Clock Logic End
if setH = '1' then --Set Time Logic Start
h <= h + 1;
end if;
if setM = '1' then
m <= m + 1;
end if;
if setS = '1' then
s <= s + 1;
end if; -- Set Time Logic End
end process;
hh <= h;
mm <= m;
ss <= s;
end Behavioral;
Let's take a look at the assignments of signal s only:
Clock_Logic : process(start, reset, clk)
begin
if reset = '1' then
s <= 0;
end if;
if start = '1' then
if rising_edge(clk) then --Clock Logic Start
s <= s + 1;
end if;
end if;
if s = 60 then
s <= 0;
end if;
if setS = '1' then
s <= s + 1;
end if; -- Set Time Logic End
end process;
In the last assignment, you are requesting that s is incremented when setS is high and the process is executed (resumed). The process is executed initially after system startup and every time when one of the signals in the sensitivity list changes. Thus, you are requesting flipf-flops clocked on both edges of three signals start, reset and clock. I suspect, that this increment should be done only on the rising edge of the clock:
if rising_edge(clk) then --Clock Logic Start
if setS = '1' then
s <= s + 1;
end if; -- Set Time Logic End
end if;
The asynchronous reset of s when s reaches 60 is possible, but error prone due to glitches. s is is multi-bit signal in hardware. Thus, when it is incremented it could be equal to 60 for short moments in time even when the final value is below 60! You should reset it synchronously to 0, when current value is 59.
The increment of s when start is high and a rising-edge on the clock occur is ok, but synthesis tool often request to re-arrange this so that the outer if block checks for the rising edge:
if rising_edge(clk) then --Clock Logic Start
if start = '1' then
s <= s + 1;
end if;
end if;
Finally, the asynchronous reset (or set) inputs on flip-flops have always a higher priority then the synchronous data inputs. Thus, you must arrange it either this way:
Clock_Logic : process(reset, clk)
begin
if reset = '1' then
-- asynchronous part
s <= 0;
elsif rising_edge(clk) then
-- synchronous part (add more conditions if required)
s <= s + 1;
end if;
end process;
or this way:
Clock_Logic : process(reset, clk)
begin
if rising_edge(clk) then
-- synchronous part (add more conditions if required)
s <= s + 1;
end if;
if reset = '1' then
-- asynchronous part
s <= 0;
end if;
end process;
The synchronous assignments can be more complex. For example, if you want to synchronously reset a counter when it reaches 59 and to increment it otherwise when the signal setS is high:
Clock_Logic : process(reset, clk)
begin
if reset = '1' then
-- asynchronous part
s <= 0;
elsif rising_edge(clk) then
-- synchronous part
if s = 59 then
s <= 0;
elsif setS = '1' then
s <= s + 1;
end if;
end if;
end process;

Simplifying A State Machine To Reduce Logic Levels and Meet Timing

My design at the moment isn't meeting timing. I've tried putting it on a slower clock and pipelining the inputs/outputs. The problem is always the same - too many levels of logic. Have any of you got any tips on making this logic more clock friendly?
signal ctr : std_logic_vector(9 downto 0);
signal sig_bit_shift : std_logic_vector (15 downto 0);
begin
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' or nuke = '1' then
ctr <= (others => '0');
state <= ST_IDLE;
elsif unsigned(event_settings) < 1 then -- disables
state <= ST_IDLE;
elsif unsigned(event_settings) = 1 then -- always on
state <= ST_ENABLE;
else
case state is
when ST_IDLE =>
if ctr = (unsigned(event)-2) then
state <= ST_ENABLE;
elsif unsigned(ctr) = 1 and sig = '0' then --catches first word
state <= ST_ENABLE;
elsif sig = '1' then
ctr <= ctr + 1;
end if;
when ST_ENABLE =>
if s_sig = '1' then
state <= ST_IDLE;
if unsigned(s_evt) > 1 then
ctr <= (others => '0');
end if;
end if;
end case;
end if;
end if;
end process;
UPDATE:
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' or nuke = '1' then
ctr <= x"00" & "10";
state <= ST_IDLE;
elsif settings = '1' then
case state is
when ST_IDLE =>
if ctr = (unsigned(event)) then
state <= ST_ENABLE;
elsif unsigned(ctr) = 1 and sig = '0' then --catches first word -- this is the part which when added, fails timing
state <= ST_ENABLE;
elsif sig = '1' then
ctr <= ctr + 1;
end if;
when ST_ENABLE =>
if s_sig = '1' then
state <= ST_IDLE;
if unsigned(s_evt) > 1 then
ctr <= X"00" & "10";
end if;
end if;
end case;
end if;
end if;
end process;
I think too it's slowed down by where the signal comes from:
sig <= sig_token when unsigned(SIG_DELAY) < 1 else (sig_bit_shift(to_integer(unsigned(SIG_DELAY)-1)));
process(clk_p) -- delays sig
begin
if rising_edge(clk_p) then
if rst = '1' then
sig_bit_shift <= (others => '0');
else
sig_bit_shift <= l1a_bit_shift(sig_bit_shift'high-1 downto 0) & sig_token;
end if;
end if;
end process;
UPDATE 2 :
Seems like half the routing went into the above delay so i'm going to try and fix with this:
signal sig_del_en : std_logic;
signal sig_del_sel : integer;
begin
process(clk_p)
begin
if rising_edge(clk_p) then
if unsigned(SIG_DELAY) = 0 then
sig_del_en <= '0';
else
sig_del_en <= '1';
end if;
sig_del_sel <= to_integer(unsigned(SIG_DELAY)-1);
end if;
end process;
sig <= sig_token when sig_del_en = '0' else (sig_bit_shift(sig_del_sel));
Some of the "slow" operations are array = which requires compare over all bits in the argument, and < and > which requires subtraction over all bits in the argument. So you may improve timing in a cycle, if there is sufficient time in the previous cycle to generate the compare result up front as a std_logic. It may be relevant for these:
unsigned(event_settings) < 1
unsigned(event_settings) = 1
ctr = (unsigned(event)-2)
unsigned(ctr) = 1
unsigned(s_evt) > 1
The code to generate the different std_logic values depends on the way the related signal is generated, but an example can be:
process (clk) is
variable event_settings_v : event_settings'range;
begin
if rising_edge(clk) then
...
event_settings_v := ... code for generating event_settings; -- Variable with value
event_settings <= event_settings_v; -- Signal drive from variable
if unsigned(event_settings_v) < 1 then
unsigned_event_settings_tl_1 <= '1';
else
unsigned_event_settings_tl_1 <= '0';
end if;
end if;
end process;
The code unsigned(event_settings) < 1 in the state machine can then be changed to unsigned_event_settings_tl_1 = '1', which may improve timing if this compare is in the critical path.
Using the asynchronous reset typically available on the the flip-flop for rst_i = '1' may also improve timing, since it removes logic from the synchronous part. It is unlikely to give a significant improvement, but it's typically a good design practice in order to maximize the time for synchronous logic. The asynchronous reset is used through coding style like:
process (rst_i, clk_p) is
begin
if rst_i = '1' then
... Apply asynchronous reset value to signals
elsif rising_edge(clk_p) then
... Synchronous update of signals

VHDL edge detection

I want to detect the edges on the serial data signal (din). I have written the following code in VHDL which is running successfully but the edges are detected with one clock period delay i.e change output is generated with one clk_50mhz period delay at each edge. Could anyone please help me to detect edges without delay. Thank you.
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if (rst = '0') then
shift_reg <= (others => '0');
else
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= din;
end if;
end if;
end process;
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if rst = '0' then
change <= '0' ;
elsif(clk_enable_2mhz = '1') then
change <= shift_reg(0) xor shift_reg(1);
end if ;
end if ;
end process ;
When I changed my code to following I am able to detect the edges
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if (RST = '0') then
shift_reg <= (others=>'0');
else
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= din;
end if;
end if;
end process;
change <= shift_reg(1) xor din;
Here you go
library ieee;
use ieee.std_logic_1164.all;
entity double_edge_detector is
port (
clk_50mhz : in std_logic;
rst : in std_logic;
din : in std_logic;
change : out std_logic
);
end double_edge_detector;
architecture bhv of double_edge_detector is
signal din_delayed1 :std_logic;
begin
process(clk_50mhz)
begin
if rising_edge(clk_50mhz) then
if rst = '1' then
din_delayed1 <= '0';
else
din_delayed1 <= din;
end if;
end if;
end process;
change <= (din_delayed1 xor din); --rising or falling edge (0 -> 1 xor 1 -> 0)
end bhv;
You have to use a combinatorial process to detect the difference without incurring extra clock cycle delays. (You will still need one register to delay the input as well.)
DELAY: process(clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
din_reg <= din;
end if;
end process;
change <= din xor din_reg;

Resources