From c4a48db729f1e3943628a7df2e49339cac217a26 Mon Sep 17 00:00:00 2001 From: Davide Date: Tue, 3 Jun 2025 17:18:41 +0200 Subject: [PATCH] refactor: Enhance comments and code clarity in led_level_controller.vhd --- LAB3/src/led_level_controller.vhd | 92 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/LAB3/src/led_level_controller.vhd b/LAB3/src/led_level_controller.vhd index d42dac1..2b9defd 100644 --- a/LAB3/src/led_level_controller.vhd +++ b/LAB3/src/led_level_controller.vhd @@ -6,39 +6,36 @@ USE IEEE.MATH_REAL.ALL; -- Entity: led_level_controller -- Purpose: Audio level meter using LEDs to display real-time audio amplitude -- Processes stereo audio samples and drives a bar graph LED display --- Provides visual feedback of audio signal strength for both channels combined ENTITY led_level_controller IS GENERIC ( - NUM_LEDS : POSITIVE := 16; -- Number of LEDs in the level meter display - CHANNEL_LENGHT : POSITIVE := 24; -- Width of audio data (24-bit audio samples) - refresh_time_ms : POSITIVE := 1; -- LED refresh rate in milliseconds (1ms = 1kHz update rate) - clock_period_ns : POSITIVE := 10 -- System clock period in nanoseconds (10ns = 100MHz) + NUM_LEDS : POSITIVE := 16; -- Number of LEDs in the level meter display + CHANNEL_LENGHT : POSITIVE := 24; -- Width of audio data (24-bit audio samples) + refresh_time_ms : POSITIVE := 1; -- LED refresh rate in milliseconds (1ms = 1kHz update rate) + clock_period_ns : POSITIVE := 10 -- System clock period in nanoseconds (10ns = 100MHz) ); PORT ( -- Clock and reset signals - aclk : IN STD_LOGIC; -- Main clock input - aresetn : IN STD_LOGIC; -- Active-low asynchronous reset + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset -- LED output array (bar graph display) - led : OUT STD_LOGIC_VECTOR(NUM_LEDS - 1 DOWNTO 0); -- LED control signals (1=on, 0=off) + led : OUT STD_LOGIC_VECTOR(NUM_LEDS - 1 DOWNTO 0); -- LED control signals (1=on, 0=off) -- AXI4-Stream Slave Interface (Audio Input) - s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal - s_axis_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Audio sample input - s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=right, 1=left) - s_axis_tready : OUT STD_LOGIC -- Always ready to accept data + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=right, 1=left) + s_axis_tready : OUT STD_LOGIC -- Always ready to accept data ); END led_level_controller; ARCHITECTURE Behavioral OF led_level_controller IS -- Calculate clock cycles needed for LED refresh timing - -- Formula: (refresh_time_ms * 1_000_000 ns/ms) / clock_period_ns - -- Example: (1ms * 1,000,000) / 10ns = 100,000 cycles for 1ms refresh at 100MHz CONSTANT REFRESH_CYCLES : INTEGER := (refresh_time_ms * 1_000_000) / clock_period_ns - 1; -- Calculate the number of bits needed to represent the number of LEDs - CONSTANT NUMLEDS_BITS : INTEGER := INTEGER(ceil(log2(real(NUM_LEDS)))); + CONSTANT NUMLEDS_BITS : INTEGER := INTEGER(ceil(log2(real(NUM_LEDS)))); -- LED refresh timing control signals SIGNAL refresh_counter : INTEGER RANGE 0 TO REFRESH_CYCLES := 0; -- Counts clock cycles between LED updates @@ -50,17 +47,18 @@ ARCHITECTURE Behavioral OF led_level_controller IS BEGIN - -- AXI4-Stream interface: Always ready to receive audio data - -- This ensures continuous audio processing without backpressure + -- Always ready for AXI4-Stream input s_axis_tready <= '1'; - -- Audio sample acquisition process based on channel identification - -- Processes incoming stereo audio samples and converts to absolute amplitude values - -- Uses s_axis_tlast to distinguish between left (1) and right (0) channels + -- Capture absolute value of input sample for left/right channel PROCESS (aclk) - VARIABLE signed_sample : SIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); -- Temporary variable for signed arithmetic + + VARIABLE signed_sample : SIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN -- Reset: Clear both channel amplitude registers abs_l <= (OTHERS => '0'); @@ -79,64 +77,72 @@ BEGIN -- Right channel: Store absolute value of audio sample abs_r <= UNSIGNED(ABS(signed_sample)); END IF; + END IF; + END IF; + END PROCESS; - -- LED refresh timing generator process - -- Creates a periodic tick signal to control LED update rate - -- Prevents LED flickering by limiting update frequency to human-visible rates + -- LED refresh tick generator PROCESS (aclk) BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN -- Reset: Initialize counter and tick signal refresh_counter <= 0; refresh_tick <= '0'; + ELSE - -- Normal operation: Count clock cycles and generate refresh tick IF refresh_counter = REFRESH_CYCLES THEN - -- End of refresh period: Reset counter and generate tick pulse refresh_counter <= 0; - refresh_tick <= '1'; -- Single clock cycle pulse for LED update + refresh_tick <= '1'; + ELSE - -- Continue counting: Increment counter, no tick refresh_counter <= refresh_counter + 1; refresh_tick <= '0'; + END IF; + END IF; + END IF; + END PROCESS; -- LED level calculation and bar graph generation process -- Combines left and right channel amplitudes and converts to LED display pattern -- Updates only when refresh_tick is active to maintain stable visual display PROCESS (aclk) - VARIABLE combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); -- Combined amplitude of both channels - VARIABLE led_level : INTEGER RANGE 0 TO 2**NUMLEDS_BITS := 0; -- Calculated LED level for bar graph display + + VARIABLE combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); + VARIABLE led_level : INTEGER RANGE 0 TO 2 ** NUMLEDS_BITS := 0; + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN -- Reset: Turn off all LEDs and reset level counter led <= (OTHERS => '0'); ELSIF refresh_tick = '1' THEN -- LED update cycle: Calculate new LED pattern based on audio amplitude - -- This section is executed once per refresh_tick to avoid flicker and ensure a stable display. -- Combine left and right channel amplitudes - -- The sum of the absolute values of both channels gives a measure of total audio energy. -- RESIZE ensures the sum fits within the variable's bit width. - -- There isn't data loss here since both abs_l and abs_r are one bit shorter than combined_amp, + -- There isn't data loss since both abs_l and abs_r are one bit shorter than combined_amp, -- due to the absolute value operation. combined_amp := RESIZE(abs_l + abs_r, combined_amp'LENGTH); - -- Normalize combined amplitude to LED scale (0 to NUM_LEDS) - -- The combined amplitude is mapped to the number of LEDs using a right shift. - -- For 24-bit audio, shifting by (CHANNEL_LENGHT - 4) reduces the range to approximately 4 bits (0-15). - -- Adding 1 ensures that at least one LED lights up for any non-zero audio input. - -- Example: For 24-bit input, 1 + (combined_amp >> 20) gives a range from 1 to 16. - led_level := 1 + to_integer(shift_right(combined_amp, CHANNEL_LENGHT - NUMLEDS_BITS)); + -- Linear scale to LED level conversion to get the best visual effect + IF combined_amp = 0 THEN + led_level := 0; -- No audio signal, turn off all LEDs + ELSE + led_level := 1 + to_integer(shift_right(combined_amp, CHANNEL_LENGHT - NUMLEDS_BITS)); + END IF; -- Saturation protection: Limit LED level to maximum available LEDs -- Prevents overflow and ensures the LED index stays within bounds. @@ -144,16 +150,16 @@ BEGIN led_level := NUM_LEDS; END IF; - -- Generate bar graph LED pattern - -- Implements a "thermometer" style display: all LEDs from 0 up to (led_level-1) are ON. - -- All higher LEDs remain OFF. - -- The assignment first turns all LEDs OFF, then sets the lower 'led_level' LEDs ON. + -- Update LED output based on calculated level led <= (OTHERS => '0'); IF led_level > 0 THEN led(led_level - 1 DOWNTO 0) <= (OTHERS => '1'); END IF; + END IF; + END IF; + END PROCESS; END Behavioral; \ No newline at end of file