VHDL code to read the inputs of a parallel AD converter - vhdl

I was wondering if someone could help me to find the error I am making when reading the analog input introduced to the AD7822 converter by a potentiometer capable of varying its voltage in a range of 0 to 5V.
As far as I understand what I have to do is to generate a 20ns wide pulse for the CONVST bit every 10MHz at most (starting from a clock operating at a maximum frequency of 50 MHz), then wait for the DR to be set to 0 and the value of the digital inputs could be taken.
Timeline for working with AD7822 in automatic mode
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity db_read is
generic
(
div : natural := 5
);
port
(
-- Input ports
clk_in : in std_logic;
rd : in std_logic;
db_input : in std_logic_vector (7 downto 0) := (others => '0');
-- Output ports
convst : out std_logic := '1';
db_output : out std_logic_vector (7 downto 0) := (others => '0')
);
end db_read;
-- Library Clause(s) (optional)
-- Use Clause(s) (optional)
architecture arch1 of db_read is
begin
----------------------------------------------------------------------
-- Send CONVST each div/50MHz ms.
----------------------------------------------------------------------
process(clk_in)
variable cont_convst : integer range 0 to div := 0;
begin
if (rising_edge(clk_in)) then
cont_convst := cont_convst + 1;
if (cont_convst = 1) then
convst <= '0';
else
convst <= '1';
end if;
if (cont_convst = div) then
cont_convst := 0;
end if;
end if;
end process;
----------------------------------------------------------------------
-- Read digital inputs when ready
----------------------------------------------------------------------
process(clk_in)
variable cont_rd : integer := 0;
begin
if (rising_edge(clk_in)) then
-- Detect if RD takes '0' value
if (rd = '0') then
cont_rd := cont_rd + 1;
end if;
if (cont_rd = 1) then
db_output <= db_input;
end if;
if (rd = '1') then
cont_rd := 0;
end if;
end if;
end process;
end arch1;
When I simulate it on a board what I see is that I always have all the outputs at high state regardless of the voltage that I introduce to the input of the converter.

Related

PWM controlled LED using VHDL

I've written the following VHDL code and test-bench to control the brightness of LEDs. Then tried with Altera ModelSim to simulate the code. However, I'm facing some technical difficulties. It would be really nice if someone will compile the code and share me the simulated result with me. Thanks in advance.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity main_testbench is
end main_testbench;
architecture behavior of main_testbench is
component led_controller is
Port ( clk, reset: in std_logic; -- system clock is assumed 10KHz
in_word: in std_logic_vector(7 downto 0); -- LS 4 bits - frequency & MS 4 bits - duty-cycle
LEDs: out std_logic_vector(3 downto 0));
end component;
signal clk, reset: std_logic := '0';
signal in_word: std_logic_vector(7 downto 0) := "00010001"; -- 0.2 Hz, 10% duty cycle
signal LEDs: std_logic_vector(3 downto 0) := "0000";
type in_word_commands is array (0 to 15) of std_logic_vector(7 downto 0);
signal in_words: in_word_commands := ("00010001", "00010010", "00010100", "00011000", -- 10% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
"00100001", "00100010", "00100100", "00101000", -- 30% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
"01000001", "01000010", "01000100", "01001000", -- 60% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
"10000001", "10000010", "10000100", "10001000"); -- 85% duty cycle with 0.2Hz, 0.5Hz, 1Hz, 2Hz
signal command_num : integer := 0;
begin
dut: led_controller port map (clk, reset, in_word, LEDs);
clk <= not clk after 50 us; -- 0.1ms/2 = 50us
command_num <= command_num + 1 after 5000 ms; -- 5000ms = 5s
in_word <= in_words(command_num);
end behavior;
controller:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
entity led_controller is
Port ( clk, reset: in std_logic;
in_word: in std_logic_vector(7 downto 0);
LEDs: out std_logic_vector(3 downto 0));
end led_controller;
architecture behavior of led_controller is
--------------------- signals ---------------------
type freq is array (0 to 3) of integer range 0 to 50000;
signal frq: freq := (25000, 10000, 5000, 2500);
signal led_freq_count: integer range 0 to 50000 := frq(0);
type d is array (0 to 3) of integer range 0 to 100;
signal duty: d := (10, 30, 60, 85);
signal duty_cycle: integer range 0 to 100 := duty(0);
signal LED_switch, new_command: std_logic := '0';
begin
--------- clock process / sync reset configuration ---------------
process (clk)
variable duty_counter: integer range 0 to 100 := 100;
variable freq_counter: integer range 0 to 50000 := led_freq_count;
begin
if rising_edge(clk) then
------- if reset was high or new in_word were arrived --------
if reset = '1' or new_command = '1' then
LEDs <= "0000";
duty_counter := 100;
freq_counter := led_freq_count;
new_command <= '0';
else
------- blinking process --------
if freq_counter = 0 then
freq_counter := led_freq_count;
LED_switch <= not LED_switch;
end if;
freq_counter := freq_counter - 1;
if duty_counter = 0 then
duty_counter := 100;
end if;
duty_counter := duty_counter - 1;
------ output assignment -------
if LED_switch = '1' and duty_counter < duty_cycle then
LEDs <= "1111";
else
LEDs <= "0000";
end if;
end if;
end if;
end process;
--------- input process---------------
process (in_word)
begin
case in_word(3 downto 0) is
when "0001" => led_freq_count <= frq(0);
when "0010" => led_freq_count <= frq(1);
when "0100" => led_freq_count <= frq(2);
when "1000" => led_freq_count <= frq(3);
when others => led_freq_count <= frq(0);
end case;
case in_word(7 downto 4) is
when "0001" => duty_cycle <= duty(0);
when "0010" => duty_cycle <= duty(1);
when "0100" => duty_cycle <= duty(2);
when "1000" => duty_cycle <= duty(3);
when others => duty_cycle <= duty(0);
end case;
new_command <= '1';
end process;
end behavior;
if freq_counter = 0 then
freq_counter := led_freq_count;
LED_switch <= not LED_switch;
else
freq_counter := freq_counter - 1;
end if;
if duty_counter = 0 then
duty_counter := 100;
else
duty_counter := duty_counter - 1;
end if;

Implementing a VHDL binary search on a std_logic_vector [vhdl]

I'm attempting to create synthesizable VHDL (function or procedure) for an ASIC (it must be part of the ASIC) that will look for the first '1' in a standard_logic_vector and output which vector position that '1' was in. For example, I have an 8-bit slv of "10001000" (a '1' in position 3 and 7). If I use this slv, the output should be 4 (the output is 1 based).
The actual VHDL will be searching a large slv, up to 512 bits in length. I tried implementing a binary search function but I get synthesis errors that states "Could not synthesize non-constant range values. [CDFG-231] [elaborate]
The non-constant range values are in file '...' on line 61" I indicated in the code below where it complains. I'm not sure how to implement a binary search algorithm without having non-constant range values. How would I modify this code so it's synthesizable?
I have attempted to search for binary search algorithms for HDL for potential code to look at and for my error, but I didn't find anything.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
entity bin_search is
generic (
constant NREGS : positive := 16 -- number of registers
);
port (
clk_i : in std_logic; -- clock
bin_i : in unsigned( NREGS-1 downto 0 ); -- input
en_i : in std_logic; -- input enable
addr_o : out natural range 0 to NREGS -- first binary location
);
end bin_search;
architecture rtl of bin_search is
function f_bin_search( input: unsigned; nob: positive ) return natural is
constant nbits : positive := 2**nob;
variable lower : natural range 0 to 1 := 0;
variable upper : natural range 0 to 1 := 0;
variable idx : natural range 0 to nob := 4;
variable cnt : natural range 0 to nbits := 0;
variable mid : positive range 1 to nbits := nbits/2; --
variable ll : natural range 0 to nbits := 0;
variable ul : positive range 1 to nbits := nbits; --
begin
if input = 0 then
cnt := 0;
return cnt;
else
loop1: while ( idx > 0 ) loop
if ( input( mid-1 downto ll ) > 0 ) then -- <===WHERE SYNTH COMPLAINS
lower := 1;
else
lower := 0;
end if;
if ( input( ul-1 downto mid ) > 0 ) then
upper := 1;
else
upper := 0;
end if;
if ( idx = 1 ) then
if ( lower = 1 ) then
cnt := mid;
else
cnt := ul;
end if;
elsif ( lower = 1 ) then
ul := mid;
mid := ( ( ll+ul )/2 );
elsif ( upper = 1 ) then
ll := mid;
mid := ( ll+ul )/2;
else
cnt := 0;
exit loop1;
end if;
idx := idx-1;
end loop loop1;
return cnt;
end if;
end f_bin_search;
begin
test_proc: process ( clk_i )
begin
if rising_edge( clk_i ) then
if en_i = '1' then
addr_o <= f_bin_search( bin_i, 4 );
end if;
end if;
end process test_proc;
end rtl;
Here's a simple test bench where the input is inc'd by '1'. The addr_o should be the location (1 based) of the input lsb with a '1'.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_misc.all;
use ieee.numeric_std.all;
entity bin_search_tb is
end bin_search_tb;
architecture behavior of bin_search_tb is
constant NREGS : positive := 16;
signal clk : std_logic;
signal input : unsigned( NREGS-1 downto 0 );
signal start : std_logic;
signal addr : natural range 0 to NREGS;
constant clk_per : time := 1 ns;
signal row : natural range 0 to 2**NREGS-1;
begin
bin_search_inst: entity work.bin_search( rtl )
generic map (
NREGS => NREGS
)
port map (
clk_i => clk, -- master clock
bin_i => input, -- captured events
en_i => start, -- start binary search
addr_o => addr -- addr where the first '1' appears
);
-- master clock process
clk_proc: process
begin
clk <= '0';
wait for clk_per / 2;
clk <= '1';
wait for clk_per / 2;
end process clk_proc;
--
stim1_proc: process
begin
input <= ( others => '0' );
start <= '0';
row <= 1;
wait until clk'event and clk = '1';
loop
wait until clk'event and clk = '1';
input <= to_unsigned( row, input'length );
start <= '1';
wait until clk'event and clk = '1';
start <= '0';
wait for 4*clk_per;
row <= row+1;
end loop;
end process stim1_proc;
end architecture behavior;
Thanks for your assistance!
-Jason
Edited code and added a testbench
Your design will most certainly depend on latency and other performance requirements, but, you could use some combination of or-reduction, sequencers (for mux selection of sliced vectors), shift register, and counters. I drew up a simple circuit that should find your lsb instance of "1" in ~30 clock cycles
The RTL translation that implements this design should be straight forward.
You say that you are thinking in hardware, but in fact you're not. Or you are misleading yourself.
input( mid-1 downto ll ) > 0
is not an OR-reduction, but a comparison operation. You must know > is the larger than comparison operator. The synthesis will therefor infer a comparator. But how many inputs must that comparator have, I ask? Well, there's your problem: it depends on the value of mid, which:
initially depends on the value of nbits, which depends on the value of nob which is a variable input for the function.
is changed within the loop. Thus it's value is not constant.
A hardware component cannot have a variable amount of wires.
But why do you want binary search? Why not keep-it-simple?
library ieee;
use ieee.std_logic_1164.all;
entity detect_one is
generic(
input_size : positive := 512);
port(
input : in std_logic_vector (input_size-1 downto 0);
output : out natural range 0 to input_size);
end entity;
architecture rtl of detect_one is
begin
main: process(input)
begin
output <= 0;
for i in input_size-1 downto 0 loop
if input(i)='1' then
output <= i+1;
end if;
end loop;
end process;
end architecture;
entity detect_one_tb is end entity;
library ieee;
architecture behavior of detect_one_tb is
constant input_size : positive := 512;
use ieee.std_logic_1164.all;
signal input : std_logic_vector (input_size-1 downto 0) := (others => '0');
signal output : integer;
begin
DUT : entity work.detect_one
generic map ( input_size => input_size )
port map(
input => input,
output => output);
test: process begin
wait for 1 ns;
assert (output = 0) report "initial test failure" severity warning;
for i in 0 to input_size-1 loop
input <= (others => '0');
input(i) <= '1';
wait for 1 ns;
assert (output = i+1) report "single ones test failure" severity warning;
end loop;
input <= (others => '1');
wait for 1 ns;
assert (output = 1) report "initial multiple ones test failure" severity warning;
for i in 0 to input_size-2 loop
input(i) <= '0';
wait for 1 ns;
assert (output = i+2) report "multiple ones test failure" severity warning;
end loop;
wait;
end process;
end architecture;

VHDL wrapper for 1-wire core for DS18B20 temperature sensor

currently I am trying to write a VHDL wrapper for this Opencore Verilog module (1-wire master) so that I can send/receive from this temperature sensor (DS18B20).
However I am struggling to understand the usage. Namely the read/write enable vs. the cyc bit in the control/status register of the 1-wire master module.
The code I have so far sets the cyc bit to 1 and the read/write enable to one simultaneously but does not cycle them during each bit. Is this correct or am I misunderstanding it? I'm new to VHDL/ reading a datasheet so I have been struggling over this for a few days. Any help would be appreciated.
I found this site that I have been using as a reference but it does not deal with the Verilog module that I am using.
I am also looking for tips on my code style, and VHDL tips in general.
My current code:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --may need to remove if signed not used
ENTITY one_wire_temp_probe_control IS
GENERIC (
one_us_divider_g : integer range 0 to 50 := 50 -- clock divider for one micro second
);
PORT (
i_clk_50mhz : IN STD_LOGIC;
i_read_enable : IN std_logic;
io_temp_probe : INOUT STD_LOGIC; --how do i register an inout
o_temperature : OUT signed(6 DOWNTO 0);
o_temp_ready : OUT std_logic
);
END one_wire_temp_probe_control;
ARCHITECTURE rtl of one_wire_temp_probe_control IS
----temp commands----
CONSTANT skip_rom_c : std_logic_vector(7 DOWNTO 0) := x"CC"; --command to skip ROM identity of temperature sensor
CONSTANT convert_temp_c : std_logic_vector(7 DOWNTO 0) := x"44"; --command to start temperature conversion
CONSTANT read_scratchpad_c : std_logic_vector(7 DOWNTO 0) := x"BE"; --command to read the scratchpad i.e. get temperature data
CONSTANT command_bits_c : integer RANGE 0 TO 8 := 8; --number of bits in the above commands (note: range used to limit number of bits to minimum needed)
CONSTANT data_bits_c : integer RANGE 0 to 12 := 12; --number of bits in received data
----1-wire commands----
CONSTANT send_reset_pulse : std_logic_vector(7 DOWNTO 0) := "00001010"; --command to send reset pulse
CONSTANT write_command_structure_c : std_logic_vector(6 DOWNTO 0) := "0000000"; --structure of the command that must be passed to the 1-wire controller (----EDIT----)
----timing constants----
CONSTANT delay_65us_c : integer := one_us_divider_g * 65; --65 micro-second delay
CONSTANT delay_960us_c : integer := one_us_divider_g * 960; --960 micro-second delay
CONSTANT delay_750ms : integer := one_us_divider_g * 1000 * 750; --760 milli-second delay
----state machine----
TYPE state_type IS (idle, presence_pulse, wait_presence_pulse, skip_rom, temp_conversion, wait_for_conversion,
read_scratchpad, data_read, convert_data, wait_65us);
SIGNAL state : state_type := idle;
SIGNAL previous_state : state_type := idle;
----1-wire----
SIGNAL read_enable_s, write_enable_s, reset_s, owr_e_s : std_logic := '0';
SIGNAL write_data_s, read_data_s : std_logic_vector(7 DOWNTO 0):= (OTHERS => '0'); --8 bit mode chosen in sockit_owm
SIGNAL address_s : std_logic_vector(1 DOWNTO 0) := "00";
SIGNAL timer_s : integer := 0;
----commands---
SIGNAL bit_counter_command_s : integer RANGE 0 TO command_bits_c := 0; --counter for bits in commands (note: not -1 due to using 9th bit as state change)
SIGNAL bit_counter_data_s : integer RANGE 0 TO data_bits_c := 0; --counter for bits in data recieved
----temperature----
SIGNAL temperature_raw_data : std_logic_vector(11 DOWNTO 0) := (OTHERS => '0');
----one wire control----
COMPONENT sockit_owm IS
PORT (
----control interface----
clk : IN std_logic;
rst : IN std_logic;
bus_ren : IN std_logic;
bus_wen : IN std_logic;
bus_adr : IN std_logic_vector(7 DOWNTO 0);
bus_wdt : IN std_logic_vector(7 DOWNTO 0);
bus_rdt : OUT std_logic_vector(7 DOWNTO 0);
bus_irq : OUT std_logic;
----1-wire interface----
owr_p : OUT std_logic; --verilog code is a one bit wide vector
owr_e : OUT std_logic;
owr_i : IN std_logic
);
END COMPONENT;
BEGIN
address_s <= "00"; --for the temp probe control we're not interested in other address spaces
PROCESS(i_clk_50mhz) BEGIN --state change
IF rising_edge(i_clk_50mhz) THEN
CASE state is
WHEN idle =>
o_temp_ready <= '0';
IF (i_read_enable = '1') THEN
state <= presence_pulse;
ELSE
state <= idle;
END IF;
WHEN presence_pulse =>
----send reset/presence pulse----
write_enable_s <= '1';
write_data_s <= send_reset_pulse;
timer_s <= delay_960us_c;
state <= wait_presence_pulse;
WHEN wait_presence_pulse =>
----wait for 960 micro seconds----
read_enable_s <= '1';
IF (timer_s = 0) THEN
IF (read_data_s(0) = '0') THEN
state <= skip_rom;
ELSIF (read_data_s(0) = '1') THEN
--precence not detected
ELSE
state <= wait_presence_pulse;
END IF;
ELSE
timer_s <= timer_s - 1;
state <= wait_presence_pulse;
END IF;
WHEN skip_rom =>
----send skip rom command----
previous_state <= skip_rom;
write_enable_s <= '1';
IF (bit_counter_command_s = command_bits_c) THEN
bit_counter_command_s <= 0;
state <= temp_conversion;
ELSE
write_data_s <= write_command_structure_c & skip_rom_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN temp_conversion =>
----send temp conversion command to probe----
previous_state <= temp_conversion;
IF (bit_counter_command_s = bit_counter_command_s) THEN
bit_counter_command_s <= 0;
timer_s <= delay_750ms;
state <= wait_for_conversion;
ELSE
write_data_s <= write_command_structure_c & convert_temp_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN wait_for_conversion =>
----wait for temperature conversion to finish----
IF (timer_s = 0) then
state <= read_scratchpad;
ELSE
timer_s <= timer_s - 1;
END IF;
WHEN read_scratchpad =>
----send read scratchpad command----
previous_state <= read_scratchpad;
IF (bit_counter_command_s = command_bits_c) THEN
state <= data_read;
bit_counter_command_s <= 0;
ELSE
write_data_s <= write_command_structure_c & read_scratchpad_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN data_read =>
----read incoming data----
previous_state <= data_read;
read_enable_s <= '1';
IF (bit_counter_data_s = data_bits_c) THEN
bit_counter_data_s <= 0; --may need to invert this
state <= convert_data;
ELSE
temperature_raw_data(bit_counter_data_s) <= read_data_s(0);
bit_counter_data_s <= bit_counter_data_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN convert_data =>
----convert raw data into temperature----
o_temp_ready <= '1';
WHEN wait_65us =>
----wait for read/write cycle to finish----
IF (timer_s = 0) THEN
state <= previous_state;
ELSE
timer_s <= timer_s - 1;
state <= wait_65us;
END IF;
END CASE;
END IF;
END PROCESS;
----one wire component instantiation----
one_wire_control : sockit_owm
PORT MAP(
----control interface----
clk => i_clk_50mhz,
rst => reset_s,
bus_ren => read_enable_s,
bus_wen => write_enable_s,
bus_adr => address_s,
bus_wdt => write_data_s,
bus_rdt => read_data_s,
bus_irq => OPEN,
----1-wire interface----
owr_p => OPEN,
owr_e => owr_e_s,
owr_i => io_temp_probe
);
io_temp_probe <= owr_e_s ? '0' : 'Z'; --I also need help converting this line to VHDL
END rtl;
Thank you in advance.
Best
Tom
I am also looking for tips on my code style, and VHDL tips in general.
OK.
First thing: don't make the lines so long. So don't put comments at the end of a line. Put them a line before.
use IEEE.NUMERIC_STD.ALL; --may need to remove if signed not used
then remove, as I don't see any signed
one_us_divider_g : integer range 0 to 50 := 50 -- clock divider for one micro second
So... what happens is one_us_divider_g is set to 0? Seems an illegal value. Using it for simulation?
io_temp_probe : INOUT STD_LOGIC; --how do i register an inout
One option is to use a tristate IOBUFFER. This is a special FPGA edge element which splits the input and output to separate signals. You can tristate the ouput by setting a control port.
Alternatively you could just do it the way you do in your code (this is also explained in for instance the Xilinx synthesis user guide). Which leads me to another question in your code.
io_temp_probe <= owr_e_s ? '0' : 'Z'; --I also need help converting this line to VHDL
io_temp_probe <= '0' when owr_e_s = '1' else 'Z';
CONSTANT command_bits_c : integer RANGE 0 TO 8 := 8;
No need for an integer range if it is a constant.
CONSTANT send_reset_pulse : ...
CONSTANT delay_750ms : ...
Missing the "_c" you put behind all your constants. But I would not add this "s", "_c" or "_g" anyhow. A lot of work for little gain.
COMPONENT sockit_owm IS
PORT (
[...]
);
END COMPONENT;
Component declarations are not required anymore since some time now. You can remove it and change your instantiation:
one_wire_control : entity work.sockit_owm
PORT MAP(
[...]
WHEN idle =>
[...]
ELSE
state <= idle;
END IF;
not required. If you don't change state, it stays at idle.
WHEN wait_presence_pulse =>
IF (timer_s = 0) THEN
IF (read_data_s(0) = '0') THEN
[...]
ELSIF (read_data_s(0) = '1') THEN
[...]
ELSE
state <= wait_presence_pulse;
END IF;
read_data_s(0) '0' and '1' are covered. Do you expect any other value? That can only happen in simulation, not in implementation. So the code in the last else-statement is unreachable then.
[...]
timer_s <= delay_65us_c;
state <= wait_65us;
[...]
WHEN wait_65us =>
IF (timer_s = 0) THEN
[...]
ELSE
timer_s <= timer_s - 1;
END IF;
Let's say a delay is 65 us lasts 10 clock cycles. Setting the divider to 1, delay_65us_c=10. So at t=0, timer_s is set to 10. at t=1 -state is wait_65us now- timer_s is set to 9. And so on: at t=10, timer_s is set to 0... but state is still wait_65us. So at t=11, timer_s is detected 0, and state is changed to the previous one. Which it will enter at t=12.
So, instead of a 10 clock cycle delay, you get a 12 clock cycle delay.
Is this a problem? If yes, you should reconsider your code.
SIGNAL read_enable_s, write_enable_s, reset_s, owr_e_s : std_logic := '0';
[... not used anywhere else... ]
one_wire_control : sockit_owm
PORT MAP(
[...]
rst => reset_s,
Are you sure this is correct? A lot of components need to be properly reset before they operate correctly.
If you're working with Quartus, you can mix VHDL code with Verilog and even schematic elements. In the link below, I use a verilog driver for the same chip (DS18B20).
See here for details:
https://physnoct.wordpress.com/2016/12/14/altera-quartus-combining-verilog-and-vhdl/

Self implemented UART in VHDL always skips second character

I am learning VHDL right now and I tried to implement UART (1 start bit, 8 data bits, 1 stop bit) to periodically send a hardcoded string.
Everything works as expected - I receive string every 1 second. However, there is no second character.
No matter how long the string is, which character it is. I checked this fact on a oscilloscope and there is no waveform for this particular character. 1 start bit, 8 bits for first character, stop bit, start bit and 8 bits for third character, not the second one.
Following code is for 10 MHz clock divided to send with ~38 400 bits per second, I also tried with 9600 bits per second, both the same problem.
I'm using Altera MAX10 dev board: http://maximator-fpga.org/
Short video how it works:
https://gfycat.com/JoyousIlliterateGuillemot
UART.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.ALL;
use ieee.std_logic_arith.all;
entity UART is
port (
clk_10mhz: in STD_LOGIC;
txPin: out STD_LOGIC
);
end entity;
architecture Test of UART is
signal txStart: STD_LOGIC;
signal txIdle: STD_LOGIC;
signal txData: STD_LOGIC_VECTOR(7 downto 0);
component TX is
port (
clk_in: in STD_LOGIC;
start: in STD_LOGIC;
data: in STD_LOGIC_VECTOR(7 downto 0);
tx: out STD_LOGIC;
txIdle: out STD_LOGIC
);
end component TX;
begin
process (clk_10mhz, txIdle)
variable clkDividerCounter : integer range 0 to 10000000;
variable textToSend : string(1 to 31) := "Hello darkness my old friend!" & CR & LF;
variable currentCharacterIndex : integer range 0 to 31;
begin
if (rising_edge(clk_10mhz)) then
if (clkDividerCounter < 10000000) then
clkDividerCounter := clkDividerCounter + 1;
else
clkDividerCounter := 0;
currentCharacterIndex := 1;
end if;
if (txIdle = '1' and currentCharacterIndex > 0) then
txData <= CONV_STD_LOGIC_VECTOR(character'pos(textToSend(currentCharacterIndex)),8);
txStart <= '1';
if (currentCharacterIndex < 31) then
currentCharacterIndex := currentCharacterIndex + 1;
else
currentCharacterIndex := 0;
txStart <= '0';
end if;
end if;
end if;
end process;
u1: TX port map (clk_10mhz, txStart, txData, txPin, txIdle);
end Test;
TX.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.ALL;
entity TX is
port (
clk_in: in STD_LOGIC;
start: in STD_LOGIC;
data: in STD_LOGIC_VECTOR(7 downto 0);
tx: out STD_LOGIC;
txIdle: out STD_LOGIC
);
end entity;
architecture Test of TX is
signal idle: STD_LOGIC;
begin
process (clk_in)
variable bitIndex : integer range 0 to 9;
variable clkDividerCounter : integer range 0 to 260;
variable dataFrame : STD_LOGIC_VECTOR(9 downto 0);
variable dataFrameCurrentIndex : integer range 0 to 9;
begin
if (rising_edge(clk_in)) then
if (start = '1' and idle = '1') then
dataFrame(0) := '0';
dataFrame(8 downto 1) := data;
dataFrame(9) := '1';
dataFrameCurrentIndex := 0;
idle <= '0';
end if;
if (idle = '0') then
if (clkDividerCounter < 260) then
clkDividerCounter := clkDividerCounter + 1;
else
if (dataFrameCurrentIndex <= 9) then
tx <= dataFrame(dataFrameCurrentIndex);
dataFrameCurrentIndex := dataFrameCurrentIndex + 1;
else
idle <= '1';
end if;
clkDividerCounter := 0;
end if;
end if;
txIdle <= idle;
end if;
end process;
end Test;
Move the line
txIdle <= idle;
from TX.vhd outside the process. Signals take their new value after the process ends.
For example:
idle <= '0';
txIdle <= idle;
Will set txIdle to '1' if idle was '1' when the two statements were executed inside a process. You should notice that this means that txIdle will be '1' for two consecutive cycles and causes currentCharacterIndex to increment twice at the start.
Note that contrary to signals, variable take their new value when the assigning statement is encountered, and not at the end of the process as signals do.
While your code is not that terrible for a beginner, I recommend to use only signal when you start learning VHDL. It is much easier to make mistake with variables, or describe sub-optimal or broken implementation.
Also, as Brian mentioned, don't use std_logic_arith, especially when using numeric_std. They are conflicting with each other (some tools deal with it though) and std_logic_arith is not a IEEE standard, while numeric_std is.
Finally, simulation is a crucial part of hardware design. To avoid uninitialized pin, add a reset to your circuit, which is generally a good idea.

How do you make vhdl counter that can count in tenths of a millisecond?

I am working on an IR Decoder in VHDL and I know that the widths of an IR 1 bit is 1.2 ms, an IR 0 bit is 0.6 ms, and the start bit is 2.5 ms. I am trying to make a counter that takes in the 50MHz clock and converts to tenths of a millisecond. How can I do this?
entity counter is
Port ( EN : in STD_LOGIC;
RESET : in STD_LOGIC;
CLK : in STD_LOGIC;
COUNT : out STD_LOGIC_VECTOR (4 downto 0));
end counter;
architecture Behavioral of counter is
constant max_count : integer := (2);
begin
startCounter: process(EN, RESET, CLK)
variable cnt : integer := 0;
variable div_cnt : integer := 0;
begin
if (RESET = '1') then
cnt := 0;
div_cnt := 0;
elsif (EN = '1' and rising_edge(CLK)) then
if (cnt = max_count) then
cnt := 0;
div_cnt:= div_cnt + 1;
else
cnt := cnt + 1;
end if;
end if;
COUNT <= conv_std_logic_vector(cnt, 5);
-- COUNT <= temp_count(16 downto 13);
end process startCounter;
end Behavioral;
Since you have a 50 MHz clock and want to generate a 0.1 msec pulse, you can use the ieee library, math_real, to compute the number of 50 MHz clocks to create a 0.1 msec pulse. Here's a code fragment.
library ieee;
use ieee.math_real.all;
-- omitting for clarity...
-- generate one clk cycle pulse with period of 0.1 msec
gen_0p1mspulse_p : process(Clk)
constant CLK_PERIOD : real := 1/50e6;
constant PULSE_PERIOD : real := 0.1e-3;
constant MAX_CNT : integer := INTEGER(PULSE_PERIOD/CLK_PERIOD);
variable cnt : integer range 0 to MAX_CNT-1 := 0;
begin
if rising_edge(Clk) then
if reset = '1' then
cnt := 0;
pulse_0p1msec <= '0';
else
pulse_0p1msec <= '0'; -- default value
if cnt < MAX_CNT-1 then
cnt := cnt + 1;
else
cnt := 0;
pulse_0p1msec <= '1';
end if;
end if;
end if;
end process;
-- logic using 0.1 msec pulse
your_logic_p : process(Clk)
begin
if rising_edge(Clk) then
if reset = '1' then
your_cnt := 0;
else
if pulse_0p1msec = '1' then
-- insert your logic here
end if;
end if;
end if;
end process;
I like to split up my VHDL processes so that they're short. I also prefer to use synchronous resets and enables since they synthesize to less hardware for Xilinx FPGAs as well as running at a higher clock rates. Hope that addresses your issue.

Resources