Creating strings for lcd-data - vhdl

I want to create dynamic string array, so I can transmit it to the lcd module on my Altera DE2-115 board. So far the most part is working, but the last part is not wrking in the following code:
CREATE_STRING: PROCESS (CLK, RESET, X)
BEGIN
IF RESET = '1' THEN
FOR i IN 0 TO 31 LOOP
lcd_data(i) <= x"30";
END LOOP;
END IF;
IF X /= 0 THEN
FOR i IN 0 TO 15 LOOP
IF X(15-i) = '0' THEN
lcd_data(i) <= x"30";
END IF;
IF X(15-i) ='1' THEN
lcd_data(i) <= x"31";
END IF;
END LOOP;
END IF;
IF char_count > 15 AND lcd_y = '1' THEN
ELSIF CLK = '1' AND CLK'event THEN
lcd_data(to_integer(char_count)) <= x"31";
END IF;
END PROCESS CREATE_STRING;
I'm getting this error message:
Error (10818): Can't infer register for "lcd_data[31][0]" at seqdec.vhd(75) because it does not hold its value outside the clock edge
for every lcd_data[31][x].
I googled the error and if I am not completly on the wrong thought I think i understood it, but I'm still not able the get it right...
Would be great if somebody could help with advice.
Best regards
Adrian
Did this change:
CREATE_STRING: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
FOR i IN 0 TO 31 LOOP
lcd_data(i) <= x"30";
END LOOP;
ELSIF CLK = '1' AND CLK'event THEN
IF X /= 0 THEN
FOR i IN 0 TO 15 LOOP
IF X(15-i) = '0' THEN
lcd_data(i) <= x"30";
END IF;
IF X(15-i) ='1' THEN
lcd_data(i) <= x"31";
END IF;
END LOOP;
END IF;
ELSIF lcd_y = '1' THEN
lcd_data(to_integer(pos_count)) <= x"31";
END IF;
END PROCESS CREATE_STRING;
But still the same problem.

To properly describe a register, you must reverse the order of the if statements as follows:
CREATE_STRING: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
FOR i IN 0 TO 31 LOOP
lcd_data(i) <= x"30";
END LOOP;
ELSIF CLK = '1' AND CLK'event THEN
IF X /= 0 THEN
FOR i IN 0 TO 15 LOOP
IF X(15-i) = '0' THEN
lcd_data(i) <= x"30";
END IF;
IF X(15-i) ='1' THEN
lcd_data(i) <= x"31";
END IF;
END LOOP;
END IF;
IF char_count > 15 AND lcd_y = '1' THEN
lcd_data(to_integer(char_count)) <= x"31";
END IF;
END IF;
END PROCESS CREATE_STRING;

Related

Interfacing output to a DAC - 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;

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;

Is it legal to have an independent if-clause for the D flip-flop reset in VHDL?

I have the following code describing some registers:
DCR_WR_REGS_P: process (CLK)
begin
if rising_edge(CLK) then
if DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
case to_integer(unsigned(DCR_ABUS(7 to 9))) is
when REG_DMA_RD_ADDR_OFFS =>
dma_rd_addr_reg <= DCR_WR_DBUS (0 to DMA_RD_ADDR_SZ-1);
when REG_DMA_RD_LENG_OFFS =>
dma_rd_leng_reg <= DCR_WR_DBUS (0 to DMA_RD_LENG_SZ-1);
rd_dma_req <= '1';
-- more registers here...
when
when
----------------------
when others =>
end case;
end if;
else
if clear_rd_dma_req='1' then
rd_dma_req <='0';
end if;
end if;
end if;
end process DCR_WR_REGS_P;
This code works except for the fact that the clear_rd_dma_req is ignored when DCR_WRITE is active. So, can I somehow make the "if clear_rd_dma_req='1'" clause an independent one? I realize that I can create a separate process just for the rd_dma_req bit, but I am trying to avoid that as I have a few bits like that.
Here's a version with a separate process:
DCR_WR_REGS_P: process (CLK)
begin
if rising_edge(CLK) then
if DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
case to_integer(unsigned(DCR_ABUS(7 to 9))) is
when REG_DMA_RD_ADDR_OFFS =>
dma_rd_addr_reg <= DCR_WR_DBUS (0 to DMA_RD_ADDR_SZ-1);
when REG_DMA_RD_LENG_OFFS =>
dma_rd_leng_reg <= DCR_WR_DBUS (0 to DMA_RD_LENG_SZ-1);
-- more registers here...
when
when
----------------------
when others =>
end case;
end if;
end if;
end if;
end process DCR_WR_REGS_P;
RD_DMA_REQ_P: process (CLK)
begin
if rising_edge(CLK) then
if clear_rd_dma_req='1' then
rd_dma_req <='0';
elsif DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
if to_integer(unsigned(DCR_ABUS(7 to 9))) = REG_DMA_RD_LENG_OFFS then
rd_dma_req <= '1';
end if;
end if;
end if;
end if;
end process RD_DMA_REQ_P;
And here's a version with an independent if-clause, which is probably illegal:
DCR_WR_REGS_P: process (CLK)
begin
if rising_edge(CLK) then
if DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
case to_integer(unsigned(DCR_ABUS(7 to 9))) is
when REG_DMA_RD_ADDR_OFFS =>
dma_rd_addr_reg <= DCR_WR_DBUS (0 to DMA_RD_ADDR_SZ-1);
when REG_DMA_RD_LENG_OFFS =>
dma_rd_leng_reg <= DCR_WR_DBUS (0 to DMA_RD_LENG_SZ-1);
rd_dma_req <= '1';
-- more registers here...
when
when
----------------------
when others =>
end case;
end if;
end if;
if clear_rd_dma_req='1' then
rd_dma_req <='0';
end if;
end if;
end process DCR_WR_REGS_P;
Thanks
Yes you can make it an independent one (still inside the if rising_edge(clk) statement). What makes you think this version (last in the modified question) should be illegal?
Anything it does will override assignments made to the same signals by the if DCR_Write statement, thanks to the "last assignment wins" rule.
HOWEVER why not simply reverse the prioritisation and tidy it up, like this?
if clear_rd_dma_req='1' then
...
elsif DCR_Write = '1' then
...
end if;

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

counting clock rising edges then produce a specific signal with FSM in VHDL

sorry for my weak english .
I want to write a VHDL code of simple Control unit or TPG controller that produce a signal like S2 , that motivated from FSM which count two rising edge of clock and then make the s2=1, so I want help to write a code wich count two rise edge then produce s2=1. then in third cycle make it zero.
here is my code that does not work :
LIBRARY ieee ;
USE ieee.std_logic_1164.all ;
USE ieee.std_logic_unsigned.all ;
ENTITY TPG_CONTROL IS
PORT ( Clock : IN STD_LOGIC ;
TPG_CONTROL_En : IN STD_LOGIC ;
--reset : IN STD_LOGIC ;
ST2 : OUT STD_LOGIC ) ;
END TPG_CONTROL ;
ARCHITECTURE behav OF TPG_CONTROL IS
SIGNAL Count : std_logic_vector(1 DOWNTO 0) := "00" ;
TYPE state IS (S0, S1, S2);
SIGNAL Moore_state: state;
SIGNAL Clear: std_logic ;
begin
U_Moore0: PROCESS (clock, Clear, TPG_CONTROL_En, Count)
BEGIN
IF(Count = "11") THEN
Moore_state <= S0;
Clear <= '1';
ELSIF ( (rising_edge (clock)) AND TPG_CONTROL_En= '1') THEN
-- IF (Count = "11") THEN Clear <= '1' THEN
IF Clear = '1' THEN
Count <= "00" ;
ELSE
Count <= Count + 1 ;
-- END IF ;
-- END IF;
-- END IF;
-- END IF;
CASE Moore_state IS
WHEN S0 =>
IF Count = "01" THEN
Moore_state <= S1;
-- ELSE
-- Moore_state <= S0;
END IF;
WHEN S1 =>
IF Count = "10" THEN
Moore_state <= S2;
-- ELSE
-- Moore_state <= S1;
END IF;
WHEN S2 =>
IF Count = "11" THEN
Moore_state <= S0;
-- ELSE
-- Moore_state <= S1;
END IF;
END CASE;
END IF;
END IF;
--ST2 <= ‘1’ WHEN Moore_state = S2 ELSE ‘0’;
END PROCESS;
U_Moore1: PROCESS (clock, TPG_CONTROL_En)
BEGIN
IF ( (rising_edge (clock)) AND TPG_CONTROL_En= '1') THEN
IF ( Moore_state = S2 ) THEN ST2 <= '1' ;
ELSE ST2 <= '0' ;
END IF;
END IF;
END PROCESS;
END behav ;
Fixing the back ticks in you're comment:
Was:
--ST2 <= ‘1’ WHEN Moore_state = S2 ELSE ‘0’;
Is:
-- st2 <= '1' when moore_state = s2 else '0';
Your code analyzes and elaborates.
Writing a simple testbench:
library ieee;
use ieee.std_logic_1164.all;
entity tpg_control_tb is
end entity;
architecture foo of tpg_control_tb is
signal clk: std_logic := '0';
signal enab: std_logic := '1';
signal st2: std_logic;
begin
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 100 ns then
wait;
end if;
end process;
DUT:
entity work.tpg_control
port map (
clock => clk,
tpg_control_en => enab,
st2 => st2
);
end architecture;
with a constant tpg_control_en emonstrates the behavior to which you allude, that you aren't reaching S2.
If you comment out the asynchronous clear of moore_state by count:
u_moore0: process (clock, clear, tpg_control_en, count)
begin
if(count = "11") then
-- moore_state <= s0;
clear <= '1';
elsif ( (rising_edge (clock)) and tpg_control_en= '1') then
-- if (count = "11") then clear <= '1' then
if clear = '1' then
count <= "00" ;
else
count <= count + 1 ;
-- end if ;
-- end if;
-- end if;
-- end if;
case moore_state is
when s0 =>
if count = "01" then
moore_state <= s1;
-- else
-- moore_state <= s0;
end if;
when s1 =>
if count = "10" then
moore_state <= s2;
-- else
-- moore_state <= s1;
end if;
when s2 =>
if count = "11" then
moore_state <= s0;
-- else
-- moore_state <= s1;
end if;
end case;
end if;
end if;
-- st2 <= '1' when moore_state = s2 else '0';
end process;
You actually get there:
I'd suspect without knowing why you have an asynchronous clear that the process statement sensitivity list could be reduced to clock.
And because unsigned/std_logic_vector "+" rolls over you can simply the heck out of what you have:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity tpg_control is
port (
clock: in std_logic;
tpg_control_en: in std_logic;
--reset: in std_logic;
st2: out std_logic
);
end tpg_control;
architecture behav of tpg_control is
signal count : std_logic_vector(1 downto 0) := "00" ;
type state is (s0, s1, s2);
signal moore_state: state;
-- signal clear: std_logic;
begin
u_moore0:
process (clock)
begin
-- if(count = "11") then
-- moore_state <= s0;
-- clear <= '1';
-- elsif ...
if rising_edge(clock) and tpg_control_en = '1' then
-- if clear = '1' then
-- count <= "00" ;
-- else
count <= count + 1;
case moore_state is
when s0 =>
if count = "01" then
moore_state <= s1;
end if;
when s1 =>
if count = "10" then
moore_state <= s2;
end if;
when s2 =>
if count = "11" then
moore_state <= s0;
end if;
end case;
-- end if;
end if;
end process;
u_moore1:
process (clock)
begin
if rising_edge(clock) and tpg_control_en = '1' then
if moore_state = s2 then
st2 <= '1' ;
else st2 <= '0' ;
end if;
end if;
end process;
end behav ;
And this shows the state roll over:
Note that count and moore_state hold the same information in two different type formats. You don't actually need both. Generally synthesis tools would be capable of producing a working implementation from moore_state alone.

Resources