Compare commits

...

9 Commits

13 changed files with 177 additions and 115 deletions

39
LAB2/Readme.md Normal file
View File

@@ -0,0 +1,39 @@
# LAB2 Project Presentation
## Project Description
The LAB2 project consists of the design and implementation of a digital system for image processing and data communication. The system is composed of several functional blocks, each responsible for a specific task in the processing pipeline. The main objectives are:
- Receive and process image data
- Perform color space conversion (e.g., RGB to grayscale)
- Apply convolution filters to the image
- Packetize the processed data for transmission
- Support loopback and test modes for verification
## Block Diagram
Below is a conceptual block diagram of the LAB2 system:
```mermaid
flowchart LR
IN[PC] -.-> UART[UART]
UART -.-> IN
UART --> DEPACK[Depack]
DEPACK --> C2G[Color to Grayscale Converter]
C2G --> BRAM[BRAM Writer]
BRAM --> Underflow
BRAM -->Overflow
BRAM -->Ok
BRAM <-.-> CONV[Convolution Filter]
BRAM <-.-> CONV
CONV --> PACK[Packetizer]
PACK --> UART
```
## Areas for Improvement
- In loopback mode, when sending an empty packet (FFF1), the module temporarily stores H and F and prepends them to the header of the next packet. There is an error in the pack/depack logic.
- The implementation of the depacketizer is complex, and the precise error has not been identified.
- The color conversion (C2G) uses a divider by 3, but the approximation method is unclear (it sums half of the power-of-two factor used in the divider—why?). -> Just add comments explainig how it works
- Convolution is performed with various unconstrained integers.
- In general, the VHDL code is somewhat complex, although generally correct. Aim to simplify and make the code more readable.

16
LAB3/Readme.md Normal file
View File

@@ -0,0 +1,16 @@
# LAB3 Project Presentation
## Project Description
*To be completed: Add a description of the LAB3 project here.*
## Block Diagram
*To be completed: Add a block diagram of the LAB3 system here (e.g., using Mermaid or an image).*
## Areas for Improvement
- JSTK: Non-atomicity in writing to the RGB LED; the rest is well done and clear.
- Mute: (IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN) AXIS error; s_axis_tready should be checked. The original would be correct if s_axis_tready was directly connected to m_axis_tready. As written, it waits for ready to assert valid.
- Volume controller: Waits for ready to assert valid (IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN).
- Balance: (IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN) AXI condition is incorrect; the rest is correct.

View File

@@ -3,7 +3,7 @@ USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL; USE IEEE.NUMERIC_STD.ALL;
-- Entity: LFO (Low Frequency Oscillator) - Alternative Implementation -- Entity: LFO (Low Frequency Oscillator) - Alternative Implementation
-- Purpose: Applies tremolo effect to audio by modulating amplitude with a triangular wave -- Purpose: Applies effect to audio by modulating amplitude with a triangular wave
-- This is a simplified, single-process implementation compared to the pipelined version -- This is a simplified, single-process implementation compared to the pipelined version
-- Provides real-time audio amplitude modulation for musical effects -- Provides real-time audio amplitude modulation for musical effects
ENTITY LFO IS ENTITY LFO IS
@@ -24,13 +24,13 @@ ENTITY LFO IS
-- Slave AXI Stream interface (audio input) -- Slave AXI Stream interface (audio input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal 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_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Audio sample input
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- Master AXI Stream interface (audio output) -- Master AXI Stream interface (audio output)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Modulated audio sample output m_axis_tdata : OUT STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Modulated audio sample output
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
m_axis_tready : IN STD_LOGIC -- Downstream ready signal m_axis_tready : IN STD_LOGIC -- Downstream ready signal
); );
@@ -57,7 +57,7 @@ ARCHITECTURE Behavioral OF LFO IS
-- Triangular wave generation signals -- Triangular wave generation signals
-- Note: Using signed counter with extra bit to handle full range calculations -- Note: Using signed counter with extra bit to handle full range calculations
SIGNAL tri_counter : SIGNED(TRIANGULAR_COUNTER_LENGHT DOWNTO 0) := (OTHERS => '0'); -- Triangular wave amplitude SIGNAL tri_counter : SIGNED(TRIANGULAR_COUNTER_LENGHT DOWNTO 0) := (OTHERS => '0'); -- Triangular wave amplitude
SIGNAL direction_up : STD_LOGIC := '1'; -- Wave direction: '1' = ascending, '0' = descending SIGNAL direction_up : STD_LOGIC := '1'; -- Wave direction: '1' = ascending, '0' = descending
-- AXI4-Stream control signals -- AXI4-Stream control signals
@@ -92,11 +92,11 @@ BEGIN
ELSE ELSE
-- Calculate LFO period based on joystick input -- Calculate LFO period based on joystick input
-- Joystick mapping: -- Joystick mapping:
-- 0-511: Faster than base frequency (shorter period, higher frequency) -- 0-511: Slower than base frequency (longer period, lower frequency)
-- 512: Base frequency (1kHz) -- 512: Base frequency (1kHz)
-- 513-1023: Slower than base frequency (longer period, lower frequency) -- 513-1023: Faster than base frequency (shorter period, higher frequency)
step_clk_cycles_delta <= (to_integer(unsigned(lfo_period)) - JSTK_CENTER_VALUE) * ADJUSTMENT_FACTOR; step_clk_cycles_delta <= (to_integer(unsigned(lfo_period)) - JSTK_CENTER_VALUE);
step_clk_cycles <= LFO_COUNTER_BASE_CLK_CYCLES - step_clk_cycles_delta; step_clk_cycles <= LFO_COUNTER_BASE_CLK_CYCLES - step_clk_cycles_delta * ADJUSTMENT_FACTOR;
-- Generate triangular wave when LFO is enabled -- Generate triangular wave when LFO is enabled
IF lfo_enable = '1' THEN IF lfo_enable = '1' THEN
@@ -106,7 +106,7 @@ BEGIN
step_counter <= 0; -- Reset counter for next period step_counter <= 0; -- Reset counter for next period
-- Check for triangular wave direction changes at extremes -- Check for triangular wave direction changes at extremes
-- Note: Using (2^n - 2) and 1 instead of (2^n - 1) and 0 to avoid edge cases -- Note: Using (2^n - 2) and 1 instead of (2^n - 1) and 0 due to process signal assignment
IF tri_counter = (2 ** TRIANGULAR_COUNTER_LENGHT) - 2 THEN IF tri_counter = (2 ** TRIANGULAR_COUNTER_LENGHT) - 2 THEN
direction_up <= '0'; -- Switch to descending at near-maximum direction_up <= '0'; -- Switch to descending at near-maximum
@@ -180,8 +180,8 @@ BEGIN
-- Data input logic: Process new audio samples when available and output is ready -- Data input logic: Process new audio samples when available and output is ready
IF s_axis_tvalid = '1' AND (m_axis_tready = '1' OR m_axis_tvalid_int = '0') THEN IF s_axis_tvalid = '1' AND (m_axis_tready = '1' OR m_axis_tvalid_int = '0') THEN
IF lfo_enable = '1' THEN IF lfo_enable = '1' THEN
-- Apply LFO tremolo effect: multiply audio sample by triangular wave -- Apply LFO effect: multiply audio sample by triangular wave
-- This creates amplitude modulation (tremolo effect) -- This creates amplitude modulation (effect)
m_axis_tdata_temp <= signed(s_axis_tdata) * tri_counter; m_axis_tdata_temp <= signed(s_axis_tdata) * tri_counter;
s_axis_tlast_reg <= s_axis_tlast; -- Register channel indicator s_axis_tlast_reg <= s_axis_tlast; -- Register channel indicator
@@ -212,11 +212,11 @@ BEGIN
-- LFO Implementation Summary: -- LFO Implementation Summary:
-- 1. Generates triangular wave at frequency controlled by joystick input -- 1. Generates triangular wave at frequency controlled by joystick input
-- 2. When enabled: multiplies audio samples by triangular wave (tremolo effect) -- 2. When enabled: multiplies audio samples by triangular wave (multiplier value range from 0 to 1)
-- 3. When disabled: passes audio through unchanged (bypass mode) -- 3. When disabled: passes audio through unchanged (bypass mode)
-- 4. Uses proper AXI4-Stream handshaking for real-time audio processing -- 4. Uses proper AXI4-Stream handshaking for real-time audio processing
-- --
-- Tremolo Effect Characteristics: -- Effect Characteristics:
-- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO) -- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO)
-- - Modulation depth: Controlled by TRIANGULAR_COUNTER_LENGHT generic -- - Modulation depth: Controlled by TRIANGULAR_COUNTER_LENGHT generic
-- - Waveform: Triangular (linear amplitude changes, smooth transitions) -- - Waveform: Triangular (linear amplitude changes, smooth transitions)

View File

@@ -4,7 +4,7 @@ USE ieee.numeric_std.ALL;
-- Entity: all_pass_filter -- Entity: all_pass_filter
-- Purpose: A pass-through filter that maintains the same interface and timing -- Purpose: A pass-through filter that maintains the same interface and timing
-- characteristics as a moving average filter but passes data unchanged. -- characteristics as the moving average filter but passes data unchanged.
ENTITY all_pass_filter IS ENTITY all_pass_filter IS
GENERIC ( GENERIC (
TDATA_WIDTH : POSITIVE := 24 -- Width of the data bus in bits TDATA_WIDTH : POSITIVE := 24 -- Width of the data bus in bits
@@ -16,13 +16,13 @@ ENTITY all_pass_filter IS
-- AXI4-Stream Slave Interface (Input) -- AXI4-Stream Slave Interface (Input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Input data s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Input data
s_axis_tlast : IN STD_LOGIC; -- Input end-of-packet signal s_axis_tlast : IN STD_LOGIC; -- Input end-of-packet signal
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- AXI4-Stream Master Interface (Output) -- AXI4-Stream Master Interface (Output)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Output data m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Output data
m_axis_tlast : OUT STD_LOGIC; -- Output end-of-packet signal m_axis_tlast : OUT STD_LOGIC; -- Output end-of-packet signal
m_axis_tready : IN STD_LOGIC -- Downstream ready signal m_axis_tready : IN STD_LOGIC -- Downstream ready signal
); );
@@ -36,9 +36,9 @@ ARCHITECTURE Behavioral OF all_pass_filter IS
-- Internal slave interface signals -- Internal slave interface signals
SIGNAL s_axis_tready_int : STD_LOGIC := '0'; -- Internal ready signal for input SIGNAL s_axis_tready_int : STD_LOGIC := '0'; -- Internal ready signal for input
SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of input tlast SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of input tlast
SIGNAL s_axis_tdata_reg : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Temporary storage for input data
-- Internal data storage and master interface signals -- Internal data storage and master interface signals
SIGNAL m_axis_tdata_temp : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Temporary storage for input data
SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal valid signal for output SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal valid signal for output
BEGIN BEGIN
@@ -66,10 +66,10 @@ BEGIN
-- Asynchronous reset logic (active low) -- Asynchronous reset logic (active low)
IF aresetn = '0' THEN IF aresetn = '0' THEN
-- Reset all internal signals to known states -- Reset all internal signals to known states
trigger <= '0'; -- Clear data processing trigger trigger <= '0'; -- Clear data processing trigger
s_axis_tlast_reg <= '0'; -- Clear registered tlast s_axis_tlast_reg <= '0'; -- Clear registered tlast
s_axis_tready_int <= '0'; -- Not ready to accept data during reset s_axis_tready_int <= '0'; -- Not ready to accept data during reset
m_axis_tdata_temp <= (OTHERS => '0'); -- Clear temporary data storage s_axis_tdata_reg <= (OTHERS => '0'); -- Clear temporary data storage
m_axis_tvalid_int <= '0'; -- No valid data on output during reset m_axis_tvalid_int <= '0'; -- No valid data on output during reset
m_axis_tlast <= '0'; -- Clear output tlast m_axis_tlast <= '0'; -- Clear output tlast
@@ -88,7 +88,7 @@ BEGIN
-- (either no valid data pending OR downstream is ready) -- (either no valid data pending OR downstream is ready)
IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN
-- Transfer stored data to output -- Transfer stored data to output
m_axis_tdata <= m_axis_tdata_temp; -- Output the stored input data unchanged m_axis_tdata <= s_axis_tdata_reg; -- Output the stored input data unchanged
m_axis_tlast <= s_axis_tlast_reg; -- Output the registered tlast signal m_axis_tlast <= s_axis_tlast_reg; -- Output the registered tlast signal
-- Set output control signals -- Set output control signals
@@ -101,7 +101,7 @@ BEGIN
IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN
-- Store input signals for later output -- Store input signals for later output
s_axis_tlast_reg <= s_axis_tlast; -- Register the tlast signal s_axis_tlast_reg <= s_axis_tlast; -- Register the tlast signal
m_axis_tdata_temp <= s_axis_tdata; -- Store input data (pass-through, no processing) s_axis_tdata_reg <= s_axis_tdata; -- Store input data (pass-through, no processing)
-- Set trigger to indicate data is ready for output -- Set trigger to indicate data is ready for output
trigger <= '1'; trigger <= '1';

View File

@@ -19,25 +19,25 @@ ENTITY balance_controller IS
-- AXI4-Stream Slave Interface (Audio Input) -- AXI4-Stream Slave Interface (Audio Input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid s_axis_tvalid : IN STD_LOGIC; -- Input data valid
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample data s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample data
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input s_axis_tready : OUT STD_LOGIC; -- Ready to accept input
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
-- AXI4-Stream Master Interface (Audio Output) -- AXI4-Stream Master Interface (Audio Output)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid m_axis_tvalid : OUT STD_LOGIC; -- Output data valid
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Balanced audio sample m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Balanced audio sample
m_axis_tready : IN STD_LOGIC; -- Downstream ready m_axis_tready : IN STD_LOGIC; -- Downstream ready
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
-- Balance Control Input -- Balance Control Input
balance : IN STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) -- Balance position (0=full left, 1023=full right, 512=center) balance : IN STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) -- Balance position (0=full left, 1023=full right, 512=center)
); );
END balance_controller; END balance_controller;
ARCHITECTURE Behavioral OF balance_controller IS ARCHITECTURE Behavioral OF balance_controller IS
-- Balance calculation constants -- Balance calculation constants
CONSTANT BALANCE_STEPS : INTEGER := (2 ** (BALANCE_WIDTH - 1)) / (2 ** BALANCE_STEP_2) + 1; -- Number of attenuation steps (9 steps for 10-bit balance) CONSTANT BALANCE_STEPS : INTEGER := (2 ** (BALANCE_WIDTH - 1)) / (2 ** BALANCE_STEP_2) + 1; -- Number of attenuation steps (9 steps for 10-bit balance)
CONSTANT BAL_MID : INTEGER := 2 ** (BALANCE_WIDTH - 1); -- Center balance position (512 for 10-bit) CONSTANT BAL_MID : INTEGER := 2 ** (BALANCE_WIDTH - 1); -- Center balance position (512 for 10-bit)
CONSTANT DEAD_ZONE : INTEGER := (2 ** BALANCE_STEP_2) / 2; -- Dead zone around center (32 for step size 64) CONSTANT DEAD_ZONE : INTEGER := (2 ** BALANCE_STEP_2) / 2; -- Dead zone around center (32 for step size 64)

View File

@@ -16,17 +16,17 @@ ENTITY digilent_jstk2 IS
-- AXI4-Stream Master Interface: Data going TO the SPI IP-Core (and so, to the JSTK2 module) -- AXI4-Stream Master Interface: Data going TO the SPI IP-Core (and so, to the JSTK2 module)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- 8-bit data to send via SPI m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- 8-bit data to send via SPI
m_axis_tready : IN STD_LOGIC; -- SPI IP-Core ready to accept data m_axis_tready : IN STD_LOGIC; -- SPI IP-Core ready to accept data
-- AXI4-Stream Slave Interface: Data coming FROM the SPI IP-Core (and so, from the JSTK2 module) -- AXI4-Stream Slave Interface: Data coming FROM the SPI IP-Core (and so, from the JSTK2 module)
-- Note: There is no tready signal, so you must be always ready to accept incoming data, or it will be lost! -- Note: There is no tready signal, so you must be always ready to accept incoming data, or it will be lost!
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 8-bit data received via SPI s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 8-bit data received via SPI
-- Joystick and button values read from the JSTK2 module -- Joystick and button values read from the JSTK2 module
jstk_x : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- X-axis joystick position (10-bit, 0-1023) jstk_x : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- X-axis joystick position (10-bit, 0-1023)
jstk_y : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- Y-axis joystick position (10-bit, 0-1023) jstk_y : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- Y-axis joystick position (10-bit, 0-1023)
btn_jstk : OUT STD_LOGIC; -- Joystick button state (1=pressed) btn_jstk : OUT STD_LOGIC; -- Joystick button state (1=pressed)
btn_trigger : OUT STD_LOGIC; -- Trigger button state (1=pressed) btn_trigger : OUT STD_LOGIC; -- Trigger button state (1=pressed)
@@ -44,7 +44,7 @@ ARCHITECTURE Behavioral OF digilent_jstk2 IS
-- Calculate delay in clock cycles: (delay_period + 1_SPI_clock_period) * clock_frequency -- Calculate delay in clock cycles: (delay_period + 1_SPI_clock_period) * clock_frequency
-- This ensures proper timing between SPI packets as required by JSTK2 datasheet -- This ensures proper timing between SPI packets as required by JSTK2 datasheet
CONSTANT DELAY_CLK_CYCLES : INTEGER := (DELAY_US + 1_000_000 / SPI_SCLKFREQ) * (CLKFREQ / 1_000_000); CONSTANT DELAY_CLK_CYCLES : INTEGER := (DELAY_US + 1_000_000 / SPI_SCLKFREQ) * (CLKFREQ / 1_000_000) - 1;
-- State machine type definitions -- State machine type definitions
TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY); TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY);
@@ -56,7 +56,7 @@ ARCHITECTURE Behavioral OF digilent_jstk2 IS
-- Timing and data storage signals -- Timing and data storage signals
SIGNAL tx_delay_counter : INTEGER RANGE 0 TO DELAY_CLK_CYCLES := 0; -- Counter for inter-packet delay timing SIGNAL tx_delay_counter : INTEGER RANGE 0 TO DELAY_CLK_CYCLES := 0; -- Counter for inter-packet delay timing
SIGNAL rx_cache : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Temporary storage for multi-byte data reception SIGNAL rx_cache : STD_LOGIC_VECTOR(s_axis_tdata'range); -- Temporary storage for multi-byte data reception
BEGIN BEGIN
@@ -80,7 +80,8 @@ BEGIN
"01101001" WHEN SEND_DUMMY; -- Dummy byte to complete 5-byte transaction "01101001" WHEN SEND_DUMMY; -- Dummy byte to complete 5-byte transaction
-- TX State Machine: Sends LED color commands to JSTK2 module -- TX State Machine: Sends LED color commands to JSTK2 module
-- Protocol: Command(1) + Red(1) + Green(1) + Blue(1) + Dummy(1) = 5 bytes total -- Protocol: Command(1) + Red(1) + Green(1) + Blue(1) + Dummy(1) = 5 bytes total > Delay before next command
-- The delay is required by the JSTK datasheet to ensure proper timing between SPI transactions
TX : PROCESS (aclk) TX : PROCESS (aclk)
BEGIN BEGIN
IF rising_edge(aclk) THEN IF rising_edge(aclk) THEN

View File

@@ -28,7 +28,7 @@ END effect_selector;
ARCHITECTURE Behavioral OF effect_selector IS ARCHITECTURE Behavioral OF effect_selector IS
constant JOYSTICK_DEFAULT : STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_unsigned(2 ** (JOYSTICK_LENGHT - 1), JOYSTICK_LENGHT)); -- Default joystick value constant JOYSTICK_DEFAULT : STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_unsigned(2 ** (JOYSTICK_LENGHT - 1), JOYSTICK_LENGHT)); -- Default joystick value (center position for 10-bit joystick is 512)
BEGIN BEGIN
@@ -52,9 +52,11 @@ BEGIN
-- X-axis behavior differs between modes -- X-axis behavior differs between modes
-- Note: When switching between modes, some outputs are reset while others preserved -- Note: When switching between modes, some outputs are reset while others preserved
IF effect = '1' THEN IF effect = '1' THEN
-- LFO Mode: Y-axis controls Low Frequency Oscillator period -- LFO Mode:
-- Used for tremolo, vibrato, or other modulation effects -- Y-axis controls Low Frequency Oscillator period
-- X-axis is ignored in this mode
lfo_period <= jstck_y; lfo_period <= jstck_y;
-- Volume remains at last set value (preserved from previous mode) -- Volume remains at last set value (preserved from previous mode)
-- Reset balance to center/default position when in LFO mode -- Reset balance to center/default position when in LFO mode
@@ -64,9 +66,9 @@ BEGIN
-- Volume/Balance Mode: -- Volume/Balance Mode:
-- Y-axis controls overall volume level -- Y-axis controls overall volume level
-- X-axis controls left/right audio balance -- X-axis controls left/right audio balance
-- Traditional audio mixer control mode
volume <= jstck_y; volume <= jstck_y;
balance <= jstck_x; balance <= jstck_x;
-- LFO period remains at last set value (preserved from previous LFO mode) -- LFO period remains at last set value (preserved from previous LFO mode)
END IF; END IF;

View File

@@ -1,11 +1,11 @@
LIBRARY IEEE; LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL; USE IEEE.NUMERIC_STD.ALL;
USE IEEE.MATH_REAL.ALL;
-- Entity: led_level_controller -- Entity: led_level_controller
-- Purpose: Audio level meter using LEDs to display real-time audio amplitude -- Purpose: Audio level meter using LEDs to display real-time audio amplitude
-- Processes stereo audio samples and drives a bar graph LED display -- 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 ENTITY led_level_controller IS
GENERIC ( GENERIC (
NUM_LEDS : POSITIVE := 16; -- Number of LEDs in the level meter display NUM_LEDS : POSITIVE := 16; -- Number of LEDs in the level meter display
@@ -32,9 +32,10 @@ END led_level_controller;
ARCHITECTURE Behavioral OF led_level_controller IS ARCHITECTURE Behavioral OF led_level_controller IS
-- Calculate clock cycles needed for LED refresh timing -- Calculate clock cycles needed for LED refresh timing
-- Formula: (refresh_time_ms * 1_000_000 ns/ms) / clock_period_ns CONSTANT REFRESH_CYCLES : INTEGER := (refresh_time_ms * 1_000_000) / clock_period_ns - 1;
-- 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; -- Calculate the number of bits needed to represent the number of LEDs
CONSTANT NUMLEDS_BITS : INTEGER := INTEGER(ceil(log2(real(NUM_LEDS))));
-- LED refresh timing control signals -- LED refresh timing control signals
SIGNAL refresh_counter : INTEGER RANGE 0 TO REFRESH_CYCLES := 0; -- Counts clock cycles between LED updates SIGNAL refresh_counter : INTEGER RANGE 0 TO REFRESH_CYCLES := 0; -- Counts clock cycles between LED updates
@@ -42,112 +43,123 @@ ARCHITECTURE Behavioral OF led_level_controller IS
-- Audio amplitude storage for both stereo channels -- Audio amplitude storage for both stereo channels
-- Stores absolute values (magnitude) of left and right audio channels -- Stores absolute values (magnitude) of left and right audio channels
SIGNAL abs_l, abs_r : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Absolute amplitude registers SIGNAL abs_l : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Absolute left channel amplitude registers
SIGNAL combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Combined amplitude for LED level calculation
BEGIN BEGIN
-- AXI4-Stream interface: Always ready to receive audio data -- Always ready for AXI4-Stream input
-- This ensures continuous audio processing without backpressure
s_axis_tready <= '1'; s_axis_tready <= '1';
-- Audio sample acquisition process based on channel identification -- Capture absolute value of input sample for left/right channel
-- Processes incoming stereo audio samples and converts to absolute amplitude values
-- Uses s_axis_tlast to distinguish between left (1) and right (0) channels
PROCESS (aclk) PROCESS (aclk)
VARIABLE signed_sample : SIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); -- Temporary variable for signed arithmetic
BEGIN BEGIN
IF rising_edge(aclk) THEN IF rising_edge(aclk) THEN
IF aresetn = '0' THEN IF aresetn = '0' THEN
-- Reset: Clear both channel amplitude registers -- Reset: Clear both channel amplitude registers
abs_l <= (OTHERS => '0'); abs_l <= (OTHERS => '0');
abs_r <= (OTHERS => '0'); combined_amp <= (OTHERS => '0');
ELSIF s_axis_tvalid = '1' THEN ELSIF s_axis_tvalid = '1' THEN
-- Valid audio data received: Process the sample -- Valid audio data received: Process the sample
signed_sample := SIGNED(s_axis_tdata); -- Convert input to signed for ABS operation
-- Channel routing based on AXI4-Stream tlast signal -- Channel routing based on AXI4-Stream tlast signal
-- tlast = '1' indicates left channel, tlast = '0' indicates right channel -- tlast = '1' indicates right channel, tlast = '0' indicates left channel
IF s_axis_tlast = '1' THEN IF s_axis_tlast = '1' THEN
-- Left channel: Store absolute value of audio sample -- Right channel: Combine left and right channel amplitudes
abs_l <= UNSIGNED(ABS(signed_sample)); -- RESIZE ensures the sum fits within the variable's bit width.
-- There isn't data loss since both abs_l and abs(s_axis_tdata) are one bit shorter than combined_amp,
-- due to the absolute value operation.
combined_amp <= RESIZE(abs_l + UNSIGNED(ABS(SIGNED(s_axis_tdata))), combined_amp'LENGTH);
ELSE ELSE
-- Right channel: Store absolute value of audio sample -- Left channel: Store absolute value of audio sample
abs_r <= UNSIGNED(ABS(signed_sample)); abs_l <= UNSIGNED(ABS(SIGNED(s_axis_tdata)));
END IF; END IF;
END IF; END IF;
END IF; END IF;
END PROCESS; END PROCESS;
-- LED refresh timing generator process -- LED refresh tick generator
-- Creates a periodic tick signal to control LED update rate
-- Prevents LED flickering by limiting update frequency to human-visible rates
PROCESS (aclk) PROCESS (aclk)
BEGIN BEGIN
IF rising_edge(aclk) THEN IF rising_edge(aclk) THEN
IF aresetn = '0' THEN IF aresetn = '0' THEN
-- Reset: Initialize counter and tick signal -- Reset: Initialize counter and tick signal
refresh_counter <= 0; refresh_counter <= 0;
refresh_tick <= '0'; refresh_tick <= '0';
ELSE ELSE
-- Normal operation: Count clock cycles and generate refresh tick IF refresh_counter = REFRESH_CYCLES THEN
IF refresh_counter = REFRESH_CYCLES - 1 THEN
-- End of refresh period: Reset counter and generate tick pulse
refresh_counter <= 0; refresh_counter <= 0;
refresh_tick <= '1'; -- Single clock cycle pulse for LED update refresh_tick <= '1';
ELSE ELSE
-- Continue counting: Increment counter, no tick
refresh_counter <= refresh_counter + 1; refresh_counter <= refresh_counter + 1;
refresh_tick <= '0'; refresh_tick <= '0';
END IF; END IF;
END IF; END IF;
END IF; END IF;
END PROCESS; END PROCESS;
-- LED level calculation and bar graph generation process -- LED level calculation and bar graph generation process
-- Combines left and right channel amplitudes and converts to LED display pattern -- Combines left and right channel amplitudes and converts to LED display pattern
-- Updates only when refresh_tick is active to maintain stable visual display -- Updates only when refresh_tick is active to maintain stable visual display
PROCESS (aclk) PROCESS (aclk)
VARIABLE combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); -- Combined amplitude of both channels
VARIABLE led_level : INTEGER RANGE 0 TO NUM_LEDS := 0; -- Calculated LED level for bar graph display VARIABLE led_level : INTEGER RANGE 0 TO 2 ** NUMLEDS_BITS := 0;
BEGIN BEGIN
IF rising_edge(aclk) THEN IF rising_edge(aclk) THEN
IF aresetn = '0' THEN IF aresetn = '0' THEN
-- Reset: Turn off all LEDs and reset level counter -- Reset: Turn off all LEDs and reset level counter
led <= (OTHERS => '0'); led <= (OTHERS => '0');
ELSIF refresh_tick = '1' THEN ELSIF refresh_tick = '1' THEN
-- LED update cycle: Calculate new LED pattern based on audio amplitude -- 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 -- Linear scale to LED level conversion to get the best visual effect
-- The sum of the absolute values of both channels gives a measure of total audio energy. IF combined_amp = 0 THEN
-- RESIZE ensures the sum fits within the variable's bit width. led_level := 0; -- No audio signal, turn off all LEDs
combined_amp := RESIZE(abs_l + abs_r, combined_amp'LENGTH);
-- Normalize combined amplitude to LED scale (0 to NUM_LEDS) ELSE
-- The combined amplitude is mapped to the number of LEDs using a right shift. led_level := 1 + to_integer(shift_right(combined_amp, CHANNEL_LENGHT - NUMLEDS_BITS));
-- 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. END IF;
-- 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 - 4));
-- Saturation protection: Limit LED level to maximum available LEDs -- Saturation protection: Limit LED level to maximum available LEDs
-- Prevents overflow and ensures the LED index stays within bounds. -- Prevents overflow and ensures the LED index stays within bounds.
IF led_level > NUM_LEDS THEN IF led_level > NUM_LEDS THEN
led_level := NUM_LEDS; led_level := NUM_LEDS;
END IF; END IF;
-- Generate bar graph LED pattern -- Update LED output based on calculated level
-- 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.
led <= (OTHERS => '0'); led <= (OTHERS => '0');
IF led_level > 0 THEN IF led_level > 0 THEN
led(led_level - 1 DOWNTO 0) <= (OTHERS => '1'); led(led_level - 1 DOWNTO 0) <= (OTHERS => '1');
END IF; END IF;
END IF; END IF;
END IF; END IF;
END PROCESS; END PROCESS;
END Behavioral; END Behavioral;

View File

@@ -3,7 +3,7 @@ USE IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; USE ieee.numeric_std.ALL;
-- Entity: moving_average_filter -- Entity: moving_average_filter
-- Purpose: Implements a finite impulse response (FIR) low-pass filter using moving average -- Purpose: Implements a moving average filter for audio data
-- Maintains separate circular buffers for left and right audio channels -- Maintains separate circular buffers for left and right audio channels
-- Filter order is configurable as 2^(FILTER_ORDER_POWER) samples -- Filter order is configurable as 2^(FILTER_ORDER_POWER) samples
ENTITY moving_average_filter IS ENTITY moving_average_filter IS
@@ -21,13 +21,13 @@ ENTITY moving_average_filter IS
-- AXI4-Stream Slave Interface (Audio Input) -- AXI4-Stream Slave Interface (Audio Input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- AXI4-Stream Master Interface (Audio Output) -- AXI4-Stream Master Interface (Audio Output)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Filtered audio sample output m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Filtered audio sample output
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
m_axis_tready : IN STD_LOGIC -- Downstream ready signal m_axis_tready : IN STD_LOGIC -- Downstream ready signal
); );
@@ -42,14 +42,14 @@ ARCHITECTURE Behavioral OF moving_average_filter IS
TYPE sample_array IS ARRAY (0 TO FILTER_ORDER - 1) OF signed(TDATA_WIDTH - 1 DOWNTO 0); TYPE sample_array IS ARRAY (0 TO FILTER_ORDER - 1) OF signed(TDATA_WIDTH - 1 DOWNTO 0);
-- Right channel (RX) processing signals -- Right channel (RX) processing signals
SIGNAL samples_rx : sample_array := (OTHERS => (OTHERS => '0')); -- Circular buffer for right channel samples SIGNAL samples_rx : sample_array := (OTHERS => (OTHERS => '0')); -- Circular buffer for right channel samples
SIGNAL sum_rx : signed(TDATA_WIDTH + FILTER_ORDER_POWER - 1 DOWNTO 0) := (OTHERS => '0'); -- Running sum of right channel samples SIGNAL sum_rx : signed(TDATA_WIDTH + FILTER_ORDER_POWER - 1 DOWNTO 0) := (OTHERS => '0'); -- Running sum of right channel samples
SIGNAL wr_ptr_rx : INTEGER RANGE 0 TO FILTER_ORDER - 1 := 0; -- Write pointer for right channel buffer SIGNAL wr_ptr_rx : INTEGER RANGE 0 TO FILTER_ORDER - 1 := 0; -- Write pointer for right channel buffer
-- Left channel (LX) processing signals -- Left channel (LX) processing signals
SIGNAL samples_lx : sample_array := (OTHERS => (OTHERS => '0')); -- Circular buffer for left channel samples SIGNAL samples_lx : sample_array := (OTHERS => (OTHERS => '0')); -- Circular buffer for left channel samples
SIGNAL sum_lx : signed(TDATA_WIDTH + FILTER_ORDER_POWER - 1 DOWNTO 0) := (OTHERS => '0'); -- Running sum of left channel samples SIGNAL sum_lx : signed(TDATA_WIDTH + FILTER_ORDER_POWER - 1 DOWNTO 0) := (OTHERS => '0'); -- Running sum of left channel samples
SIGNAL wr_ptr_lx : INTEGER RANGE 0 TO FILTER_ORDER - 1 := 0; -- Write pointer for left channel buffer SIGNAL wr_ptr_lx : INTEGER RANGE 0 TO FILTER_ORDER - 1 := 0; -- Write pointer for left channel buffer
-- Control and interface signals -- Control and interface signals
SIGNAL trigger : STD_LOGIC := '0'; -- Trigger signal to indicate when to output filtered data SIGNAL trigger : STD_LOGIC := '0'; -- Trigger signal to indicate when to output filtered data

View File

@@ -22,13 +22,13 @@ ENTITY moving_average_filter_en IS
-- AXI4-Stream Slave Interface (Audio Input) -- AXI4-Stream Slave Interface (Audio Input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- AXI4-Stream Master Interface (Audio Output) -- AXI4-Stream Master Interface (Audio Output)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (filtered or unfiltered) m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (filtered or unfiltered)
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
m_axis_tready : IN STD_LOGIC; -- Downstream ready signal m_axis_tready : IN STD_LOGIC; -- Downstream ready signal

View File

@@ -21,13 +21,13 @@ ENTITY volume_controller IS
-- AXI4-Stream Slave Interface (Audio Input) -- AXI4-Stream Slave Interface (Audio Input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- AXI4-Stream Master Interface (Audio Output) -- AXI4-Stream Master Interface (Audio Output)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (volume adjusted) m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (volume adjusted)
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
m_axis_tready : IN STD_LOGIC; -- Downstream ready signal m_axis_tready : IN STD_LOGIC; -- Downstream ready signal
@@ -98,10 +98,10 @@ ARCHITECTURE Behavioral OF volume_controller IS
-- Internal AXI4-Stream signals between multiplier and saturator -- Internal AXI4-Stream signals between multiplier and saturator
-- These signals carry the wide multiplication results before saturation -- These signals carry the wide multiplication results before saturation
SIGNAL int_axis_tvalid : STD_LOGIC; -- Valid signal between stages SIGNAL int_axis_tvalid : STD_LOGIC; -- Valid signal between stages
SIGNAL int_axis_tready : STD_LOGIC; -- Ready signal between stages SIGNAL int_axis_tready : STD_LOGIC; -- Ready signal between stages
SIGNAL int_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Wide data between stages SIGNAL int_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Wide data between stages
SIGNAL int_axis_tlast : STD_LOGIC; -- Channel indicator between stages SIGNAL int_axis_tlast : STD_LOGIC; -- Channel indicator between stages
BEGIN BEGIN

View File

@@ -19,15 +19,15 @@ ENTITY volume_multiplier IS
-- AXI4-Stream Slave Interface (Audio Input) -- AXI4-Stream Slave Interface (Audio Input)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- AXI4-Stream Master Interface (Audio Output with extended width) -- AXI4-Stream Master Interface (Audio Output with extended width)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Extended width output data m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Extended width output data
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
m_axis_tready : IN STD_LOGIC; -- Downstream ready signal m_axis_tready : IN STD_LOGIC; -- Downstream ready signal
-- Volume control input -- Volume control input
volume : IN STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) -- Volume level (0=minimum, 1023=maximum) volume : IN STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) -- Volume level (0=minimum, 1023=maximum)
@@ -37,7 +37,7 @@ END volume_multiplier;
ARCHITECTURE Behavioral OF volume_multiplier IS ARCHITECTURE Behavioral OF volume_multiplier IS
-- Calculate volume control parameters based on generics -- Calculate volume control parameters based on generics
CONSTANT VOLUME_STEPS : INTEGER := (2 ** (VOLUME_WIDTH - 1)) / (2 ** VOLUME_STEP_2) + 1; -- Number of volume steps (9 steps for 10-bit) CONSTANT VOLUME_STEPS : INTEGER := (2 ** (VOLUME_WIDTH - 1)) / (2 ** VOLUME_STEP_2) + 1; -- Number of volume steps (9 steps for 10-bit)
CONSTANT VOL_MID : INTEGER := 2 ** (VOLUME_WIDTH - 1); -- Center volume position (512 for 10-bit) CONSTANT VOL_MID : INTEGER := 2 ** (VOLUME_WIDTH - 1); -- Center volume position (512 for 10-bit)
CONSTANT DEAD_ZONE : INTEGER := (2 ** VOLUME_STEP_2) / 2; -- Dead zone around center (32 for step size 64) CONSTANT DEAD_ZONE : INTEGER := (2 ** VOLUME_STEP_2) / 2; -- Dead zone around center (32 for step size 64)
@@ -58,7 +58,7 @@ BEGIN
-- Volume to exponent conversion process -- Volume to exponent conversion process
-- Converts joystick y-axis position to bit-shift amount for exponential volume scaling -- Converts joystick y-axis position to bit-shift amount for exponential volume scaling
PROCESS (aclk) VOLUME_CALC : PROCESS (aclk)
BEGIN BEGIN
IF rising_edge(aclk) THEN IF rising_edge(aclk) THEN
@@ -78,6 +78,7 @@ BEGIN
-- volume = 0-479: Negative exponent (attenuation, right shift) -- volume = 0-479: Negative exponent (attenuation, right shift)
-- volume = 480-543: Zero exponent (unity gain, dead zone) -- volume = 480-543: Zero exponent (unity gain, dead zone)
-- volume = 544-1023: Positive exponent (amplification, left shift) -- volume = 544-1023: Positive exponent (amplification, left shift)
volume_exp_mult <= to_integer( volume_exp_mult <= to_integer(
shift_right( shift_right(
signed('0' & volume) - to_signed(VOL_MID - DEAD_ZONE, volume'length + 1), signed('0' & volume) - to_signed(VOL_MID - DEAD_ZONE, volume'length + 1),
@@ -89,11 +90,11 @@ BEGIN
END IF; END IF;
END PROCESS; END PROCESS VOLUME_CALC;
-- AXI4-Stream data processing -- AXI4-Stream data processing
-- Applies exponential volume scaling using bit-shifting multiplication -- Applies exponential volume scaling using bit-shifting multiplication
PROCESS (aclk) AXIS : PROCESS (aclk)
BEGIN BEGIN
IF rising_edge(aclk) THEN IF rising_edge(aclk) THEN
@@ -155,7 +156,7 @@ BEGIN
END IF; END IF;
END PROCESS; END PROCESS AXIS;
-- Example scaling factors (VOLUME_STEP_2 = 6, 64 values per step): -- Example scaling factors (VOLUME_STEP_2 = 6, 64 values per step):
-- volume_exp_mult = -3: Divide by 8 (>>3) -- volume_exp_mult = -3: Divide by 8 (>>3)

View File

@@ -20,14 +20,14 @@ ENTITY volume_saturator IS
aresetn : IN STD_LOGIC; -- Active-low asynchronous reset aresetn : IN STD_LOGIC; -- Active-low asynchronous reset
-- AXI4-Stream Slave Interface (Extended width input from multiplier) -- AXI4-Stream Slave Interface (Extended width input from multiplier)
s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal
s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Wide input data from multiplier s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Wide input data from multiplier
s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right)
s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data
-- AXI4-Stream Master Interface (Original width output for audio) -- AXI4-Stream Master Interface (Original width output for audio)
m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal
m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Saturated audio sample output m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Saturated audio sample output
m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough
m_axis_tready : IN STD_LOGIC -- Downstream ready signal m_axis_tready : IN STD_LOGIC -- Downstream ready signal
); );
@@ -82,12 +82,10 @@ BEGIN
IF signed(s_axis_tdata) > signed(HIGHER_BOUND_VEC) THEN IF signed(s_axis_tdata) > signed(HIGHER_BOUND_VEC) THEN
-- Positive overflow: Clip to maximum positive value -- Positive overflow: Clip to maximum positive value
-- This prevents "wraparound" distortion from mathematical overflow
m_axis_tdata <= HIGHER_BOUND_VEC; m_axis_tdata <= HIGHER_BOUND_VEC;
ELSIF signed(s_axis_tdata) < signed(LOWER_BOUND_VEC) THEN ELSIF signed(s_axis_tdata) < signed(LOWER_BOUND_VEC) THEN
-- Negative overflow: Clip to maximum negative value -- Negative overflow: Clip to maximum negative value
-- This prevents "wraparound" distortion from mathematical underflow
m_axis_tdata <= LOWER_BOUND_VEC; m_axis_tdata <= LOWER_BOUND_VEC;
ELSE ELSE
@@ -109,11 +107,4 @@ BEGIN
END PROCESS; END PROCESS;
-- Saturation Purpose and Benefits:
-- 1. Prevents audio distortion from mathematical overflow
-- 2. Maintains audio dynamic range within valid bit representation
-- 3. Reduces wide multiplication results back to standard audio format
-- 4. Provides "soft limiting" behavior for volume control
-- 5. Ensures compatibility with downstream audio processing blocks
END Behavioral; END Behavioral;