From c3967c3124f31e086e5012830c1f48feb9fb5fad Mon Sep 17 00:00:00 2001 From: Cd16d Date: Thu, 15 May 2025 16:46:09 +0200 Subject: [PATCH] Update VHDL and Python files for improved functionality and performance - Updated the date in the diligent_jstk_wrapper.vhd file. - Modified the testbench (tb_digilent_jstk2.vhd) to ensure proper data transmission and added a delay to simulate real response time. - Adjusted the digilent_jstk2.vhd file to refine the state machine logic for sending and receiving data, including a new IDLE state and improved handling of the SPI communication. - Enhanced uart_viewer.py to automatically detect the Basys3 board's serial port, improving user experience and reducing configuration errors. - Updated the Vivado project file (diligent_jstk.xpr) to reflect changes in simulation and synthesis settings, ensuring compatibility with the latest design updates. --- LAB3/design/diligent_jstk/diligent_jstk.bd | 69 ++++- .../hdl/diligent_jstk_wrapper.vhd | 2 +- LAB3/sim/tb_digilent_jstk2.vhd | 22 +- LAB3/src/digilent_jstk2.vhd | 293 +++++++++--------- LAB3/test/uart_viewer.py | 25 +- LAB3/vivado/diligent_jstk/diligent_jstk.xpr | 276 ++++++++++++++++- 6 files changed, 495 insertions(+), 192 deletions(-) diff --git a/LAB3/design/diligent_jstk/diligent_jstk.bd b/LAB3/design/diligent_jstk/diligent_jstk.bd index 45a1dc3..6bd4c2c 100644 --- a/LAB3/design/diligent_jstk/diligent_jstk.bd +++ b/LAB3/design/diligent_jstk/diligent_jstk.bd @@ -5,7 +5,7 @@ "device": "xc7a35tcpg236-1", "name": "diligent_jstk", "rev_ctrl_bd_flag": "RevCtrlBdOff", - "synth_flow_mode": "None", + "synth_flow_mode": "Hierarchical", "tool_version": "2020.2", "validated": "true" }, @@ -15,7 +15,8 @@ "AXI4Stream_UART_0": "", "jstk_uart_bridge_0": "", "axi4stream_spi_master_0": "", - "digilent_jstk2_0": "" + "digilent_jstk2_0": "", + "system_ila_0": "" }, "interface_ports": { "usb_uart": { @@ -551,25 +552,63 @@ "right": "0" } } + }, + "system_ila_0": { + "vlnv": "xilinx.com:ip:system_ila:1.1", + "xci_name": "diligent_jstk_system_ila_0_0", + "xci_path": "ip\\diligent_jstk_system_ila_0_0\\diligent_jstk_system_ila_0_0.xci", + "inst_hier_path": "system_ila_0", + "parameters": { + "C_NUM_MONITOR_SLOTS": { + "value": "2" + }, + "C_SLOT": { + "value": "1" + }, + "C_SLOT_0_INTF_TYPE": { + "value": "xilinx.com:interface:axis_rtl:1.0" + }, + "C_SLOT_1_INTF_TYPE": { + "value": "xilinx.com:interface:axis_rtl:1.0" + } + }, + "interface_ports": { + "SLOT_0_AXIS": { + "mode": "Monitor", + "vlnv": "xilinx.com:interface:axis_rtl:1.0" + }, + "SLOT_1_AXIS": { + "mode": "Monitor", + "vlnv": "xilinx.com:interface:axis_rtl:1.0" + } + } } }, "interface_nets": { - "axi4stream_spi_master_0_M_AXIS": { - "interface_ports": [ - "axi4stream_spi_master_0/M_AXIS", - "digilent_jstk2_0/s_axis" - ] - }, "jstk_uart_bridge_0_m_axis": { "interface_ports": [ "AXI4Stream_UART_0/S00_AXIS_TX", "jstk_uart_bridge_0/m_axis" ] }, + "AXI4Stream_UART_0_M00_AXIS_RX": { + "interface_ports": [ + "AXI4Stream_UART_0/M00_AXIS_RX", + "jstk_uart_bridge_0/s_axis" + ] + }, "digilent_jstk2_0_m_axis": { "interface_ports": [ "digilent_jstk2_0/m_axis", - "axi4stream_spi_master_0/S_AXIS" + "axi4stream_spi_master_0/S_AXIS", + "system_ila_0/SLOT_0_AXIS" + ] + }, + "axi4stream_spi_master_0_M_AXIS": { + "interface_ports": [ + "axi4stream_spi_master_0/M_AXIS", + "digilent_jstk2_0/s_axis", + "system_ila_0/SLOT_1_AXIS" ] }, "AXI4Stream_UART_0_UART": { @@ -583,12 +622,6 @@ "SPI_M_0", "axi4stream_spi_master_0/SPI_M" ] - }, - "AXI4Stream_UART_0_M00_AXIS_RX": { - "interface_ports": [ - "AXI4Stream_UART_0/M00_AXIS_RX", - "jstk_uart_bridge_0/s_axis" - ] } }, "nets": { @@ -620,7 +653,8 @@ "AXI4Stream_UART_0/m00_axis_rx_aclk", "jstk_uart_bridge_0/aclk", "AXI4Stream_UART_0/s00_axis_tx_aclk", - "digilent_jstk2_0/aclk" + "digilent_jstk2_0/aclk", + "system_ila_0/clk" ] }, "digilent_jstk2_0_btn_trigger": { @@ -672,7 +706,8 @@ "jstk_uart_bridge_0/aresetn", "AXI4Stream_UART_0/s00_axis_tx_aresetn", "axi4stream_spi_master_0/aresetn", - "digilent_jstk2_0/aresetn" + "digilent_jstk2_0/aresetn", + "system_ila_0/resetn" ] }, "proc_sys_reset_0_peripheral_reset": { diff --git a/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd b/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd index 7fff9d5..61c4d43 100644 --- a/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd +++ b/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd @@ -1,7 +1,7 @@ --Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. ---------------------------------------------------------------------------------- --Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 ---Date : Wed May 14 13:59:17 2025 +--Date : Thu May 15 16:34:14 2025 --Host : Davide-Samsung running 64-bit major release (build 9200) --Command : generate_target diligent_jstk_wrapper.bd --Design : diligent_jstk_wrapper diff --git a/LAB3/sim/tb_digilent_jstk2.vhd b/LAB3/sim/tb_digilent_jstk2.vhd index f5ae1fa..181f2ae 100644 --- a/LAB3/sim/tb_digilent_jstk2.vhd +++ b/LAB3/sim/tb_digilent_jstk2.vhd @@ -130,23 +130,29 @@ BEGIN -- Main loop: wait for CMDSETLEDRGB, then send mem bytes for each byte received WHILE TRUE LOOP WAIT UNTIL rising_edge(aclk); + + -- Default: s_axis_tvalid low unless sending + s_axis_tvalid <= '0'; + IF m_axis_tvalid = '1' THEN IF m_axis_tdata = CMDSETLEDRGB THEN send_data := TRUE; mem_idx := 0; END IF; - IF send_data THEN - IF mem_idx <= 4 THEN - s_axis_tdata <= spi_mem(mem_idx); - s_axis_tvalid <= '1'; - mem_idx := mem_idx + 1; - ELSE + IF send_data AND mem_idx <= 4 THEN + -- Present data for one cycle when master is ready + s_axis_tdata <= spi_mem(mem_idx); + s_axis_tvalid <= '1'; + WAIT UNTIL rising_edge(aclk); -- handshake + s_axis_tvalid <= '0'; + mem_idx := mem_idx + 1; + -- Simula il tempo di risposta reale del JSTK2 (1,6 ms per byte) + WAIT FOR 1600 us; + IF mem_idx > 4 THEN send_data := FALSE; END IF; END IF; - ELSE - s_axis_tvalid <= '0'; END IF; END LOOP; END PROCESS; diff --git a/LAB3/src/digilent_jstk2.vhd b/LAB3/src/digilent_jstk2.vhd index 356632e..0fc19a5 100644 --- a/LAB3/src/digilent_jstk2.vhd +++ b/LAB3/src/digilent_jstk2.vhd @@ -2,192 +2,177 @@ LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY digilent_jstk2 IS - GENERIC ( - DELAY_US : INTEGER := 25; -- Delay (in us) between two packets - CLKFREQ : INTEGER := 100_000_000; -- Frequency of the aclk signal (in Hz) - SPI_SCLKFREQ : INTEGER := 66_666 -- Frequency of the SPI SCLK clock signal (in Hz) - ); - PORT ( - aclk : IN STD_LOGIC; - aresetn : IN STD_LOGIC; + GENERIC ( + DELAY_US : INTEGER := 25; -- Delay (in us) between two packets + CLKFREQ : INTEGER := 100_000_000; -- Frequency of the aclk signal (in Hz) + SPI_SCLKFREQ : INTEGER := 5_000 -- Frequency of the SPI SCLK clock signal (in Hz) + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; - -- Data going TO the SPI IP-Core (and so, to the JSTK2 module) - m_axis_tvalid : OUT STD_LOGIC; - m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); - m_axis_tready : IN STD_LOGIC; + -- Data going TO the SPI IP-Core (and so, to the JSTK2 module) + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + m_axis_tready : IN STD_LOGIC; - -- Data coming FROM the SPI IP-Core (and so, from the JSTK2 module) - -- There is no tready signal, so you must be always ready to accept and use the incoming data, or it will be lost! - s_axis_tvalid : IN STD_LOGIC; - s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + -- Data coming FROM the SPI IP-Core (and so, from the JSTK2 module) + -- There is no tready signal, so you must be always ready to accept and use the incoming data, or it will be lost! + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); - -- Joystick and button values read from the module - jstk_x : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); - jstk_y : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); - btn_jstk : OUT STD_LOGIC; - btn_trigger : OUT STD_LOGIC; + -- Joystick and button values read from the module + jstk_x : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); + jstk_y : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); + btn_jstk : OUT STD_LOGIC; + btn_trigger : OUT STD_LOGIC; - -- LED color to send to the module - led_r : IN STD_LOGIC_VECTOR(7 DOWNTO 0); - led_g : IN STD_LOGIC_VECTOR(7 DOWNTO 0); - led_b : IN STD_LOGIC_VECTOR(7 DOWNTO 0) - ); + -- LED color to send to the module + led_r : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + led_g : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + led_b : IN STD_LOGIC_VECTOR(7 DOWNTO 0) + ); END digilent_jstk2; ARCHITECTURE Behavioral OF digilent_jstk2 IS - -- Code for the SetLEDRGB command, see the JSTK2 datasheet. - CONSTANT CMDSETLEDRGB : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"84"; + -- Code for the SetLEDRGB command, see the JSTK2 datasheet. + CONSTANT CMDSETLEDRGB : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"84"; - -- Do not forget that you MUST wait a bit between two packets. See the JSTK2 datasheet (and the SPI IP-Core README). - ------------------------------------------------------------ + -- Do not forget that you MUST wait a bit between two packets. See the JSTK2 datasheet (and the SPI IP-Core README). + ------------------------------------------------------------ - CONSTANT DELAY_CLK_CYCLES : INTEGER := DELAY_US * (CLKFREQ / 1_000_000) - 1; + CONSTANT DELAY_CLK_CYCLES : INTEGER := DELAY_US * (CLKFREQ / 1_000_000) - 1; - -- State machine states - TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY); - TYPE rx_state_type IS (JSTK_X_LOW, JSTK_X_HIGH, JSTK_Y_LOW, JSTK_Y_HIGH, BUTTONS); + -- State machine states + TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY); + TYPE rx_state_type IS (IDLE, JSTK_X_LOW, JSTK_X_HIGH, JSTK_Y_LOW, JSTK_Y_HIGH, BUTTONS); - SIGNAL tx_state : tx_state_type; - SIGNAL rx_state : rx_state_type; + SIGNAL tx_state : tx_state_type := DELAY; + SIGNAL rx_state : rx_state_type := JSTK_X_LOW; - SIGNAL rx_cache : STD_LOGIC_VECTOR(7 DOWNTO 0); - SIGNAL tx_delay_counter : INTEGER := 0; + SIGNAL tx_delay_counter : INTEGER := 0; - SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; + SIGNAL rx_cache : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL rx_done : STD_LOGIC := '1'; -- Pronto a trasmettere al primo ciclo BEGIN + -- The SPI IP-Core is a slave, so we must set the m_axis_tvalid signal to '1' when we want to send data to it. + WITH tx_state SELECT m_axis_tvalid <= + '0' WHEN DELAY, + '1' WHEN OTHERS; - m_axis_tvalid <= m_axis_tvalid_int; + -- TX FSM: invia un nuovo comando solo dopo che la risposta precedente è stata ricevuta (rx_done = '1') + TX : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN + tx_state <= DELAY; + m_axis_tdata <= (OTHERS => '0'); + tx_delay_counter <= 0; - -- Send the data to the SPI IP-Core - TX : PROCESS (aclk) - BEGIN - IF rising_edge(aclk) THEN - IF aresetn = '0' THEN - -- Reset the state machine - tx_state <= DELAY; + ELSE - m_axis_tvalid_int <= '0'; - m_axis_tdata <= (OTHERS => '0'); + CASE tx_state IS + WHEN DELAY => + m_axis_tdata <= (OTHERS => '0'); + IF tx_delay_counter >= DELAY_CLK_CYCLES THEN + IF rx_done = '1' THEN + tx_delay_counter <= 0; + tx_state <= SEND_CMD; + END IF; + ELSE + tx_delay_counter <= tx_delay_counter + 1; + END IF; - tx_delay_counter <= 0; + WHEN SEND_CMD => + m_axis_tdata <= CMDSETLEDRGB; + IF m_axis_tready = '1' THEN + tx_state <= SEND_RED; + END IF; - ELSE - -- Clear valid flag when master interface is ready - IF m_axis_tready = '1' THEN - m_axis_tvalid_int <= '0'; - END IF; + WHEN SEND_RED => + m_axis_tdata <= led_r; + IF m_axis_tready = '1' THEN + tx_state <= SEND_GREEN; + END IF; - -- State machine for sending data to the SPI IP-Core - CASE tx_state IS + WHEN SEND_GREEN => + m_axis_tdata <= led_g; + IF m_axis_tready = '1' THEN + tx_state <= SEND_BLUE; + END IF; - WHEN DELAY => - m_axis_tvalid_int <= '0'; - m_axis_tdata <= (OTHERS => '0'); + WHEN SEND_BLUE => + m_axis_tdata <= led_b; + IF m_axis_tready = '1' THEN + tx_state <= SEND_DUMMY; + END IF; - IF tx_delay_counter >= DELAY_CLK_CYCLES THEN - tx_delay_counter <= 0; - tx_state <= SEND_CMD; - ELSE - tx_delay_counter <= tx_delay_counter + 1; - END IF; + WHEN SEND_DUMMY => + m_axis_tdata <= (OTHERS => '0'); + IF m_axis_tready = '1' THEN + tx_state <= DELAY; + END IF; + END CASE; + END IF; + END IF; + END PROCESS TX; - WHEN SEND_CMD => - IF (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN - m_axis_tdata <= CMDSETLEDRGB; - m_axis_tvalid_int <= '1'; - tx_state <= SEND_RED; - END IF; + -- RX FSM: riceve 5 byte, aggiorna le uscite e segnala a TX FSM quando la risposta è completa + RX : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN - WHEN SEND_RED => - IF (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN - m_axis_tdata <= led_r; - m_axis_tvalid_int <= '1'; - tx_state <= SEND_GREEN; - END IF; + IF aresetn = '0' THEN - WHEN SEND_GREEN => - IF (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN - m_axis_tdata <= led_g; - m_axis_tvalid_int <= '1'; - tx_state <= SEND_BLUE; - END IF; + rx_state <= IDLE; + rx_cache <= (OTHERS => '0'); + rx_done <= '1'; - WHEN SEND_BLUE => - IF (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN - m_axis_tdata <= led_b; - m_axis_tvalid_int <= '1'; - tx_state <= SEND_DUMMY; - END IF; + ELSE + + CASE rx_state IS + WHEN IDLE => + IF tx_state = SEND_CMD THEN + rx_state <= JSTK_X_LOW; + rx_done <= '0'; -- In attesa di ricevere la risposta + END IF; - WHEN SEND_DUMMY => - IF (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN - m_axis_tdata <= (OTHERS => '0'); - m_axis_tvalid_int <= '1'; - tx_state <= DELAY; - END IF; + WHEN JSTK_X_LOW => + IF s_axis_tvalid = '1' THEN + rx_cache <= s_axis_tdata; + rx_state <= JSTK_X_HIGH; + END IF; - END CASE; + WHEN JSTK_X_HIGH => + IF s_axis_tvalid = '1' THEN + jstk_x <= s_axis_tdata(1 DOWNTO 0) & rx_cache; + rx_state <= JSTK_Y_LOW; + END IF; - END IF; - END IF; + WHEN JSTK_Y_LOW => + IF s_axis_tvalid = '1' THEN + rx_cache <= s_axis_tdata; + rx_state <= JSTK_Y_HIGH; + END IF; - END PROCESS TX; + WHEN JSTK_Y_HIGH => + IF s_axis_tvalid = '1' THEN + jstk_y <= s_axis_tdata(1 DOWNTO 0) & rx_cache; + rx_state <= BUTTONS; + END IF; - -- Receive the data from the SPI IP-Core - RX : PROCESS (aclk) - BEGIN - IF rising_edge(aclk) THEN - IF aresetn = '0' THEN - -- Reset the state machine - rx_state <= JSTK_X_LOW; - - -- jstk_x <= (others => '0'); - -- jstk_y <= (others => '0'); - btn_jstk <= '0'; - btn_trigger <= '0'; - - rx_cache <= (OTHERS => '0'); - ELSE - -- State machine for receiving data from the SPI IP-Core - CASE rx_state IS - - WHEN JSTK_X_LOW => - IF s_axis_tvalid = '1' THEN - rx_cache(7 DOWNTO 0) <= s_axis_tdata; - rx_state <= JSTK_X_HIGH; - END IF; - - WHEN JSTK_X_HIGH => - IF s_axis_tvalid = '1' THEN - jstk_x(9 DOWNTO 0) <= s_axis_tdata(1 DOWNTO 0) & rx_cache(7 DOWNTO 0); - rx_state <= JSTK_Y_LOW; - END IF; - - WHEN JSTK_Y_LOW => - IF s_axis_tvalid = '1' THEN - rx_cache(7 DOWNTO 0) <= s_axis_tdata; - rx_state <= JSTK_Y_HIGH; - END IF; - - WHEN JSTK_Y_HIGH => - IF s_axis_tvalid = '1' THEN - jstk_y(9 DOWNTO 0) <= s_axis_tdata(1 DOWNTO 0) & rx_cache(7 DOWNTO 0); - rx_state <= BUTTONS; - END IF; - - WHEN BUTTONS => - IF s_axis_tvalid = '1' THEN - btn_jstk <= s_axis_tdata(0); - btn_trigger <= s_axis_tdata(1); - rx_state <= JSTK_X_LOW; - END IF; - - END CASE; - END IF; - END IF; - - END PROCESS RX; + WHEN BUTTONS => + IF s_axis_tvalid = '1' THEN + btn_jstk <= s_axis_tdata(0); + btn_trigger <= s_axis_tdata(1); + rx_state <= IDLE; + rx_done <= '1'; -- Risposta completa ricevuta + END IF; + END CASE; + END IF; + END IF; + END PROCESS RX; END ARCHITECTURE; \ No newline at end of file diff --git a/LAB3/test/uart_viewer.py b/LAB3/test/uart_viewer.py index 07b2d2d..ad6fb2f 100644 --- a/LAB3/test/uart_viewer.py +++ b/LAB3/test/uart_viewer.py @@ -1,11 +1,24 @@ import serial +import serial.tools.list_ports import time # CONFIGURAZIONE -PORT = 'COM4' # Cambia con la tua porta: es. 'COM3' su Windows o '/dev/ttyUSB0' su Linux +BASYS3_PID = 0x6010 +BASYS3_VID = 0x0403 BAUDRATE = 115200 # Imposta la tua velocità CHUNK_SIZE = 4 # 4 byte per riga +# Ricerca automatica della porta Basys3 +dev = "" +for port in serial.tools.list_ports.comports(): + if (port.vid == BASYS3_VID and port.pid == BASYS3_PID): + dev = port.device + +if not dev: + raise RuntimeError("Basys 3 Not Found!") + +PORT = dev + def receive_mode(ser): print("Modalità ricezione. Premi Ctrl+C per uscire.\n") while True: @@ -41,16 +54,20 @@ def send_mode(ser): try: mode = "" - while mode not in ["r", "s"]: - mode = input("Vuoi ricevere (r) o inviare (s) dati? [r/s]: ").strip().lower() + while mode not in ["r", "s", "4"]: + mode = input("Vuoi ricevere (r), inviare (s) ? [r/s]: ").strip().lower() ser = serial.Serial(PORT, BAUDRATE, timeout=1) print(f"Aperta porta seriale: {PORT} a {BAUDRATE} baud.\n") if mode == "r": receive_mode(ser) - else: + elif mode == "s": send_mode(ser) + else: + print("Selezione non valida. Uscita...") + ser.close() + exit(1) except KeyboardInterrupt: print("\nChiusura programma...") diff --git a/LAB3/vivado/diligent_jstk/diligent_jstk.xpr b/LAB3/vivado/diligent_jstk/diligent_jstk.xpr index b670b84..248e1d7 100644 --- a/LAB3/vivado/diligent_jstk/diligent_jstk.xpr +++ b/LAB3/vivado/diligent_jstk/diligent_jstk.xpr @@ -48,20 +48,20 @@