Update:
- comments - new DELAY_CLK_CYCLES formula
This commit is contained in:
@@ -99,7 +99,7 @@ BEGIN
|
|||||||
valid_flag_stage1 <= '0'; -- No valid data
|
valid_flag_stage1 <= '0'; -- No valid data
|
||||||
last_flag_stage1 <= '0'; -- Clear channel indicator
|
last_flag_stage1 <= '0'; -- Clear channel indicator
|
||||||
ELSE
|
ELSE
|
||||||
-- Calculate LFO period based on joystick input
|
-- Calculate LFO period based on joystick y-axis input
|
||||||
-- Joystick mapping:
|
-- Joystick mapping:
|
||||||
-- 0-511: Faster than base frequency (shorter period)
|
-- 0-511: Faster than base frequency (shorter period)
|
||||||
-- 512: Base frequency (1kHz)
|
-- 512: Base frequency (1kHz)
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
LIBRARY IEEE;
|
LIBRARY IEEE;
|
||||||
USE IEEE.STD_LOGIC_1164.ALL;
|
USE IEEE.STD_LOGIC_1164.ALL;
|
||||||
|
|
||||||
-- Uncomment the following library declaration if using
|
|
||||||
-- arithmetic functions with Signed or Unsigned values
|
|
||||||
USE IEEE.NUMERIC_STD.ALL;
|
USE IEEE.NUMERIC_STD.ALL;
|
||||||
|
|
||||||
-- Entity: LFO (Low Frequency Oscillator) - Alternative Implementation
|
-- Entity: LFO_1 (Low Frequency Oscillator) - Alternative Implementation
|
||||||
-- Purpose: Applies tremolo effect to audio by modulating amplitude with a triangular wave
|
-- Purpose: Applies tremolo 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_1 IS
|
||||||
GENERIC (
|
GENERIC (
|
||||||
CHANNEL_LENGHT : INTEGER := 24; -- Bit width of audio samples (24-bit signed)
|
CHANNEL_LENGHT : INTEGER := 24; -- Bit width of audio samples (24-bit signed)
|
||||||
JOYSTICK_LENGHT : INTEGER := 10; -- Bit width of joystick input (10-bit = 0-1023 range)
|
JOYSTICK_LENGHT : INTEGER := 10; -- Bit width of joystick input (10-bit = 0-1023 range)
|
||||||
@@ -21,9 +18,9 @@ ENTITY LFO IS
|
|||||||
aclk : IN STD_LOGIC; -- Main system clock
|
aclk : IN STD_LOGIC; -- Main system clock
|
||||||
aresetn : IN STD_LOGIC; -- Active-low asynchronous reset
|
aresetn : IN STD_LOGIC; -- Active-low asynchronous reset
|
||||||
|
|
||||||
-- LFO Control inputs
|
-- LFO_1 Control inputs
|
||||||
lfo_period : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Controls LFO frequency (joystick Y-axis)
|
lfo_period : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Controls LFO_1 frequency (joystick Y-axis)
|
||||||
lfo_enable : IN STD_LOGIC; -- Enable/bypass LFO effect
|
lfo_enable : IN STD_LOGIC; -- Enable/bypass LFO_1 effect
|
||||||
|
|
||||||
-- 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
|
||||||
@@ -37,26 +34,26 @@ ENTITY LFO IS
|
|||||||
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
|
||||||
);
|
);
|
||||||
END ENTITY LFO;
|
END ENTITY LFO_1;
|
||||||
|
|
||||||
ARCHITECTURE Behavioral OF LFO IS
|
ARCHITECTURE Behavioral OF LFO_1 IS
|
||||||
|
|
||||||
-- LFO timing configuration constants
|
-- LFO_1 timing configuration constants
|
||||||
CONSTANT LFO_COUNTER_BASE_PERIOD_US : INTEGER := 1000; -- Base period: 1ms (1kHz base frequency)
|
CONSTANT LFO_1_COUNTER_BASE_PERIOD_US : INTEGER := 1000; -- Base period: 1ms (1kHz base frequency)
|
||||||
CONSTANT ADJUSTMENT_FACTOR : INTEGER := 90; -- Frequency adjustment sensitivity (clock cycles per joystick unit)
|
CONSTANT ADJUSTMENT_FACTOR : INTEGER := 90; -- Frequency adjustment sensitivity (clock cycles per joystick unit)
|
||||||
CONSTANT JSTK_CENTER_VALUE : INTEGER := 2 ** (JOYSTICK_LENGHT - 1); -- Joystick center position (512 for 10-bit)
|
CONSTANT JSTK_CENTER_VALUE : INTEGER := 2 ** (JOYSTICK_LENGHT - 1); -- Joystick center position (512 for 10-bit)
|
||||||
|
|
||||||
-- Calculate base clock cycles for 1ms period at current clock frequency
|
-- Calculate base clock cycles for 1ms period at current clock frequency
|
||||||
CONSTANT LFO_COUNTER_BASE_CLK_CYCLES : INTEGER := LFO_COUNTER_BASE_PERIOD_US * 1000 / CLK_PERIOD_NS; -- 1ms = 100,000 clk cycles
|
CONSTANT LFO_1_COUNTER_BASE_CLK_CYCLES : INTEGER := LFO_1_COUNTER_BASE_PERIOD_US * 1000 / CLK_PERIOD_NS; -- 1ms = 100,000 clk cycles
|
||||||
|
|
||||||
-- Calculate frequency range limits based on joystick range
|
-- Calculate frequency range limits based on joystick range
|
||||||
CONSTANT LFO_CLK_CYCLES_MIN : INTEGER := LFO_COUNTER_BASE_CLK_CYCLES - ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1)); -- 53,920 clk cycles (faster)
|
CONSTANT LFO_1_CLK_CYCLES_MIN : INTEGER := LFO_1_COUNTER_BASE_CLK_CYCLES - ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1)); -- 53,920 clk cycles (faster)
|
||||||
CONSTANT LFO_CLK_CYCLES_MAX : INTEGER := LFO_COUNTER_BASE_CLK_CYCLES + ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1) - 1); -- 145,990 clk cycles (slower)
|
CONSTANT LFO_1_CLK_CYCLES_MAX : INTEGER := LFO_1_COUNTER_BASE_CLK_CYCLES + ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1) - 1); -- 145,990 clk cycles (slower)
|
||||||
|
|
||||||
-- LFO timing control signals
|
-- LFO_1 timing control signals
|
||||||
SIGNAL step_clk_cycles_delta : INTEGER RANGE - 2 ** (JOYSTICK_LENGHT - 1) * ADJUSTMENT_FACTOR TO (2 ** (JOYSTICK_LENGHT - 1) - 1) * ADJUSTMENT_FACTOR := 0;
|
SIGNAL step_clk_cycles_delta : INTEGER RANGE - 2 ** (JOYSTICK_LENGHT - 1) * ADJUSTMENT_FACTOR TO (2 ** (JOYSTICK_LENGHT - 1) - 1) * ADJUSTMENT_FACTOR := 0;
|
||||||
SIGNAL step_clk_cycles : INTEGER RANGE LFO_CLK_CYCLES_MIN TO LFO_CLK_CYCLES_MAX := LFO_COUNTER_BASE_CLK_CYCLES;
|
SIGNAL step_clk_cycles : INTEGER RANGE LFO_1_CLK_CYCLES_MIN TO LFO_1_CLK_CYCLES_MAX := LFO_1_COUNTER_BASE_CLK_CYCLES;
|
||||||
SIGNAL step_counter : NATURAL RANGE 0 TO LFO_CLK_CYCLES_MAX := 0;
|
SIGNAL step_counter : NATURAL RANGE 0 TO LFO_1_CLK_CYCLES_MAX := 0;
|
||||||
|
|
||||||
-- 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
|
||||||
@@ -79,29 +76,29 @@ BEGIN
|
|||||||
-- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset
|
-- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset
|
||||||
s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn;
|
s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn;
|
||||||
|
|
||||||
-- Optimized single process for LFO timing and triangular waveform generation
|
-- Optimized single process for LFO_1 timing and triangular waveform generation
|
||||||
-- This process handles both the frequency control and wave shape generation
|
-- This process handles both the frequency control and wave shape generation
|
||||||
triangular_wave_lfo_generator : PROCESS (aclk)
|
triangular_wave_lfo_generator : PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
IF rising_edge(aclk) THEN
|
IF rising_edge(aclk) THEN
|
||||||
|
|
||||||
IF aresetn = '0' THEN
|
IF aresetn = '0' THEN
|
||||||
-- Reset LFO generator to initial state
|
-- Reset LFO_1 generator to initial state
|
||||||
step_clk_cycles <= LFO_COUNTER_BASE_CLK_CYCLES; -- Set to base frequency
|
step_clk_cycles <= LFO_1_COUNTER_BASE_CLK_CYCLES; -- Set to base frequency
|
||||||
step_counter <= 0; -- Clear timing counter
|
step_counter <= 0; -- Clear timing counter
|
||||||
tri_counter <= (OTHERS => '0'); -- Start triangular wave at zero
|
tri_counter <= (OTHERS => '0'); -- Start triangular wave at zero
|
||||||
direction_up <= '1'; -- Start counting up
|
direction_up <= '1'; -- Start counting up
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
-- Calculate LFO period based on joystick input
|
-- Calculate LFO_1 period based on joystick input
|
||||||
-- Joystick mapping:
|
-- Joystick mapping:
|
||||||
-- 0-511: Faster than base frequency (shorter period, higher frequency)
|
-- 0-511: Faster than base frequency (shorter period, higher frequency)
|
||||||
-- 512: Base frequency (1kHz)
|
-- 512: Base frequency (1kHz)
|
||||||
-- 513-1023: Slower than base frequency (longer period, lower frequency)
|
-- 513-1023: Slower than base frequency (longer period, lower 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) * ADJUSTMENT_FACTOR;
|
||||||
step_clk_cycles <= LFO_COUNTER_BASE_CLK_CYCLES - step_clk_cycles_delta;
|
step_clk_cycles <= LFO_1_COUNTER_BASE_CLK_CYCLES - step_clk_cycles_delta;
|
||||||
|
|
||||||
-- Generate triangular wave when LFO is enabled
|
-- Generate triangular wave when LFO_1 is enabled
|
||||||
IF lfo_enable = '1' THEN
|
IF lfo_enable = '1' THEN
|
||||||
|
|
||||||
-- Clock divider: Update triangular wave at calculated rate
|
-- Clock divider: Update triangular wave at calculated rate
|
||||||
@@ -140,7 +137,7 @@ BEGIN
|
|||||||
END PROCESS triangular_wave_lfo_generator;
|
END PROCESS triangular_wave_lfo_generator;
|
||||||
|
|
||||||
-- AXI4-Stream handshake logic and audio processing
|
-- AXI4-Stream handshake logic and audio processing
|
||||||
-- This process handles input/output data flow and applies the LFO modulation
|
-- This process handles input/output data flow and applies the LFO_1 modulation
|
||||||
AXIS : PROCESS (aclk)
|
AXIS : PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
IF rising_edge(aclk) THEN
|
IF rising_edge(aclk) THEN
|
||||||
@@ -183,15 +180,15 @@ 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_1 tremolo effect: multiply audio sample by triangular wave
|
||||||
-- This creates amplitude modulation (tremolo effect)
|
-- This creates amplitude modulation (tremolo 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
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
-- LFO disabled: pass audio through unchanged but maintain bit width
|
-- LFO_1 disabled: pass audio through unchanged but maintain bit width
|
||||||
-- Left shift compensates for the right shift that occurs during output
|
-- Left shift compensates for the right shift that occurs during output
|
||||||
-- This ensures unity gain when LFO is bypassed
|
-- This ensures unity gain when LFO_1 is bypassed
|
||||||
m_axis_tdata_temp <= shift_left(
|
m_axis_tdata_temp <= shift_left(
|
||||||
resize(
|
resize(
|
||||||
signed(s_axis_tdata), -- Convert input to signed
|
signed(s_axis_tdata), -- Convert input to signed
|
||||||
@@ -213,14 +210,14 @@ BEGIN
|
|||||||
|
|
||||||
END PROCESS AXIS;
|
END PROCESS AXIS;
|
||||||
|
|
||||||
-- LFO Implementation Summary:
|
-- LFO_1 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 (tremolo effect)
|
||||||
-- 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:
|
-- Tremolo Effect Characteristics:
|
||||||
-- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO)
|
-- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO_1)
|
||||||
-- - 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)
|
||||||
-- - Bypass capability: Clean audio passthrough when disabled
|
-- - Bypass capability: Clean audio passthrough when disabled
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ 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 a moving average filter but passes data unchanged.
|
||||||
-- This is useful for testing or as a baseline comparison.
|
|
||||||
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
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ BEGIN
|
|||||||
s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn;
|
s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn;
|
||||||
|
|
||||||
-- Balance calculation process
|
-- Balance calculation process
|
||||||
-- Converts balance knob position to attenuation levels for each channel
|
-- Converts joystick x-axis position to attenuation levels for each channel
|
||||||
BALANCE_CALC : PROCESS (aclk)
|
BALANCE_CALC : PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ USE IEEE.STD_LOGIC_1164.ALL;
|
|||||||
-- Sends LED color commands and receives joystick/button data
|
-- Sends LED color commands and receives joystick/button data
|
||||||
ENTITY digilent_jstk2 IS
|
ENTITY digilent_jstk2 IS
|
||||||
GENERIC (
|
GENERIC (
|
||||||
DELAY_US : INTEGER := 225; -- Delay (in microseconds) between two SPI packets
|
DELAY_US : INTEGER := 25; -- Delay (in microseconds) between two SPI packets
|
||||||
-- 25us required by SPI IP-Core doesn't work,
|
|
||||||
-- it requires another SPI clock cycle
|
|
||||||
CLKFREQ : INTEGER := 100_000_000; -- Frequency of the aclk signal (in Hz)
|
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)
|
SPI_SCLKFREQ : INTEGER := 5_000 -- Frequency of the SPI SCLK clock signal (in Hz)
|
||||||
);
|
);
|
||||||
@@ -44,9 +42,11 @@ ARCHITECTURE Behavioral OF digilent_jstk2 IS
|
|||||||
-- Command code for the SetLEDRGB command, see the JSTK2 datasheet
|
-- Command code for the SetLEDRGB command, see the JSTK2 datasheet
|
||||||
CONSTANT CMDSETLEDRGB : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"84";
|
CONSTANT CMDSETLEDRGB : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"84";
|
||||||
|
|
||||||
-- Calculate delay in clock cycles based on microsecond delay and clock frequency
|
-- Calculate delay in clock cycles: (delay_period + 1_SPI_clock_period) * clock_frequency
|
||||||
-- Important: You MUST wait between two SPI packets (see JSTK2 datasheet and SPI IP-Core README)
|
-- Uses integer arithmetic optimized to avoid truncation by performing multiplications before divisions
|
||||||
CONSTANT DELAY_CLK_CYCLES : INTEGER := DELAY_US * (CLKFREQ / 1_000_000);
|
-- Formula: ((DELAY_US * SPI_SCLKFREQ + 1_000_000) * CLKFREQ) / (SPI_SCLKFREQ * 1_000_000)
|
||||||
|
-- This ensures proper timing between SPI packets as required by JSTK2 datasheet
|
||||||
|
CONSTANT DELAY_CLK_CYCLES : INTEGER := ((DELAY_US * SPI_SCLKFREQ + 1_000_000) * CLKFREQ) / (SPI_SCLKFREQ * 1_000_000);
|
||||||
|
|
||||||
-- 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);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ BEGIN
|
|||||||
s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn;
|
s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn;
|
||||||
|
|
||||||
-- Volume to exponent conversion process
|
-- Volume to exponent conversion process
|
||||||
-- Converts joystick position to bit-shift amount for exponential volume scaling
|
-- Converts joystick y-axis position to bit-shift amount for exponential volume scaling
|
||||||
PROCESS (aclk)
|
PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
|
|||||||
@@ -115,10 +115,5 @@ BEGIN
|
|||||||
-- 3. Reduces wide multiplication results back to standard audio format
|
-- 3. Reduces wide multiplication results back to standard audio format
|
||||||
-- 4. Provides "soft limiting" behavior for volume control
|
-- 4. Provides "soft limiting" behavior for volume control
|
||||||
-- 5. Ensures compatibility with downstream audio processing blocks
|
-- 5. Ensures compatibility with downstream audio processing blocks
|
||||||
--
|
|
||||||
-- Without saturation, volume amplification could cause:
|
|
||||||
-- - Mathematical overflow leading to sign bit flips
|
|
||||||
-- - Severe audio distortion (crackling, popping sounds)
|
|
||||||
-- - Invalid audio sample values outside the representable range
|
|
||||||
|
|
||||||
END Behavioral;
|
END Behavioral;
|
||||||
Reference in New Issue
Block a user