Untitled
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