Mod-M counter Unsigned values have no signal - vhdl

I am writing a RS232 module for my Nexys2 board. I am currently having issues with my baud rate controller which I want to set to 19200.
For this I am using a Mod-M counter, after many ISim simulations the problem with my code is in the mod-m counter as it is not producing any ticks.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity baud_rate is
generic (
N: integer := 8;
M: integer :=163);
Port (clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out STD_LOGIC_VECTOR(N-1 downto 0));
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : unsigned(N-1 downto 0);
signal r_next : unsigned(N-1 downto 0);
begin
process(clk,reset)
begin
if (reset ='1') then
r_reg <= (others=>'0');
elsif(clk'event and clk='1') then
r_reg <= r_next;
end if;
end process;
r_next <= (others =>'0') when r_reg=(M-1) else r_reg+1;
tick <='1' when r_reg=(M-1) else '0';
q <= std_logic_vector(r_reg);
end Behavioral;
I have tested and all the clk inputs and run fine and the issue seems to be with the r_reg and r_next registers. In ISim when outputing either of these on q I get UUUUUUUU, so it seems they are not generating signal. From this i can infer that the two r_reg and r_next registers aren't being created or storing values, is there an issue when using unsigned?
To make triple sure I have even copied the mod-m counter from the book FPGA Prototyping with VHDL (which is the code shown) BUT still this does not work and q output is UUUUUUUU.
If there are any better ways of creating a baud rate from the nexys2 50mz clock that would also be appreciated!
Cheers

Frankly I am horrified if people are expected to learn VHDL from a book where examples like this are presented. I know the author has a similar book on Verilog : do people end up thinking VHDL is just a more verbose Verilog?
Specific criticisms (actually 7,8 are more observations):
1) Spurious type conversions.
Q represents an unsigned number. So make it unsigned!
The baud generator isn't the only thing in your FPGA so Q isn't likely to be an off-chip port. There are good arguments for making top level, off-chip ports std_logic_vector but even that isn't compulsory. However, if your customer's specification or coding style insists on spurious type conversions on ports; follow it.
2) the DRY principle:
package CPU_types is
subtype baud_count is unsigned(7 downto 0);
end CPU_types;
Spot the simplification in maintenance.
If you are using a subtype in several places, put it in a package; the universal code reuse tool.
3) Indentation, formatting. (I recognise that may have become garbled by editor settings). It adds to the brain load reading it. What I've done here isn't The One Way though.
4) Spurious brackets round logical expressions. Harmless, but look like crutches for C programmers.
5) Antique clk'event style. Next year, the rising_edge function will be old enough to drink (in America. In Britain it's been getting plastered every Saturday night for a couple of years now...)
6) The "two process" style with r_reg and r_next. Does he also write state machines with a separate combinational process on next_state? Given this, I'm guessing so. Single process state machines are easier, smaller (to write : they don't generate smaller hardware) and safer.
7) I cheated and my tick is one cycle later than in the original. If that is critical, restore the external "tick" assignment. I also made it synchronous vhich will help performance. Some people would prefer tick <= '0' in an else clause; however the default assignment I used is safe, and prevents a lot of mistakes (and unnecessary else clauses) in larger designs.
8) The assignment to Q can be brought into the process too; if you made r_reg a process variable you'd have to. There is room for other variations and preferences.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use CPU_types.all;
entity baud_rate is
generic (
M: integer := 163);
Port (
clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out baud_count);
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : baud_count;
begin
process(clk,reset)
begin
if reset ='1' then
r_reg <= (others=>'0');
elsif rising_edge(clk) then
tick <= 0;
r_reg <= r_reg+1;
if r_reg = M then
tick <= '1';
r_reg <= (others=>'0');
end if;
end if;
end process;
-- tick <='1' when r_reg = M-1 else '0';
-- or simpler, when r_reg = 0
q <= r_reg;
end Behavioral;

Related

How to calculate the RPM of a hometrainer with VHDL

I've got a problem; I need to calculate / measure the RPM of a hometrainer using a hall sensor and a magnet on the wheel, the hardware needs to be described in VHDL, my current method is this:
If the hall sensor detects a pulse, reset a counter
Increment counter every clockcycle
On the next pulse, store the previous value, reset, and repeat.
The code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity teller is
port(
hallsens : in std_logic;
counter : out std_logic_vector(15 downto 0);
areset : in std_logic;
clk : in std_logic
);
end entity teller;
architecture rtl of teller is
signal counttemp : std_logic_vector(15 downto 0);
signal timerval2 : std_logic_vector(15 downto 0);
signal lastcount : std_logic_vector(15 downto 0);
begin
process(clk, areset)
begin
if areset = '1' then
counter <= "0000000000000000";
counttemp <= "0000000000000000";
timerval2 <= "0000001111101000";
elsif hallsens = '1' then
counter <= lastcount + "1";
timerval2 <= "0000001111101000";
counttemp <= "0000000000000000";
elsif rising_edge(clk) then
timerval2 <= timerval2 - "1";
if timerval2 = "0000000000000000" then
lastcount <= counttemp;
counttemp <= counttemp + "1";
timerval2 <= "0000001111101000";
end if;
end if;
end process;
end rtl;
But to calculate the RPM from this I have to divide the counter by the clockspeed, and multiply by 60. This takes up a lot of hardware on the FPGA (Altera Cyclone 2).
Is there a more efficient way to do this?
TIA
I don't have a computer at hand now, but I'll try to point different things I see:
Don't mix numerical libraries (preferably only use the numeric_std) #tricky suggests.
If handling numerical values, and including libraries for that.. you can should use numerical types for signals (integer, unsigned, signed..) it makes things clear and helps to distinguish numeric signals and no numercial-meant signals.
Hallsens is read as a pseudo-reset, but is not in the sensitivity list of the process, this could cause mismatches between Sims and hw. Anyway this is not a good approach, stick with a simple reset and clock pair.
I would detect hallsens within the clocked region of the process and increment the counter of events there. It should be simpler.
I'm assuming your hallsens asserted time is wide enough to be captured by the clock.
Once timer signal has reached zero (I'm assuming this gives you a known time based on your clk frequency) you can reload again the timer (as you do), output the count value and reset the counter, starting again.
For math operations 1/Freq and *60, you could use some numerical tricks if needed, based on the frequency value.. but you could:
multiply by inverse of frequency instead of dividing.
approximate it to sums of power of 2. (60 = 64-4)
make Freq to be multiple of 60 to simplify calcs.
Ps: to be less error prone, you can initialize your vectors (as theyre multiple of 4) in hex format like: signal<=X"0003" avoiding big binary numbers.

Process or not to Process?

I have the below code in VHDL that I use in a project. I have been using a Process within the architecture and wanted to know if there were any other means which I'm sure there are of accomplishing the same goal.. in essence to take one number compare it to another and if there is a difference of +/- 2 reflect this in the output. I am using the following:
LIBRARY IEEE;
USE IEEE.std_logic_1164.all, IEEE.std_logic_arith.all, IEEE.std_logic_signed;
ENTITY thermo IS
PORT (
CLK : in std_logic;
Tset, Tact : in std_logic_vector (6 DOWNTO 0);
Heaton : out std_logic
);
END ENTITY thermo;
ARCHITECTURE behavioral OF thermo IS
SIGNAL TsetINT, TactINT : integer RANGE 63 Downto -64; --INT range so no 32bit usage
BEGIN
Heat_on_off: PROCESS
VARIABLE ONOFF: std_logic;
BEGIN
TsetINT <= conv_integer (signed (Tset));--converts vector to Int
TactINT <= conv_integer (signed (Tact));--converts vector to Int
--If you read this why is it conv_integer not to_integer?? thx
ONOFF := '0'; --so variable does not hang on start
WAIT UNTIL CLK'EVENT and CLK = '1';
IF TactINT <= (TsetINT - 2) then
ONOFF := '1';
ELSIF TactINT >= (TsetINT + 2) then
ONOFF := '0';
END IF;
Heaton <= ONOFF;
END PROCESS;
END ARCHITECTURE behavioral;
I'm just after a comparison really and to know if there are any better ways of doing what I have already done.
Why convert Tact and Tset to an integer?
Why have the variable ONOFF? The variable initialization appears to remove any sense of hysteresis, is that what you intended? Based on your other code, I bet not. I recommend that you assign directly to the signal Heaton instead of using the variable ONOFF.
If I were to create TsetINT and TactINt, these would be good candidates to be variables. However, there is no need to do the integer conversion as you can simply do the following:
if signed(Tact) <= signed(Tset) - 2 then
...
elsif signed(Tact) >= signed(Tset) + 2 then
Please use numeric_std. Please ask your professor why they are teaching you old methodologies that are not current industry practice. Numeric_std is an IEEE standard and is updated with the standard, std_logic_arith is not an IEEE standard.
use ieee.numeric_std.all ;
In response to Jim's comment I wrote a simple thermal model test bench to test your design.
I only changed your design to use package numeric_std instead of the Synopsys packages. The rest is just prettifying and eliminating comments not germane to the question of whether or not Tact ever reaches Tset.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity thermo is
port (
CLK: in std_logic;
Tset, Tact: in std_logic_vector (6 downto 0);
Heaton: out std_logic
);
end entity thermo;
architecture behavioral of thermo is
signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process
variable ONOFF: std_logic;
begin
TsetINT <= to_integer (signed (Tset)); -- package numeric_std
TactINT <= to_integer (signed (Tact)); -- instead of conv_integer
ONOFF := '0'; -- AT ISSUE -- so variable does not hang on start
wait until CLK'event and CLK = '1';
if TactINT <= TsetINT - 2 then -- operator precedence needs no parens
ONOFF := '1';
elsif TactINT >= TsetINT + 2 then
ONOFF := '0';
end if;
Heaton <= ONOFF;
end process;
end architecture behavioral;
You have a comment in your process asking why conv_integer was required instead of to_integer. That prompted the change.
I removed superfluous parentheses based on operator order precedence (adding operators being higher precedence than relational operators), notice Jim's answer did the same.
So the simple model thermal model runs with a clock set to a 1 second period, and has two coefficients, relating to the temperature increase when Heaton is '1' or not. I arbitrarily set the heating up coefficient to 1 every 4 clocks, and the temperature decay coefficient to 1 every 10 clocks. Also set the ambient temperature (tout) to 10 and tset to 22. The numbers selected are severe to keep the model run time short enhancing portability without relying on setting a simulator resolution limit.
The thermal model was implemented using fixed signed arithmetic without using fixed_generic_pkg, allowing portability to -1993 tools without math packages and includes a fractional part, responsible for the different widths of Heaton true after reaching normal operating temperature. The model could just as easily have been implemented with two different precursor counters used to tell when to increment or decrement Tact.
Using REAL types is possible, not desirable because converting REAL to INTEGER (then to SIGNED) isn't portable (IEEE Std 1076-2008 Annex D).
The idea here is to demonstrate the lack of hysteresis and demonstrate the model doesn't reach Tset:
The lack of hitting Tset (22 + 2) is based on the lack of hysteresis. Hysteresis is desirable for reducing the number of heat on and off cycles The idea is once you start the heater you leave in on for a while, and once you stop it you want to leave it off for a while too.
Using Jim's modification:
-- signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process (CLK)
begin
if rising_edge(CLK) then
if signed(Tact) <= signed(Tset) - 2 then
Heaton <= '1';
elsif signed(Tact) >= signed(Tset) + 2 then
Heaton <= '0';
end if;
end if;
end process;
gives us longer Heaton on and off cycles, decreasing how many times the heater starts and stops:
And actually allows us to see the temperature reach Tset + 2 as well as Tset - 2. where these thresholds provide the hysteresis which is characterized as a minimum on or minimum off time, depending on the efficiency of the heater and heat loss rate when the heater is off.
So what changed in the execution of the thermo model process? Look at the difference in the synthesis results for the two versions.

Unsigned Addition with Counter Doesn't Work

I'm building a counter that counts rising edges from an input channel. I've simplified my design to include two states, one and two, where counting is done. For some reason, whenever I try to add 1 to counter_reg, or try to assign any number at all to it, the signal becomes red with an X in ModelSim. The code and picture of what happens to the signal are provided below.
I have included the IEEE.NUMERIC_STD.ALL, so I should be able to do unsigned addition. I am not sure what is wrong with counter_reg. Is there anything I'm doing wrong with the counter?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity photon_counter is
Port ( clk,reset : in STD_LOGIC;
arm,shifter,channel : in STD_LOGIC;
start : in STD_LOGIC);
end photon_counter;
architecture fsm_arch of photon_counter is
type state_type is (idle,zero,one);
type array_type is array (1 downto 0) of UNSIGNED (15 downto 0);
signal state_reg,state_next : state_type;
signal arm_prev,shifter_prev,channel_prev : STD_LOGIC;
signal counter : array_type;
signal counter_reg,counter_next : UNSIGNED (15 downto 0);
begin
--------------------------------------
--State Register
--------------------------------------
process(clk,reset)
begin
if reset='1' then
state_reg <= zero;
counter_reg <= (others => '0');
counter <= (others => (others => '0'));
elsif rising_edge(clk) then
state_reg <= state_next;
counter_reg <= counter_next;
arm_prev <= arm;
shifter_prev <= shifter;
channel_prev <= channel;
end if;
end process;
--------------------------------------
--Next-State Logic/Output Logic
--------------------------------------
process(clk,reset,state_reg,start,counter_reg,shifter_prev,shifter,arm,channel_prev,channel)
begin
--default actions
state_next <= state_reg;
counter_next <= counter_reg;
counter_reg <= counter_reg;
case state_reg is
when idle =>
counter_reg <= (others => '0');
counter <= (others => (others => '0'));
if start = '1' then
state_next <= zero;
end if;
when zero =>
if (shifter = '1') and (shifter_prev = '0') then
state_next <= one;
counter(0) <= counter_reg;
end if;
if (channel = '1') and (channel_prev = '0') then
counter_next <= counter_reg + 1;
end if;
when one =>
if arm = '1' then
state_next <= zero;
counter(1) <= counter_reg;
end if;
if (channel = '1') and (channel_prev = '0') then
counter_reg <= counter_reg + 1;
end if;
end case;
end process;
end fsm_arch;
As shown below, counter_reg and counter_next start off with a value of 0 until I try to add 1 to counter_next. The moment channel_prev rises, both counter_reg and counter_next become X (error) and turn red.
Your counter_reg signal is assigned in two different processes. This is what we call a "multiple drive" situation. It is usually undesirable, just like any short circuit, because when the two processes disagree about the value to assign things are getting very bad.
Solution: drive your counter from one single process.
A bit more about this: if this is bad, why didn't you get an error when compiling or when launching your simulation? Because most people do not know or care about unresolved/resolved types in VHDL. By default, a VHDL type is unresolved. This means that, if you try to drive a signal of this type from more than one process you will get an error at compilation or elaboration time that basically says "I cannot decide what value to assign if your processes disagree, this is forbidden". And this is a very nice feature because such accidental short circuits can have serious consequences. You can try this and see the errors by replacing your unsigned (resolved) counter by a natural (unresolved) one:
signal counter_reg,counter_next : natural 0 to 2**16 - 1;
adapt the rest of your code, and see what happens when compiling.
Sometimes, rarely, it is useful to drive a signal from more than one process (high impedance shared bus, bi-directional RAM data bus...) So VHDL allows to define a resolution function that computes the resulting value of several drivers. This function can be used to define the resolved subtype of a unresolved parent type. If you can find the source code of ieee.std_logic_1164 you will see the declaration of the unresolved, 9-valued std_ulogic type (u for unresolved), the resolution function, and the declaration of the resolved subtype std_logic (see? no u).
But when using resolved types you must yourself take care of not creating short-circuits. There is no compiler error any more, no seatbelt. When one of your driving processes drives a strong value ('0' or '1'), all the others must drive a weak value ('Z' for high impedance). Else, you will get unknown resulting values, represented in red by Modelsim, as you saw.
Unfortunately, most people do not really know what the U stands for in std_Ulogic. So, in order to simplify they always use std_logic instead of what they should use: std_ulogic. Moreover, vendors of logic synthesisers push in the same direction because they frequently favour std_logic (when they do not simply force you to use it). And the people who standardized the ieee.numeric_std package did the same: they declared the unsigned and signed types as resolved types (if fact, they have the same declaration as std_logic_vector). This is as unfortunate as driving full speed, at night, wearing sunglasses, without light and without your seatbelt fasten.
Finally, someone realized how unfortunate this was and the current version of ieee.numeric_std now also declares UNRESOLVED_UNSIGNED (alias U_UNSIGNED) and UNRESOLVED_SIGNED (alias U_SIGNED). Alas, this is a bit too late, most designers will never change their existing code or habits, and I wonder how many bugs could have been avoided if the first choice had been different.
My advices:
never drive a signal from several processes if you do not really intend to have multiple physical drivers, manually avoid short circuits, and so on,
never use a resolved type if you do not need it, so that the tools will raise an error if you accidentally create a multiple drive situation,
in your case, drive counter_reg from one single process, declare it as U_UNSIGNED or NATURAL, and declare all your other signals as STD_ULOGIC, not STD_LOGIC.

LFSR in VHDL always generating zero

I have written a LFSR in VHDL. I have tested it in simulation and it works as expected (generates random integers between 1 and 512). However when I put it onto hardware it always generates "000000000"
The code is as follows:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity LFSR is
port(clk, reset : in bit;
random : out std_logic_vector (8 downto 0));
end entity LFSR;
architecture behaviour of LFSR is
signal temp : std_logic_vector (8 downto 0) := (8 => '1', others => '0');
begin
process(clk)
begin
if(clk'event and clk='1') then
if(reset='0') then --reset on signal high, carry out normal function
temp(0) <= temp(8);
temp(1) <= temp(0);
temp(2) <= temp(1) XOR temp(8);
temp(3) <= temp(2) XOR temp(8);
temp(4) <= temp(3) XOR temp(8);
temp(8 downto 5) <= temp(7 downto 4);
else
--RESET
temp <= "100000000";
end if;
end if;
random <= temp;
end process;
end architecture behaviour;
It was tested in Modelsim and compiled in Quartus II for a Cyclone III DE0 board.
Can anyone see why it is not working (in practice, the simulation is fine) and explain what I need to change to get it to work?
If reset is directly from a FPGA pin, then it is probably not synchronized
with clk, so proper synchronous reset operation is not ensured.
Add two flip-flops for synchronization of reset to clk before it is used in
the process. This can be done with:
...
signal reset_meta : bit; -- Meta-stable flip-flop
signal reset_sync : bit; -- Synchronized reset
begin
process(clk)
begin
if(clk'event and clk='1') then
reset_meta <= reset;
reset_sync <= reset_meta;
if (reset_sync = '0') then -- Normal operation
...
Altera have some comment about this in External Reset Should be Correctly
Synchronized.
The description covers flip-flops with asynchronous reset, but the use of two
flip-flops for synchronisation of external reset applies equally in your case.
Still remember to move the random <= temp inside the if as David pointed
out.
If you haven't any luck you might take a look at the synthesized schematic or perform post-synthesis simulation. I occasionally swap RTL models out for post - synth models for verification if there's something that isn't obvious in behavioral simulation.
-Jerry

Why it is necessary to use internal signal for process?

I'm learning VHDL from the root, and everything is OK except this. I found this from Internet. This is the code for a left shift register.
library ieee;
use ieee.std_logic_1164.all;
entity lsr_4 is
port(CLK, RESET, SI : in std_logic;
Q : out std_logic_vector(3 downto 0);
SO : out std_logic);
end lsr_4;
architecture sequential of lsr_4 is
signal shift : std_logic_vector(3 downto 0);
begin
process (RESET, CLK)
begin
if (RESET = '1') then
shift <= "0000";
elsif (CLK'event and (CLK = '1')) then
shift <= shift(2 downto 0) & SI;
end if;
end process;
Q <= shift;
SO <= shift(3);
end sequential;
My problem is the third line from bottom. My question is, why we need to pass the internal signal value to the output? Or in other words, what would be the problem if I write Q <= shift (2 downto 0) & SI?
In the case of the shown code, the Q output of the lsr_4 entity comes from a register (shift representing a register stage and being connected to Q). If you write the code as you proposed, the SI input is connected directly (i.e. combinationally) to the Q output. This can also work (assuming you leave the rest of the code in place), it will perform the same operation logically expect eliminate one clock cycle latency. However, it's (generally) considered good design practice to have an entity's output being registered in order to not introduce long "hidden" combinational paths which are not visible when not looking inside an entity. It usually makes designing easier and avoids running into timing problems.
First, this is just a shift register, so no combinational blocks should be inferred (except for input and output buffers, which are I/O related, not related to the circuit proper).
Second, the signal called "shift" can be eliminated altogether by specifying Q as "buffer" instead of "out" (this is needed because Q would appear on both sides of the expression; "buffer" has no side effects on the inferred circuit). A suggestion for your code follows.
Note: After compiling your code, check in the Netlist Viewers / Technology Map Viewer tool what was actually implemented.
library ieee;
use ieee.std_logic_1164.all;
entity generic_shift_register is
generic (
N: integer := 4);
port(
CLK, RESET, SI: in std_logic;
Q: buffer std_logic_vector(N-1 downto 0);
SO: out std_logic);
end entity;
architecture sequential of generic_shift_register is
begin
process (RESET, CLK)
begin
if (RESET = '1') then
Q <= (others => '0');
elsif rising_edge(CLK) then
Q <= Q(N-2 downto 0) & SI;
end if;
end process;
SO <= Q(N-1);
end architecture;

Resources