Untitled

 avatar
unknown
plain_text
a month ago
25 kB
4
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