From 9bf8c21957990aee840f861de2d9ae3b0cea8013 Mon Sep 17 00:00:00 2001 From: Davide Date: Thu, 17 Apr 2025 01:24:18 +0200 Subject: [PATCH] Refactor bram_writer and test script: improve code readability, update package installation method, and enhance image processing logic --- LAB2/src/bram_writer.vhd | 273 ++++++++++++++++++++++----------------- LAB2/test/test.py | 80 ++++++------ 2 files changed, 198 insertions(+), 155 deletions(-) diff --git a/LAB2/src/bram_writer.vhd b/LAB2/src/bram_writer.vhd index bfc2a83..ad353f0 100644 --- a/LAB2/src/bram_writer.vhd +++ b/LAB2/src/bram_writer.vhd @@ -1,150 +1,191 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; -entity bram_writer is - generic( - ADDR_WIDTH: POSITIVE :=16 +ENTITY bram_writer IS + GENERIC ( + ADDR_WIDTH : POSITIVE := 16; + IMG_SIZE : POSITIVE := 256 -- Dimensione immagine NxN ); - port ( - clk : in std_logic; - aresetn : in std_logic; + PORT ( + clk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; - s_axis_tdata : in std_logic_vector(7 downto 0); - s_axis_tvalid : in std_logic; - s_axis_tready : out std_logic; - s_axis_tlast : in std_logic; + -- Interfaccia AXI Stream per ricezione dati + s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + s_axis_tvalid : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + s_axis_tlast : IN STD_LOGIC; - conv_addr: in std_logic_vector(ADDR_WIDTH-1 downto 0); - conv_data: out std_logic_vector(6 downto 0); + -- Interfaccia di lettura BRAM per il modulo di convoluzione + conv_addr : IN STD_LOGIC_VECTOR(ADDR_WIDTH - 1 DOWNTO 0); + conv_data : OUT STD_LOGIC_VECTOR(6 DOWNTO 0); -- solo 7 bit usati - start_conv: out std_logic; - done_conv: in std_logic; - - write_ok : out std_logic; - overflow : out std_logic; - underflow: out std_logic + -- Controllo avvio/fine convoluzione + start_conv : OUT STD_LOGIC; + done_conv : IN STD_LOGIC; + -- LED di stato (come da immagine) + write_ok : OUT STD_LOGIC; + overflow : OUT STD_LOGIC; + underflow : OUT STD_LOGIC ); -end entity bram_writer; +END ENTITY bram_writer; -architecture rtl of bram_writer is +ARCHITECTURE rtl OF bram_writer IS - component bram_controller is - generic ( - ADDR_WIDTH: POSITIVE :=16 + -- Componente BRAM (controller) + COMPONENT bram_controller IS + GENERIC ( + ADDR_WIDTH : POSITIVE := 16 ); - port ( - clk : in std_logic; - aresetn : in std_logic; - - addr: in std_logic_vector(ADDR_WIDTH-1 downto 0); - dout: out std_logic_vector(7 downto 0); - din: in std_logic_vector(7 downto 0); - we: in std_logic + PORT ( + clk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + + addr : IN STD_LOGIC_VECTOR(ADDR_WIDTH - 1 DOWNTO 0); + dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + din : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + we : IN STD_LOGIC ); - end component; + END COMPONENT; + + CONSTANT total_px_expected : unsigned(ADDR_WIDTH - 1 DOWNTO 0) := to_unsigned(IMG_SIZE ** 2 - 1, ADDR_WIDTH); -- IMG_SIZE * IMG_SIZE + + TYPE state_type IS (IDLE, RECEIVING, CHECK_START_CONV, CONVOLUTION); + SIGNAL state : state_type := IDLE; -- Registri di stato e segnale interno - signal addr_cnt : unsigned(ADDR_WIDTH-1 downto 0) := (others => '0'); -- Contatore indirizzo BRAM - signal wr_enable : std_logic := '0'; -- Segnale di scrittura BRAM - signal din_reg : std_logic_vector(7 downto 0) := (others => '0'); -- Dato da scrivere in BRAM - signal fsm_state : integer range 0 to 3 := 0; -- Stato FSM - signal pixel_count: unsigned(ADDR_WIDTH-1 downto 0) := (others => '0'); -- Pixel ricevuti - signal total_px_expected : unsigned(ADDR_WIDTH-1 downto 0); -- IMG_SIZE * IMG_SIZE + signal addr_write : UNSIGNED(ADDR_WIDTH DOWNTO 0) := (OTHERS => '0'); -- Indirizzo BRAM + SIGNAL addr_bram : STD_LOGIC_VECTOR(ADDR_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Indirizzo BRAM - signal dout_bram : std_logic_vector(7 downto 0); -- Dato letto dalla BRAM + SIGNAL wr_enable : STD_LOGIC := '0'; -- Segnale di scrittura BRAM + SIGNAL din_reg : STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '0'); -- Dato da scrivere in BRAM + SIGNAL flag_of : STD_LOGIC := '0'; -- Flag overflow (se addr_count > total_px_expected) -begin + SIGNAL dout_bram : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Dato letto dalla BRAM - -- Calcolo totale pixel attesi = N x N - total_px_expected <= to_unsigned(IMG_SIZE * IMG_SIZE, ADDR_WIDTH); + SIGNAL s_axis_tready_int : STD_LOGIC; + +BEGIN -- Instanziazione BRAM (scrive e legge) BRAM_CTRL : bram_controller - generic map ( - ADDR_WIDTH => ADDR_WIDTH - ) - port map ( - clk => clk, - aresetn => aresetn, - addr => conv_addr, - dout => dout_bram, - din => din_reg, - we => wr_enable - ); + GENERIC MAP( + ADDR_WIDTH => ADDR_WIDTH + ) + PORT MAP( + clk => clk, + aresetn => aresetn, + addr => addr_bram, + dout => dout_bram, + din => din_reg, + we => wr_enable + ); - -- Usiamo solo i primi 7 bit del dato letto per conv_data - conv_data <= dout_bram(6 downto 0); + -- AXIS + s_axis_tready <= s_axis_tready_int; + + -- Segnale di lettura BRAM per il modulo di convoluzione + conv_data <= dout_bram(6 DOWNTO 0); -- FSM principale - process(clk, aresetn) - begin - if aresetn = '0' then - -- Reset asincrono - fsm_state <= 0; - addr_cnt <= (others => '0'); - pixel_count <= (others => '0'); - wr_enable <= '0'; - s_axis_tready <= '0'; - write_ok <= '0'; - overflow <= '0'; - underflow <= '0'; - start_conv <= '0'; + PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + IF aresetn = '0' THEN + -- Reset sincrono + state <= IDLE; + addr_bram <= (OTHERS => '0'); + addr_write <= (OTHERS => '0'); + wr_enable <= '0'; + write_ok <= '0'; + overflow <= '0'; + underflow <= '0'; + start_conv <= '0'; + flag_of <= '0'; - elsif rising_edge(clk) then - -- Valori di default ogni ciclo - wr_enable <= '0'; - start_conv <= '0'; - write_ok <= '0'; - overflow <= '0'; - underflow <= '0'; + s_axis_tready_int <= '0'; - case fsm_state is + ELSE + -- Valori di default ogni ciclo + wr_enable <= '0'; + start_conv <= '0'; - when 0 => -- Stato IDLE/RICEZIONE (legge dati da AXIS) - s_axis_tready <= '1'; -- pronto a ricevere + write_ok <= '0'; + overflow <= '0'; + underflow <= '0'; - if s_axis_tvalid = '1' then - -- Registra dato ricevuto e scrive in BRAM - din_reg <= s_axis_tdata; - wr_enable <= '1'; - addr_cnt <= addr_cnt + 1; - pixel_count <= pixel_count + 1; + addr_bram <= conv_addr; -- Passa indirizzo al modulo di convoluzione - -- Se è l'ultimo pixel del pacchetto - if s_axis_tlast = '1' then - fsm_state <= 1; - end if; - end if; + CASE state IS - when 1 => -- Controllo overflow/underflow - s_axis_tready <= '0'; + WHEN IDLE => + addr_write <= (OTHERS => '0'); + flag_of <= '0'; -- Reset flag overflow + s_axis_tready_int <= '1'; -- Pronto a ricevere dati - if pixel_count = total_px_expected then - write_ok <= '1'; -- LED OK - elsif pixel_count < total_px_expected then - underflow <= '1'; -- LED underflow - else - overflow <= '1'; -- LED overflow - end if; + IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN + -- Registra dato ricevuto e scrive in BRAM + din_reg <= s_axis_tdata; + addr_bram <= STD_LOGIC_VECTOR(addr_write(ADDR_WIDTH - 1 DOWNTO 0)); + wr_enable <= '1'; - fsm_state <= 2; -- Vai a start convoluzione + s_axis_tready_int <= '1'; -- Pronto a ricevere nuovi dati - when 2 => -- Avvia convoluzione - start_conv <= '1'; -- Segnale per far partire modulo Conv + state <= RECEIVING; + END IF; - if done_conv = '1' then - -- Reset e torna a ricevere nuovi dati - fsm_state <= 0; - addr_cnt <= (others => '0'); - pixel_count <= (others => '0'); - end if; + WHEN RECEIVING => -- Stato RICEZIONE (legge dati da AXIS) + IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN + -- Registra dato ricevuto e scrive in BRAM + din_reg <= s_axis_tdata; + addr_bram <= STD_LOGIC_VECTOR(addr_write(ADDR_WIDTH - 1 DOWNTO 0)); + wr_enable <= '1'; + addr_write <= addr_write + 1; - when others => - fsm_state <= 0; - end case; - end if; - end process; + s_axis_tready_int <= '1'; -- Pronto a ricevere nuovi dati -end architecture; + -- Se è l'ultimo pixel del pacchetto + IF s_axis_tlast = '1' THEN + state <= CHECK_START_CONV; + END IF; + END IF; + + WHEN CHECK_START_CONV => -- Controllo overflow/underflow + s_axis_tready_int <= '0'; + + IF flag_of = '1' THEN + overflow <= '1'; -- LED overflow + + state <= IDLE; -- Torna a stato IDLE + ELSIF addr_write < total_px_expected THEN + underflow <= '1'; -- LED underflow + + state <= IDLE; -- Torna a stato IDLE + ELSIF addr_write = total_px_expected THEN + write_ok <= '1'; -- LED OK + + start_conv <= '1'; -- Segnale per far partire modulo Conv + state <= CONVOLUTION; -- Vai a start convoluzione + END IF; + + WHEN CONVOLUTION => -- Avvia convoluzione + s_axis_tready_int <= '0'; + + IF done_conv = '1' THEN + state <= IDLE; + s_axis_tready_int <= '1'; + END IF; + END CASE; + + -- il controllo viene eseguito qui nel caso in cui addr_write vada in overflow e risulti quindi minore di total_px_expected + IF addr_write > total_px_expected AND flag_of = '0' THEN + flag_of <= '1'; + END IF; + + END IF; + END IF; + END PROCESS; + +END ARCHITECTURE; \ No newline at end of file diff --git a/LAB2/test/test.py b/LAB2/test/test.py index 7db913f..a02dc9b 100644 --- a/LAB2/test/test.py +++ b/LAB2/test/test.py @@ -1,87 +1,89 @@ +import sys +import subprocess + def install_and_import(package, package_name=None): if package_name is None: package_name = package - import importlib try: importlib.import_module(package) except ImportError: - import pip - pip.main(['install', package_name]) + subprocess.check_call([sys.executable, "-m", "pip", "install", package_name]) finally: globals()[package] = importlib.import_module(package) -install_and_import("Serial", "pyserial") +install_and_import("serial", "pyserial") install_and_import("PIL", "pillow") install_and_import("tqdm") install_and_import("numpy") install_and_import("scipy") - from serial import Serial import serial.tools.list_ports from tqdm import tqdm - from PIL import Image - from scipy.signal import convolve2d import numpy as np -IMAGE_NAME2="test2.png" -IMAGE_NAME1="test1.png" +IMAGE_NAME2 = "test2.png" +IMAGE_NAME1 = "test1.png" -BASYS3_PID=0x6010 -BASYS3_VID=0x0403 +BASYS3_PID = 0x6010 +BASYS3_VID = 0x0403 -IMG_HEIGHT=256 -IMG_WIDTH=256 +IMG_HEIGHT = 256 +IMG_WIDTH = 256 -dev="" +dev = "" for port in serial.tools.list_ports.comports(): - if(port.vid==BASYS3_VID and port.pid==BASYS3_PID): - dev=port.device + if (port.vid == BASYS3_VID and port.pid == BASYS3_PID): + dev = port.device if not dev: raise RuntimeError("Basys 3 Not Found!") -test_n=int(input("Insert test number (1 or 2): ").strip()) +test_n = int(input("Insert test number (1 or 2): ").strip()) -if(test_n not in [1,2]): - raise RuntimeError("Test numer must be be 1 or 2") +if test_n not in [1, 2]: + raise RuntimeError("Test number must be 1 or 2") -dev=Serial(dev,115200) +dev = Serial(dev, 115200) -img=Image.open(IMAGE_NAME1 if test_n==1 else IMAGE_NAME2) -mat=np.asarray(img,dtype=np.uint8) +img = Image.open(IMAGE_NAME1 if test_n == 1 else IMAGE_NAME2) +if img.mode != "RGB": + img = img.convert("RGB") +mat = np.asarray(img, dtype=np.uint8) -mat=mat[:,:,:3] -if(mat.max()>127): - mat=mat//2 +mat = mat[:, :, :3] +if mat.max() > 127: + mat = mat // 2 -buff=mat.tobytes() +buff = mat.tobytes() -mat=np.sum(mat,axis=2)//3 +mat_gray = np.sum(mat, axis=2) // 3 -sim_img=convolve2d(mat,[[-1,-1,-1],[-1,8,-1],[-1,-1,-1]], mode="same") +sim_img = convolve2d(mat_gray, [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], mode="same") -sim_img[sim_img<0]=0 -sim_img[sim_img>127]=127 +sim_img[sim_img < 0] = 0 +sim_img[sim_img > 127] = 127 +sim_img = sim_img.astype(np.uint8) dev.write(b'\xff') for i in tqdm(range(IMG_HEIGHT)): - dev.write(buff[(i)*IMG_WIDTH*3:(i+1)*IMG_WIDTH*3]) + dev.write(buff[i * IMG_WIDTH * 3:(i + 1) * IMG_WIDTH * 3]) dev.write(b'\xf1') dev.flush() -res=dev.read(IMG_HEIGHT*IMG_WIDTH+2) +res = dev.read(IMG_HEIGHT * IMG_WIDTH + 2) -res_img=np.frombuffer(res[1:-1],dtype=np.uint8) +res_img = np.frombuffer(res[1:-1], dtype=np.uint8) +res_img = res_img.reshape((IMG_HEIGHT, IMG_WIDTH)) -res_img=res_img.reshape((IMG_HEIGHT,IMG_WIDTH)) - - -assert np.all(res_img==sim_img), "Image Mismatch!" - -im=Image.fromarray(np.uint8(res_img)) +im = Image.fromarray(res_img) im.show() + +if np.all(res_img != sim_img): + print("Image Mismatch!") + +dev.close()