- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm trying to build a RAM function that will write data to RAM then take the average of the array for N samples.
My current problem is that (in simulation) I cannot get variables to hold their value outside the states where their value is explicitly stated (i.e. sum := 0). This is causing an issue with the sum variable as I cannot calculate the sum of the array. I suspect that this issue is the result of the way I have my state machine setup. I'm also having issues with zero time oscillations when i use the statement sum := sum + ram_data. I can see how this would cause the osculations however i have seen this method used to increment a variable so I'm confused as to why it cannot be used to add something other than a constant to a variable. I apologize for portions of the code being awkward. I've been beating my head and trying different things for a while.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.Numeric_Std.all;
entity WriteAverage is
port(
Dready, Sclk, reset: in std_logic;
Data: in std_logic_vector (15 downto 0);
RDataIn: in std_logic_vector (15 downto 0);
Nsamples: in std_logic_vector (7 downto 0);
Raddr: out std_logic_vector (7 downto 0);
Rdata: out std_logic_vector (15 downto 0);
Average: out std_logic_vector (15 downto 0);
Rclk, We, AvgDone: out std_logic;
state: out std_logic_vector (3 downto 0);
test2, sum_temp_out:out std_logic_vector (15 downto 0);
test: out std_logic_vector (7 downto 0)
);
end;
architecture state of WriteAverage is
signal Next_state : integer range 0 to 15;
signal Current_state : integer range 0 to 15;
begin
state <= (std_logic_vector(to_unsigned(current_state, 4)));
PROCESS (Sclk, Next_state)
BEGIN
IF (reset = '0') THEN -- if we get a reset input from the blue push button, return to the idle state at any time
Current_state <= 0;
ELSIF (rising_edge (Sclk)) THEN
Current_state <= Next_state;
END IF;
END PROCESS;
PROCESS(Sclk, Dready, Data, NSamples, RDataIn)
variable Waddress :integer range 0 to 255; --write addr location
variable Waddress_temp :integer range 0 to 255;
variable Raddress :integer range 0 to 255; --read addr location
variable Raddress_temp :integer range 0 to 255;
variable Nsamples_int :integer range 0 to 255;
variable sum :integer range 0 to 16777215;
variable sum_temp1, sum_temp2 :integer range 0 to 16777215;
variable avg :integer range 0 to 16777215;
Begin
Next_state <= Current_state;
Nsamples_int := 2; --to_integer(unsigned(Nsamples));
test <= RDataIn (7 downto 0);
test2 <= (std_logic_vector(to_unsigned(sum, 16)));
sum_temp_out <= (std_logic_vector(to_unsigned(sum_temp1, 16)));
Rclk <= '0';
if (current_state = 0) then --reset state machine
waddress := 0; --reset write address
Next_state <= 1;
elsif (Current_state = 1)then --idle
We <= '1'; --enable RAM write
Raddress := 0; --set initial read addr = 0
Raddress_temp := 0;
avg := 0; --reset average
sum := 0; --reset sum of array
AvgDone <= '0';
if (Dready ='0') then --for testing, was 1
Next_state <= 2;
end if;
elsif (Current_state =2) then
Rdata <= Data; --ram data = data input
if (Waddress = Nsamples_int) then --if write addres = max address...
Waddress := 0; --loop to top of array
end if;
Raddr <= (std_logic_vector(to_unsigned(Waddress, 8))); --ram addr = write address
Next_state <= 3;
elsif (Current_state = 3) then
Rclk <= '1'; --clk ram
Waddress_temp := Waddress; --part 1 incrimenting write address, trying to prevent zero time oscilation
Next_state <= 4;
elsif (Current_state = 4) then
We <= '0'; --enable ram read
waddress := Waddress_temp + 1; --part 2 incriment write address
Next_state <= 5;
elsif (Current_state = 5) then --doing nothing ATM
Next_state <= 6;
elsif (Current_state = 6) then
--if (Raddress = Nsamples_int) then --comented out for testing
-- Next_state <= 10; --if read address = aray siize finish sum of array
--else
Next_state <= 7;
--end if;
elsif (Current_state = 7) then
Raddr <= (std_logic_vector(to_unsigned(Raddress, 8))); --ram addr = next array location to be read
Next_state <= 8;
elsif (Current_state = 8) then
Rclk <= '1'; --clk ram
Raddress_temp := raddress; --part 1 readd addr incriment, trying to prevent z-time osc
sum_temp2 := sum; --trying to add ram data to sum of array
sum_temp1 := to_integer(unsigned(RDataIn)); --trying to add ram data to sum
Next_state <= 9;
elsif (Current_state = 9) then
sum := sum_temp2 + sum_temp1; --trying to add ram data to sum
Raddress := Raddress_temp + 1; --go to next ram address
Next_state <= 6;
elsif (Current_state = 10) then
avg := sum / Nsamples_int; --average sum of array
Average <= std_logic_vector(to_unsigned(sum, 16)); --output avg
AvgDone <= '1';
Next_state <= 11;
elsif (Current_state = 11) then --wait for Dready = 0 before idle
if (Dready = '1') then --for testing, was 0
Next_state <= 1; --go to idle
end if;
end if;
END PROCESS;
END;
Link Copied
3 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Following the behavior of your code is difficult (for me at least) due to your use of a large collection of signals in the sensitivity list. Try working with just one process using the following framework:
PROCESS (Sclk, reset ) --do not add items here
BEGIN
IF (reset = '0') THEN
--put everything you want to initialize/re-initialize here
ELSIF (rising_edge (Sclk)) THEN
--put ALL of your other code here
END IF;
END PROCESS;
Using this framework, your debugging should go much smoother. As a side note, I normally don't use variables if I can help it. It makes the logic much easier to follow for me.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
the problem is all of your outputs are in the asynchronous process, and as such you will create latches which are frownd upon, and things like counters should never be in an asynchronous process.
Id go with what Kosh says - go with the single process state machine format - forget the old fashioned tutorials that show the 2 state machine process - its a little old hat.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I beg to differ: there is nothing wrong using the 2-process state machine approach nor with using variables. You just have to be careful.
The 2-process state machine, maybe be old but certainly not out of fashion. It allows you to generate both combinatorial and synchronous outputs. If you use the 1-process synchronous approach and you need combinatorial outputs, e.g. a master state machine controlling a number of slave state machines or stimulating an external device, you still have to create a second combinatorial process where you have to decode the same conditions as in the synchronous process. I do agree that we may not need combinatorial signals that often. Variables, local to the process, are fine but you must of course be fully aware of the behaviour of a variable in VHDL. You could compare it to the variable in a C function, which doesn't hold its value between calls. If that is necessary you have to use either a global variable (a signal in VHDL) or the 'static' attribute (no matching VHDL construct) to preserve the value until the next call. In VHDL a process is activated for every change in the sensitivity list, which is kind of analogous to calling a C-function. If you need persistence e.g. a counter you cannot use a variable but resort to a signal (declared outside the process).
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page