I'm woring on a project for an assingment where I need to be able write data to an avalon slave module to select data from 2 different inputs on a nios system running on a DE0 board. After much toiling, I've been unable to write data from the C app running on the nios core to the avalon slave. I have verified that I'm able to read data from the slave by using some hard coded values. I have also verified that my app is running because I'm seeing the messages I expect over the jtag uart, and the push buttons, LEDs and LED display work as expected.
I have simplified my slave so that data I write to it is then read straight back. The VHDL code is:
library ieee;
use ieee.std_logic_1164.all;
USE IEEE.NUMERIC_STD.ALL;
entity FIFO_Control is
port (clk : IN std_logic;
reset : IN std_logic;
read : IN std_logic;
readdata : OUT std_logic_vector(7 DOWNTO 0);
write : IN std_logic;
writedata : IN std_logic_vector(7 DOWNTO 0);
din1 : in std_logic_vector(4 DOWNTO 0);
din2 : in std_logic_vector(4 DOWNTO 0)
);
end FIFO_Control;
architecture FIFO_CTRL of FIFO_Control is
signal int_data : std_logic_vector(7 DOWNTO 0) := "00000000"; -- a hard coded test value to check the read works
begin
with (write) SELECT
int_data <= writedata when '1',
"01010101" when others;
readdata <= int_data;
end FIFO_CTRL;
The C code is
#include "sys/alt_stdio.h"
#include <altera_avalon_timer_regs.h>
#include <altera_avalon_pio_regs.h>
#include <system.h>
#include "Sch51.h"
#include "serial.h"
#include "seven_seg.h"
#define SEVEN_SEGMENT_0_BASE 0x1001080
#define LED_BASE (0x01001070)
#define LED0_pin (0x01)
#define LED1_pin (0x01 << 1)
#define LED2_pin (0x01 << 2)
#define LED3_pin (0x01 << 3)
#define PIO_1_BASE 0x0
#define BUTTON_BASE PIO_1_BASE
#define BUTTON0 0x01
#define BUTTON1 0x02
#define FIFO_CTRL_0_BASE 0x1001090
void LED_Flash_Update(void)
{
static count = 0;
alt_u8 read;
IOWR_8DIRECT(FIFO_CTRL_0_BASE, 0, 0);
read = IORD_8DIRECT(FIFO_CTRL_0_BASE, 0);
Serial_Printf("FIFO1: %d\r\n", read);
IOWR_8DIRECT(FIFO_CTRL_0_BASE, 0, 1);
read = IORD_8DIRECT(FIFO_CTRL_0_BASE, 0);
Serial_Printf("FIFO1: %d\r\n", read);
// Change the LED from OFF to ON (or vice versa)
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) ^ LED3_pin);
if (count < 10)
{
count++;
}
else if ((count >= 10) && (count < 100))
{
count += 10;
}
else if ((count >= 100) && (count < 1000))
{
count += 100;
}
else if ((count >= 1000) && (count < 10000))
{
count += 1000;
}
else
{
count = 0;
}
seven_seg_store_number(SEVEN_SEGMENT_0_BASE, 0, 9999, 10, count);
if ((IORD_ALTERA_AVALON_PIO_DATA(BUTTON_BASE) & BUTTON0) == 0)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) | LED0_pin);
}
else
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) & ~LED0_pin);
}
if ((IORD_ALTERA_AVALON_PIO_DATA(BUTTON_BASE) & BUTTON1) == 0)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) | LED1_pin);
}
else
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,
IORD_ALTERA_AVALON_PIO_DATA(LED_BASE) & ~LED1_pin);
}
}
int alt_main()
{
alt_u8 read;
SCH_Init_T0();
serial_Init();
SCH_Add_Task(serial_Update, 0, 10);
SCH_Add_Task(LED_Flash_Update, 0, 1000);
// Start the scheduler
SCH_Start();
Serial_Puts("EHMC AJE System Running\n");
/* Event loop never exits. */
while (1)
{
SCH_Dispatch_Tasks();
}
return 0;
}
I'm not able to see why I'm not able to write anything to the avalon slave "Fifo_control". Can someone suggest what the problem is please?
If you look at the port declarations on your entity/component and then at your code, you can already see that you are doing something wrong, as you are not using all the port.
So your problem states that you want to write data to your Avalon slave. So you want the component to remember the data you've written (i.e. memory). But there is no memory component in your code. There's just a combinatorial expression.
When designing an Avalon component, you should read the Avalon Interface Specification.
So reading the document, you see that you should have a process/statement for the write port and a process for the read port. Each takes a clock cycle to process (if the read latency is 1). E.g.
write_proc: process(clk) begin
if rising_edge(clk) then
if write = '1' then
int_data <= writedata;
end if;
-- reset statement
if reset = '1' then
int_data <= (others => '0');
end if;
end if;
end process;
read_proc: process(clk) begin
if rising_edge(clk) then
if read = '1' then
readdata <= int_data;
end if;
-- reset statement
if reset = '1' then
readdata <= (others => '0');
end if;
end if;
end process;
Related
I am implementing the following module:
library ieee;
use ieee.std_logic_1164.all;
entity Grant_Logic is
generic (
N : positive := 4
);
Port (
Priority_Logic0 : in std_logic_vector(N-1 downto 0);
Priority_Logic1 : in std_logic_vector(N-1 downto 0);
Priority_Logic2 : in std_logic_vector(N-1 downto 0);
Priority_Logic3 : in std_logic_vector(N-1 downto 0);
Gnt : out std_logic_vector (N-1 downto 0)
);
end Grant_Logic;
architecture Behavioral of Grant_Logic is
begin
gnt(0) <= Priority_Logic0(0) or Priority_Logic1(3) or Priority_Logic2(2) or Priority_Logic3(1);
gnt(1) <= Priority_Logic0(1) or Priority_Logic1(0) or Priority_Logic2(3) or Priority_Logic3(2);
gnt(2) <= Priority_Logic0(2) or Priority_Logic1(1) or Priority_Logic2(0) or Priority_Logic3(3);
gnt(3) <= Priority_Logic0(3) or Priority_Logic1(2) or Priority_Logic2(1) or Priority_Logic3(0);
end Behavioral;
I want to take advantage of for ... generate to implement the same circuit when N changes. I am using Xilinx so Vivado (vhdl'93) does not support custom types for ports in the IP generation.
However, for the architecture I would like to use for ... generate. The issue is that some logic is needed to generate each bit of gnt. What I have so far is:
gen_gnt_vertical: for y in 0 to N-1 generate
constant val, index : integer := 0;
begin
s_result <= '0';
gen_gnt_horizontal: for x in 0 to N-1 generate
begin
LOGIC BASED ON val, x and y to obtain the index
s_result <= s_result or s_Priority_Logic(x)(index);
end generate;
gnt(y) <= s_result;
end generate;
The logic to compute index is:
if(x>0)
{
val = y - x;
if (val < 0)
{
index = N + val;
}
else
index = val;
}
else
{
index = y;
}
I have a script that generates a vhdl file based on N but I would like to do it directly on vhdl. Is that possible?
Thanks for the help
EDIT: As #Tricky replied, a function did the trick. So, I have the following:
function index( N, x,y : natural) return natural is
variable val : integer;
variable index : integer := 0;
begin
if(x>0) then
val := y - x;
if(val < 0) then
index := N + val;
else
index := val;
end if;
else
index := y;
end if;
return index;
end function;
And the architecture:
architecture Behavioral of Grant_Logic is
signal s_Priority_Logic : t_Priority_logic;
signal s_result : std_logic_vector(N-1 downto 0) := (others=>'0');
begin
s_Priority_Logic(0) <= Priority_Logic0;
s_Priority_Logic(1) <= Priority_Logic1;
s_Priority_Logic(2) <= Priority_Logic2;
s_Priority_Logic(3) <= Priority_Logic3;
process(s_Priority_Logic)
variable result : std_logic;
begin
for y in 0 to N-1 loop
result := '0';
for x in 0 to N-1 loop
result := result or s_Priority_logic(x)(index(N, x, y));
end loop;
gnt_g(y) <= result;
end loop;
end process;
end Behavioral;
#Tricky using a function was the correct thing to get the index value. Alo for generate was not correct but for loop. I edited my question to show the final result
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/
i am trying to do an algorithm that verify prime numbers. To do this i have to make a circuit using RTL Design method, i am using the algorithm below to get the prime number:
int prime (int x) {
int i, div;
div = 0;
for (i = 1; i <= x; i++){
if (mod(x, i) == 0)
div++;
}
if (div == 2)
return 1; // PRIME
else
return 0; // NPRIME
}
To implement this solution I created two blocks: Datapath and Control like the image below:
My datapath has 4 intern blocks:
for_reg --> register that control the loop for of the prime algorithm (have a flag to indicate when the loop ends)
buffer --> Makes the output equal the input
modulo --> Get the mod of the div from the two inputs
comp --> Compare the output from modulo (if equal 0 the output of compare goes 1 else 0).
My control works comparing the input C (input C <= output_comp), if the comparison value is equal 1 I increment the signal div, after this i verify the value of the input flag, if is equal 1 i go to the finish state of the state machine that verify if the value of signal div is equal 2, if it is the output of control gets value 1, if not gets value 0 (1 - prime , 0 - not prime).
My problem is in the output of control block that stays always in 0. I've simulated all blocks separated and it seems to work correctly.
I believe the error is in the for_reg or in the control block, because the other blocks are simple and like I said before, its working correctly.
Below the simulation of the mod block:
PS.: I've used a state machine to create this block, when it gets on the final state automatically returns to the first state, so it's because of that the output stays always 0 and 3.
Below the codes from control and for_reg:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;
ENTITY verifica_primo_control IS
PORT (
i_CLK : IN STD_ULOGIC;
i_RST : IN STD_LOGIC;
i_C : IN STD_LOGIC;
i_FLAG : IN STD_LOGIC;
o_DOUT : OUT STD_LOGIC
);
END verifica_primo_control;
ARCHITECTURE arch_1 OF verifica_primo_control IS
TYPE state_type IS (s0, s1, s2, s3);
SIGNAL stateT : state_type;
SIGNAL w_AUX : integer;
BEGIN
PROCESS(i_CLK)
BEGIN
IF rising_edge(i_CLK) THEN
IF (i_RST = '1') THEN
stateT <= s0;
w_aux <= 0;
ELSE
CASE stateT IS
when s0 => IF (i_C = '1') THEN
stateT <= s1;
ELSE
stateT <= s3;
END IF;
when s1 => w_AUX <= w_AUX +1;
if (i_FLAG = '1') then
stateT <= s2;
else
stateT <= s0;
end if;
when s2 => IF (w_AUX = 2) THEN
o_DOUT <= '1';
ELSE
o_DOUT <= '0';
END IF;
when s3 =>
if (i_FLAG = '1') then
stateT <= s2;
else
stateT <= s0;
end if;
END CASE;
END IF;
END IF;
END PROCESS;
END arch_1;
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;
ENTITY for_reg IS
PORT (
i_CLR : IN STD_LOGIC;
i_CLK : IN STD_ULOGIC;
i_X : IN UNSIGNED (7 downto 0); -- number input to verify if its prime
i_I : IN UNSIGNED (7 downto 0) ;
o_FLAG : OUT STD_LOGIC;
o_II : OUT UNSIGNED (7 downto 0)
);
END for_reg;
ARCHITECTURE arch_1 OF for_reg IS
signal w_AUX : unsigned (7 downto 0);
BEGIN
PROCESS(i_CLK)
BEGIN
IF rising_edge(i_CLK) THEN
IF (i_CLR = '1') THEN
o_II <= "00000000";
w_AUX <= "00000000";
o_FLAG <='0';
ELSIF (i_CLR ='0' AND i_I < i_X) THEN
w_AUX <= i_I;
o_II <= w_AUX + "00000001";
o_FLAG <='0';
ELSIF (i_CLR = '0' AND i_I = i_X) THEN
o_II <= i_I;
o_FLAG <= '1';
END IF;
END IF;
END PROCESS;
END arch_1;
Like i said before, i believe the error is in one of this two blocks, i believe with that codes is possible verify where is the error. If this is not enough to have the MCVE warn me that i will update the post with the the other codes that is necessary to verify the error.
I am using the quartus II simulator, so I don't have a testbanch for this, I put all the test signals manually.
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.
After some advice on this site I've decided to use one clock FIFO. I've simulated it without errors before synthesizing it, after synthesize I've simulated code and I get this error:
** Warning: Read and Write to same address at same time. RD is unpredictable, driving RD to X
Time: 200877700 ps Iteration: 1 Instance: /testbench/FIFO/memory_tile_I_1
But simulations works like expected. After compiling I simulated again the code and I didn't get this error and simulation worked like expected.
My code is:
library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
entity FIFO is
Generic (
constant DATA_WIDTH : positive := 8;
constant FIFO_DEPTH : positive := 500
);
Port (
Clock : in STD_LOGIC;
WriteEn : in STD_LOGIC;
DataIn : in STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
ReadEn : in STD_LOGIC;
DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
Empty : out STD_LOGIC;
Full : out STD_LOGIC;
ModuleRESET : in STD_LOGIC
);
end FIFO;
architecture FIFO_archi of FIFO is
type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
signal Memory : FIFO_Memory;
signal Head : natural range 0 to FIFO_DEPTH - 1;
signal Tail : natural range 0 to FIFO_DEPTH - 1;
begin
-- Memory Pointer Process
process (Clock, ModuleRESET)
variable Looped : boolean;
begin
if ModuleRESET = '0' then
Head <= 0;
Tail <= 0;
Looped := false;
Full <= '0';
Empty <= '1';
DataOut <= (others => '0');
elsif rising_edge(Clock) then
if ReadEn = '1' then
if ((Looped = true) or (Head /= Tail)) then
-- Update data output
DataOut <= Memory(Tail);
-- Update Tail pointer as needed
if (Tail = FIFO_DEPTH - 1) then
Tail <= 0;
Looped := false;
else
Tail <= Tail + 1;
end if;
end if;
elsif WriteEn = '1' then
if ((Looped = false) or (Head /= Tail)) then
-- Write Data to Memory
Memory(Head) <= DataIn;
-- Increment Head pointer as needed
if (Head = FIFO_DEPTH - 1) then
Head <= 0;
Looped := true;
else
Head <= Head + 1;
end if;
end if;
end if;
-- Update Empty and Full flags
if (Head = Tail) then
if Looped then
Full <= '1';
else
Empty <= '1';
end if;
else
Empty <= '0';
Full <= '0';
end if;
end if;
end process;
end FIFO_archi;
I get this error every time I write the first data in simulation after synthesize(with synplify pro):
When I initialize the code and write first data
Every time I empty FIFO buffer and write first data
Of course I have Tail and Head at position 0 when my buffer is empty, but since I have two flags with an if-elseif istance, how it's possible I get an error on Read and Write same address?