Untitled
unknown
plain_text
9 months ago
25 kB
6
Indexable
consider these instructions: The task of the Assignment is to design and implement a peak detection system with modules, including the peak detector, data source and communication links based on UART. With an external computer, multiple commands can be sent through the UART link to control the peak detector to implement the required functions. All of the logic in the design including the UART and data generator will be implemented in an FPGA device from Xilinx called Artix 7. This device sits on a full development board which provides a 12 MHz clock as well as various I/O and other peripheral and control circuitry. The UART link is provided through a mini USB port and implements the RS232 protocol which is purely serial. The input and output serial lines are available at two I/O pins in the FPGA device. Details of the RS232 protocol are provided later in the document, and the VHDL code for both the Rx and Tx are provided.
The data generator, for which the code is also provided, has access to 500 bytes of data, and will provide a byte at a time upon request, with requests governed by a 2-phase handshaking protocol. Details will again be provided later in the document, but essentially, the data generator has an input control line and an output control line. When it sees a transition on the input control line (i.e. a '0' to '1' or '1' to '0' transition), it will provide a new byte on 8 parallel data lines, and change the value of its output control line; i.e. if it was '0' previously, it will transition to '1', and vice-versa. This transition on its output control line is a signal to the data acquisition module that data is valid. After the data has been latched, the consumer should effect a transition on the input to the data generator to request a new byte. Once all 500 bytes have been provided, the data generator will revert to the first byte in the sequence and keep cycling through the sequence.
The task of the peak detector is to process a number of words as typed in by the user in the terminal, and return the peak byte along with the three bytes that precede and follow it in the sequence, with the value interpreted according to unsigned or signed formats based on your group number. It should also return the index of the peak byte in the sequence. If multiple peaks are detected in a single data sequence, the first is to be retained. The design is to be implemented on the CMOD A7board with a Artix 7 device running on a 100 MHz system clock (the 100 MHz clock is generated from the 12 MHz on-board clock by using a clock-conditioning IP block). It should use the 3 supplied modules with no modifications: a Receiver and Transmitter that implement the RS232 protocol, and a Data Generator that supplies a byte at a time under the control of a 2-phase handshaking protocol.
So basically, there are 2 components we need to develop - a data procesor, which will retrieve data from a data generator using a handshake protocol (entity will be provided), find the peak value and output it to the command processor. the command processor is not the focus for us now. Upon detection of a valid start command, the number of bytes specified should be processed without interruption. Each byte should be printed in hexadecimal format. The start command is valid at any point as long as data processing is not taking place. The behaviour when a user command is typed in the middle of processing a sequence is undefined. One important consequence of the UART serial link protocol and the baud rate is that the serial signalling rate is much less than the clock frequency. The clock frequency of 100 MHz is over four orders of magnitude higher than the 9600 baud rate over the serial link. As a consequence, data retrieval needs to be halted periodically while the slow serial communication completes. This is effected by the start signal. A data retrival cycle is initiated by start being driven high. The Data Consumer should check this value on a rising edge of the clock. The value of start being high at the beginning of a clock cycle is a signal for data retrieval to take place; if the value is low, data retrieval will not take place. Used to start and halt data retrieval in the Data Processor, while the Command Processor communicates with the PC via the serial link, which operates at a much lower frequency than the clock rate. numWords A 12 bit wide set of data lines that contain the number of bytes to process, in binary-coded-decimal (BCD) format. Each decimal digit is encoded in 4 bits.
dataReady Asserted (active-high) by the Data Processor to signify that a new byte of data that has been supplied by the Data Generator is ready on the 8-bit byte line.
byte Contains the latest 8-bits wide data word retrieved from the Data Generator. Data is valid when dataReady is high.
seqDone Asserted (active high) for one clock cycle when the number of bytes specified in numWords has been processed, and the 7 bytes comprising the peak and the 3 bytes either side of it are contained in dataResults, which is 56 bits wide.
dataResults A 56-wide set of lines that contain the 7 bytes comprising the peak in the middle (i.e. bit indices 31 down to 23), and the 3 bytes either side of it. Data is valid when seqDone is high.
maxIndex Contains the index of the peak byte in BCD format.The control lines ctrl_1 and ctrl_2 are shared between the Data Processor and Data Generator, and are operated in accordance with the two-phase protocol described. Here is the entity given: library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.common_pack.all;
entity dataConsume is
port (
clk : in std_logic;
reset : in std_logic;
start : in std_logic;
numWords_bcd: in BCD_ARRAY_TYPE(2 downto 0); -- BCD-coded #words
ctrlIn : in std_logic; -- handshake from prior stage
ctrlOut : out std_logic; -- handshake toggled to request next byte
data : in std_logic_vector(7 downto 0);
dataReady : out std_logic; -- single-cycle "data is done" pulse
byte : out std_logic_vector(7 downto 0);
seqDone : out std_logic; -- single-cycle "all done" pulse
maxIndex : out BCD_ARRAY_TYPE(2 downto 0);
dataResults : out CHAR_ARRAY_TYPE(0 to RESULT_BYTE_NUM - 1)
);
end dataConsume;. Now I will send you a code that outputs fully correct simulation results. Then, the second file will be my code, and although it will compile and seems correct, the results are wrong. Its important that you have a sequential and combinatorial process. the comb logic can only assign states, and the sequential will say what happens during these states, update values etc. The combinational logic takes the current state and other inputs and determines what the next state is. The state registers just store the current state. here are the 2 codes, and find the problems in the second one: library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.common_pack.all;
entity dataConsume is
port(
clk: in std_logic;
reset: in std_logic;
start: in std_logic;
numWords_bcd: in BCD_ARRAY_TYPE(2 downto 0);
data: in std_logic_vector(7 downto 0);
ctrlIn: in std_logic;
ctrlOut: out std_logic;
dataReady: out std_logic;
seqDone: out std_logic;
byte: out std_logic_vector(7 downto 0);
maxIndex: out BCD_ARRAY_TYPE(2 downto 0);
dataResults: out CHAR_ARRAY_TYPE(0 to 6)
);
end dataConsume;
--------------------------------------------------------- SIGNAL DECLARATION ---------------------------------------------------------
architecture Behavioral of dataConsume is
-- define custom types for use within architecture
type state_type is (IDLE, PROCESS_DATA, WAIT_CMDP, CHECK_COMPLETE);
type signed_array is array (integer range <>) of signed(7 downto 0);
-- signals for managing state transitions
signal curr_state, next_state: state_type;
-- signals for two phase protocol logic
signal prev_ctrlIn, ctrlOut_state: std_logic := '0';
signal edge_detected_ctrlIn: std_logic := '0';
-- signals for counter and numWords as integer
signal numWords_int: integer := 0;
signal counter: integer := 0;
-- signals for the peak detection algorithm
signal peak_value: signed(7 downto 0) := (others => '0');
signal lastThreeBytes: signed_array(0 to 2) := (others => (others => '0'));
signal update_next_values: integer := 0;
-- enable signals and counter reset
signal en_updateCounter: boolean := FALSE;
signal en_bcdToInt: boolean := FALSE;
signal en_peakDetection: boolean := FALSE;
signal en_byteOutput: boolean := FALSE;
signal en_reset: boolean := TRUE;
begin
--------------------------------------------------------- STATE MACHINE ---------------------------------------------------------
--------------------------------
-- State Machine Transitions
--------------------------------
StateMachine: process(clk, reset)
begin
if rising_edge(clk) then
if reset = '1' then
curr_state <= IDLE;
else
curr_state <= next_state;
end if;
end if;
end process;
--------------------------------------
-- Next State Logic
--------------------------------------
combi_next: process(curr_state, start, edge_detected_ctrlIn, counter, numWords_int)
begin
case curr_state is
when IDLE => -- Remain idle until start signal goes high, synchronising us with command processor
if start = '1' then
next_state <= PROCESS_DATA;
else
next_state <= IDLE;
end if;
when PROCESS_DATA => -- Processing incoming bytes, finding peak and storing values in DataResults
if edge_detected_ctrlIn = '1' then
next_state <= WAIT_CMDP;
else
next_state <= PROCESS_DATA;
end if;
when WAIT_CMDP => -- Waiting for start from command processor or first run through
if start = '1' or counter = 1 then
next_state <= CHECK_COMPLETE;
else
next_state <= WAIT_CMDP;
end if;
when CHECK_COMPLETE => -- If we haven't reached the number of words we need to process, keep processing
if counter < numWords_int then
next_state <= PROCESS_DATA;
else
next_state <= IDLE;
end if;
when others =>
next_state <= IDLE;
end case;
end process;
--------------------------------------
-- Combinatorial logic for state machine outputs
--------------------------------------
combi_out: process(curr_state, start, edge_detected_ctrlIn, counter, numWords_int)
begin
-- Reset signals to avoid latches
en_reset <= FALSE;
en_bcdToInt <= FALSE;
en_updateCounter <= FALSE;
en_peakDetection <= FALSE;
en_byteOutput <= FALSE;
dataReady <= '0';
seqDone <= '0';
case curr_state is
when IDLE =>
en_reset <= TRUE; -- reset signals, fixing bug for board reset button
if start = '1' then
en_bcdToInt <= TRUE; -- BCDtoINT process
end if;
when PROCESS_DATA =>
if edge_detected_ctrlIn = '1' then
en_updateCounter <= TRUE; -- UpdateCounter Process
en_peakDetection <= TRUE; -- PeakDetection process
end if;
when WAIT_CMDP =>
en_byteOutput <= TRUE; -- ByteOutput process
when CHECK_COMPLETE =>
dataReady <= '1';
if counter >= numWords_int then
seqDone <= '1';
end if;
when others =>
null;
end case;
end process;
--------------------------------------------------------- TWO PHASE PROTOCOL ---------------------------------------------------------
---------------------------
-- detect ctrlIn edge toggle by using XOR gate to spot a binary difference between current and previous ctrlIn
---------------------------
CtrlInEdgeDetect: process(clk, ctrlIn, prev_ctrlIn)
begin
if rising_edge(clk) then
prev_ctrlIn <= ctrlIn;
end if;
edge_detected_ctrlIn <= ctrlIn XOR prev_ctrlIn;
end process;
---------------------------
-- ctrlOut is toggled when the program starts and when we have processed a byte and the next byte is expected
---------------------------
CtrlOutToggle: process(clk, reset, ctrlOut_state)
begin
if rising_edge(clk) then
if reset = '1' then
ctrlOut_state <= '0';
elsif (curr_state = IDLE and start = '1') or (curr_state = CHECK_COMPLETE and counter < numWords_int) then
ctrlOut_state <= not ctrlOut_state;
end if;
end if;
ctrlOut <= ctrlOut_state;
end process;
--------------------------------------------------------- BASIC PROCESSES ---------------------------------------------------------
--------------------------------------
-- Update counter to keep track of current index of byte being processed
--------------------------------------
UpdateCounter: process(clk)
begin
if rising_edge(clk) then
if en_reset then
counter <= 0;
elsif en_updateCounter then
counter <= counter + 1;
end if;
end if;
end process;
----------------------------
-- converts numWords_bcd input signal from BCD to integer for comparison against counter
----------------------------
BCDtoINT: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
numWords_int <= 0;
elsif en_bcdToInt then
numWords_int <= to_integer(unsigned(numWords_bcd(2))) * 100 +
to_integer(unsigned(numWords_bcd(1))) * 10 +
to_integer(unsigned(numWords_bcd(0)));
end if;
end if;
end process;
----------------------------
-- keep sending the bytes we read to the command processor
----------------------------
ByteOutput: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
byte <= "00000000";
elsif en_byteOutput THEN
byte <= data;
end if;
end if;
end process;
--------------------------------------------------------- PEAK DETECTION ALGORITHM ---------------------------------------------------------
PeakDetection: process(clk)
begin
if rising_edge(clk) then
if reset = '1' or en_reset then
peak_value <= (others => '0');
update_next_values <= 0;
lastThreeBytes <= (others => (others => '0'));
maxIndex <= (others => (others => '0'));
dataResults <= (others => (others => '0'));
elsif en_peakDetection then
-- 1. Update dataResults with next three values if the peak was recently found.
-- update_next_values tracks how many values we still need to store after the peak
if update_next_values > 0 then
dataResults(update_next_values - 1) <= std_logic_vector(signed(data)); -- Update next dataResults value
update_next_values <= update_next_values - 1;
end if;
-- 2. Peak detection.
-- If it's the first byte or the current byte is greater than past peak value
if counter = 0 or signed(data) > peak_value then
peak_value <= signed(data); -- update peak value for future comparison
maxIndex(0) <= std_logic_vector(to_unsigned(counter mod 10, 4)); -- Update max index using counter
maxIndex(1) <= std_logic_vector(to_unsigned((counter / 10) mod 10, 4));
maxIndex(2) <= std_logic_vector(to_unsigned((counter / 100) mod 10, 4));
dataResults(6) <= std_logic_vector(lastThreeBytes(2));-- Update the three values before the peak
dataResults(5) <= std_logic_vector(lastThreeBytes(1));
dataResults(4) <= std_logic_vector(lastThreeBytes(0));
dataResults(3) <= std_logic_vector(signed(data)); -- Update the peak value
dataResults(2) <= (others => '0'); -- Reset the three values after the peak
dataResults(1) <= (others => '0');
dataResults(0) <= (others => '0');
update_next_values <= 3; -- indicating that we need to store the next three values
end if;
-- 3. Always keep track of the last three bytes, so we can update dataResults(6 downto 4) when peak found
lastThreeBytes(2) <= lastThreeBytes(1);
lastThreeBytes(1) <= lastThreeBytes(0);
lastThreeBytes(0) <= signed(data);
end if;
end if;
end process;
end Behavioral; library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.common_pack.all;
entity dataConsume is
port (
clk : in std_logic;
reset : in std_logic;
start : in std_logic;
numWords_bcd: in BCD_ARRAY_TYPE(2 downto 0);
ctrlIn : in std_logic;
ctrlOut : out std_logic;
data : in std_logic_vector(7 downto 0);
dataReady : out std_logic;
byte : out std_logic_vector(7 downto 0);
seqDone : out std_logic;
maxIndex : out BCD_ARRAY_TYPE(2 downto 0);
dataResults : out CHAR_ARRAY_TYPE(0 to RESULT_BYTE_NUM-1)
);
end dataConsume;
architecture Behavioral of dataConsume is
-- Additional or revised states, preserving your original ones.
type fsm_state is (
IDLE,
SETUP,
REQUEST_BYTE,
WAIT_CTRL,
LATCH_DATA,
DATA_READY_PULSE,
DONE
);
signal curState, nextState : fsm_state := IDLE;
-- Internal signals
signal nWords : integer range 0 to 999 := 0;
signal counter : integer range 0 to 999 := 0;
-- ctrlOut handshake
signal ctrlOut_reg : std_logic := '0';
-- ctrlIn rising/falling detection
signal ctrlIn_prev : std_logic := '0';
signal edgeDetect : std_logic := '0';
-- Peak detection
signal peak_value : signed(7 downto 0) := (others => '0');
signal peak_index : integer range 0 to 999 := 0;
-- Rolling buffer for last 3 samples
type rolling_array is array (0 to 2) of signed(7 downto 0);
signal prev_samples : rolling_array := (others => (others => '0'));
signal post_count : integer range 0 to 3 := 0;
-- BCD convert function
function bcd_to_int(bcd3: BCD_ARRAY_TYPE(2 downto 0)) return integer is
variable tmp : integer := 0;
begin
tmp := to_integer(unsigned(bcd3(2))) * 100 +
to_integer(unsigned(bcd3(1))) * 10 +
to_integer(unsigned(bcd3(0)));
return tmp;
end function;
begin
----------------------------------------------------------------------------
-- 1) Synchronous FSM: state register
----------------------------------------------------------------------------
process(clk, reset)
begin
if rising_edge(clk) then
if reset = '1' then
curState <= IDLE;
else
curState <= nextState;
end if;
end if;
end process;
----------------------------------------------------------------------------
-- 2) Synchronous detection of ctrlIn edges
----------------------------------------------------------------------------
process(clk, ctrlIn, ctrlIn_prev)
begin
if rising_edge(clk) then
ctrlIn_prev <= ctrlIn;
end if;
edgeDetect <= ctrlIn xor ctrlIn_prev;
end process;
process(clk, reset, ctrlOut_reg)
begin
if rising_edge(clk) then
if reset = '1' then
ctrlOut_reg <= '0';
elsif (curState = REQUEST_BYTE) then
ctrlOut_reg <= not ctrlOut_reg;
end if;
end if;
ctrlOut <= ctrlOut_reg;
end process;
----------------------------------------------------------------------------
-- 3) Combinational FSM: next-state logic
----------------------------------------------------------------------------
process(curState, start, counter, nWords, edgeDetect)
begin
case curState is
--------------------------------------------------------------------
when IDLE =>
if start = '1' then
nextState <= SETUP;
else
nextState <= IDLE;
end if;
--------------------------------------------------------------------
when SETUP =>
-- Once BCD->int is done in sequential path, we request first byte
nextState <= REQUEST_BYTE;
--------------------------------------------------------------------
when REQUEST_BYTE =>
-- We'll do the toggling of ctrlOut in the sequential process
nextState <= WAIT_CTRL; -- wait for ctrlIn to go high
--------------------------------------------------------------------
when WAIT_CTRL =>
-- We want a rising edge: edgeDetect='1' AND ctrlIn='1'
if edgeDetect = '1' then
nextState <= LATCH_DATA;
else
nextState <= WAIT_CTRL;
end if;
--------------------------------------------------------------------
when LATCH_DATA =>
-- do your data latch
if counter < nWords then
nextState <= REQUEST_BYTE; -- if more words avail go back
else
nextState <= DONE;
end if;
when others =>
nextState <= IDLE;
end case;
end process;
----------------------------------------------------------------------------
-- 4) Synchronous data-path updates
----------------------------------------------------------------------------
process(clk)
variable new_sample : signed(7 downto 0);
begin
if rising_edge(clk) then
dataReady <= '0';
seqDone <= '0';
if reset = '1' then
nWords <= 0;
counter <= 0;
ctrlOut_reg <= '0';
peak_value <= (others => '0');
peak_index <= 0;
prev_samples <= (others => (others => '0'));
post_count <= 0;
dataResults <= (others => (others => '0'));
maxIndex <= (others => (others => '0'));
else
case curState is
when IDLE =>
-- do nothing
when SETUP =>
-- convert BCD->int
nWords <= bcd_to_int(numWords_bcd);
counter <= 0;
peak_value <= (others => '0');
peak_index <= 0;
prev_samples <= (others => (others => '0'));
post_count <= 0;
dataResults <= (others => (others => '0'));
when LATCH_DATA =>
-- read the data
new_sample := signed(data);
if post_count > 0 then
-- store next few samples
dataResults(post_count-1) <= data;
post_count <= post_count - 1;
end if;
-- Peak detection
if (counter=0) or (new_sample>peak_value) then
peak_value <= new_sample;
peak_index <= counter;
maxIndex(0) <= std_logic_vector(to_unsigned(peak_index mod 10, 4));
maxIndex(1) <= std_logic_vector(to_unsigned((peak_index / 10) mod 10, 4));
maxIndex(2) <= std_logic_vector(to_unsigned((peak_index / 100) mod 10, 4));
-- store the 3 samples before the new peak
dataResults(6) <= std_logic_vector(prev_samples(2));
dataResults(5) <= std_logic_vector(prev_samples(1));
dataResults(4) <= std_logic_vector(prev_samples(0));
dataResults(3) <= data; -- new peak
dataResults(2) <= (others => '0');
dataResults(1) <= (others => '0');
dataResults(0) <= (others => '0');
post_count <= 3;
counter <= counter + 1;
byte <= std_logic_vector(peak_value);
end if;
prev_samples(2) <= prev_samples(1);
prev_samples(1) <= prev_samples(0);
prev_samples(0) <= new_sample;
when DONE =>
dataReady <= '1';
if (counter >= nWords) then
seqDone <= '1';
end if;
when others =>
null;
end case;
end if;
end if;
end process;
end architecture Behavioral;Editor is loading...
Leave a Comment