-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FEATURE: Add Sample Rate Converter simple (#63)
* DEVEL: SRC up and down simple with doc- first commit * BUGFIX: change rstPol into src * BUGFIX: change rstPol and vld * DOC: MD file title name change * DOC: change link from top README.md * DOC: change logo psi_logo.png
- Loading branch information
1 parent
bbed262
commit 9c39e3d
Showing
8 changed files
with
297 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ Benoît Stef [[email protected]] | |
This library is published under [PSI HDL Library License](License.txt), which is [LGPL](LGPL2_1.txt) plus some additional exceptions to clarify the LGPL terms in the context of firmware development. | ||
|
||
## Detailed Documentation | ||
See [Documentation](doc/psi_common_index.md) | ||
See [Documentation](doc/README.md) | ||
|
||
## Changelog | ||
See [Changelog](Changelog.md) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<img align="right" src="../psi_logo.png"> | ||
|
||
*** | ||
|
||
[**component list**](../README.md) | ||
|
||
# psi_common_sample_rate_converter | ||
- VHDL source: [psi_common_sample_rate_converter.vhd](../../hdl/psi_common_sample_rate_converter.vhd) | ||
- Testbench source: [psi_common_sample_rate_converter_tb.vhd](../../testbench/psi_common_sample_rate_converter_tb/psi_common_sample_rate_converter_tb.vhd) | ||
|
||
### Description | ||
|
||
This block is converting the valid input strobe signal to a desired rate without any filter, the same block be mean of generic can produce over sampling signal output | ||
or reduce sampling rate. For downsampling a pre filter is recommended and opposite for up sampling mode a post filter to smooth or interpolate is also advised. | ||
|
||
<p align="center"><img src="psi_common_sample_rate_converter.png"></p> | ||
|
||
|
||
### Generics | ||
| Name | type | Description | | ||
|:--------------------|:----------|:----------------------------------------------------| | ||
| RATE_g | integer | Sampling rate factor for up/down sampling | | ||
| MODE_g | real | "DOWN" => downsampling, "UP" => upsampling | | ||
| length_g | positive | data input length in bit | | ||
| CLK_TO_VALID_RATIO_g| positive | Ratio between clock frequency and vld input frequency| | ||
| rst_pol_g | std_logic | polarity reset | | ||
|
||
### Interfaces | ||
| Name | In/Out | Length | Description | | ||
|:--------|:---------|:--------------------|:----------------| | ||
| clk_i | i | 1 | clock | | ||
| rst_i | i | 1 | reset | | ||
| dat_i | i | length_g | input data | | ||
| vld_i | i | 1 | valid in | | ||
| dat_o | o | length_g | data output | | ||
| vld_o | o | 1 | valid output | | ||
|
||
|
||
[**component list**](../README.md) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
------------------------------------------------------------------------------ | ||
-- Copyright (c) 2024 by Paul Scherrer Institute, Switzerland | ||
-- All rights reserved. | ||
-- Authors: Benoit Stef | ||
------------------------------------------------------------------------------ | ||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
-- @formatter:off | ||
entity psi_common_sample_rate_converter is | ||
generic(rate_g : integer := 2; -- Sampling rate factor for up/down sampling | ||
mode_g : string := "DOWN"; -- "DOWN" => downsampling, "UP" => upsampling | ||
length_g : natural := 16; -- nb of bit | ||
clk_to_vld_ratio_g : integer := 10; -- Ratio between clock frequency and vld input frequency | ||
rst_pol_g : std_logic := '1'); | ||
port( clk_i : in std_logic; -- Clock | ||
rst_i : in std_logic; -- Synchronous rst | ||
vld_i : in std_logic; -- Indicates when dat_i is vld | ||
dat_i : in std_logic_vector(length_g - 1 downto 0); -- Assuming 16-bit data in | ||
dat_o : out std_logic_vector(length_g - 1 downto 0); -- Data output align with vld out | ||
vld_o : out std_logic); -- Indicates when dat_o is vld | ||
end entity; | ||
-- @formatter:on | ||
architecture rtl of psi_common_sample_rate_converter is | ||
signal sample_count_s : integer := 0; | ||
signal dat_s : std_logic_vector(length_g - 1 downto 0); | ||
signal vld_s : std_logic := '0'; | ||
signal sample_s : std_logic_vector(length_g - 1 downto 0); | ||
signal vld_out_count_s : integer := 0; | ||
signal vdl_dff_s : std_logic := '0'; | ||
begin | ||
|
||
proc : process(clk_i) | ||
begin | ||
if rising_edge(clk_i) then | ||
if rst_i = rst_pol_g then | ||
-- Synchronous reset: reset everything on the rising edge of clk_i | ||
sample_count_s <= 0; | ||
dat_s <= (others => '0'); | ||
vld_s <= '0'; | ||
sample_s <= (others => '0'); | ||
vdl_dff_s <= '0'; | ||
else | ||
if mode_g = "DOWN" then | ||
if vld_i = '1' then | ||
-- Downsampling logic | ||
if sample_count_s = (rate_g - 1) then | ||
dat_s <= dat_i; | ||
vld_s <= '1'; | ||
sample_count_s <= 0; | ||
else | ||
vld_s <= '0'; | ||
sample_count_s <= sample_count_s + 1; | ||
end if; | ||
else | ||
-- No valid input, no valid output | ||
vld_s <= '0'; | ||
end if; | ||
|
||
elsif mode_g = "UP" then | ||
-- Check for valid input transition | ||
if clk_to_vld_ratio_g = rate_g then | ||
dat_s <= dat_i; | ||
vld_s <= '1'; | ||
else | ||
if vld_i = '1' and vdl_dff_s = '0' then | ||
-- Store the current input sample and initialize counters | ||
sample_s <= dat_i; | ||
vld_out_count_s <= clk_to_vld_ratio_g / rate_g; | ||
end if; | ||
|
||
vdl_dff_s <= vld_i; | ||
if vld_out_count_s > 0 then | ||
-- Assert valid output | ||
dat_s <= sample_s; | ||
vld_s <= '0'; | ||
vld_out_count_s <= vld_out_count_s - 1; | ||
elsif vld_out_count_s = 0 then | ||
vld_out_count_s <= clk_to_vld_ratio_g / rate_g; | ||
dat_s <= sample_s; | ||
vld_s <= '1'; | ||
end if; | ||
end if; | ||
end if; | ||
|
||
end if; | ||
end if; | ||
end process; | ||
|
||
dat_o <= dat_s; | ||
vld_o <= vld_s; | ||
|
||
end architecture; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
160 changes: 160 additions & 0 deletions
160
testbench/psi_common_sample_rate_converter_tb/psi_common_sample_rate_converter_tb.vhd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
library IEEE; | ||
use IEEE.STD_LOGIC_1164.ALL; | ||
use IEEE.NUMERIC_STD.ALL; | ||
use IEEE.MATH_REAL.ALL; | ||
|
||
entity psi_common_sample_rate_converter_tb is | ||
end entity psi_common_sample_rate_converter_tb; | ||
|
||
architecture tb of psi_common_sample_rate_converter_tb is | ||
|
||
-- Constants | ||
constant CLK_PERIOD_c : time := 4 ns; -- 250 MHz clock period | ||
constant SAMPLE_RATE_c : real := 250.0e6; -- 250 MHz sample rate | ||
constant SIGNAL_FREQ_c : real := 1.0e6; -- 1 MHz sine wave frequency | ||
constant DOWNSAMPLE_RATE_c : integer := 512; -- Downsampling rate | ||
constant UP_SAMPLING_RATE_c : integer := 8; | ||
constant NUM_INPUT_SAMPLES_c : integer := 10000; -- Number of input samples | ||
constant LENGTH_c : integer := 16; -- slv size | ||
-- Testbench signals | ||
signal clk_i : std_logic := '0'; | ||
signal rst_i : std_logic := '0'; | ||
signal vld_i : std_logic := '0'; | ||
signal dat_i : std_logic_vector(LENGTH_c - 1 downto 0) := (others => '0'); | ||
signal dat_o : std_logic_vector(LENGTH_c - 1 downto 0) := (others => 'L'); | ||
signal vld_o : std_logic := 'L'; | ||
|
||
-- Variables for sine wave generation and self-test | ||
signal sine_wave : real := 0.0; | ||
signal sample_count : integer := 0; | ||
signal valid_count : integer := 0; -- To count valid input samples | ||
signal validup_count : integer := 0; | ||
signal expected_count : integer := 0; | ||
signal count_ok : boolean := true; | ||
signal countup_ok : boolean := true; | ||
signal datup_o : std_logic_vector(LENGTH_c - 1 downto 0); | ||
signal vldup_o : std_logic; | ||
signal tb_run : boolean := true; | ||
begin | ||
|
||
-- Clock generation process | ||
clk_proc : process | ||
begin | ||
while tb_run loop | ||
clk_i <= '0'; | ||
wait for CLK_PERIOD_c / 2; | ||
clk_i <= '1'; | ||
wait for CLK_PERIOD_c / 2; | ||
end loop; | ||
wait; | ||
end process; | ||
|
||
-- Sine wave generation and signal application | ||
stim_proc : process | ||
variable t : real := 0.0; -- Time variable in seconds | ||
begin | ||
rst_i <= '1'; | ||
wait for 10 * CLK_PERIOD_c; | ||
rst_i <= '0'; | ||
|
||
vld_i <= '1'; | ||
wait for CLK_PERIOD_c; | ||
|
||
while sample_count < 10000 loop -- Generate 10000 samples | ||
t := real(sample_count + 1) / SAMPLE_RATE_c; | ||
sine_wave <= sin(2.0 * math_pi * SIGNAL_FREQ_c * t); | ||
dat_i <= std_logic_vector(to_signed(integer(2.0**(LENGTH_c - 1) * sine_wave), LENGTH_c)); -- 16-bit signed output | ||
wait for CLK_PERIOD_c; | ||
sample_count <= sample_count + 1; | ||
end loop; | ||
|
||
-- Finish simulation | ||
wait for 100 * CLK_PERIOD_c; | ||
tb_run <= false; | ||
report "###INFO: End of simulation"; | ||
wait; | ||
end process; | ||
|
||
-- Instantiate the SampleRateConverter | ||
dut_dw_inst : entity work.psi_common_sample_rate_converter | ||
generic map( | ||
RATE_g => DOWNSAMPLE_RATE_c, -- Downsampling rate | ||
MODE_g => "DOWN", -- Downsampling mode | ||
length_g => LENGTH_c, | ||
clk_to_vld_ratio_g => 1) | ||
port map( | ||
clk_i => clk_i, | ||
rst_i => rst_i, | ||
vld_i => vld_i, | ||
dat_i => dat_i, | ||
dat_o => dat_o, | ||
vld_o => vld_o | ||
); | ||
|
||
dut_up_inst : entity work.psi_common_sample_rate_converter | ||
generic map( | ||
RATE_g => UP_SAMPLING_RATE_c, -- UP sample rate | ||
MODE_g => "UP", --Upsampling mode | ||
length_g => LENGTH_c, | ||
clk_to_vld_ratio_g => DOWNSAMPLE_RATE_c | ||
) | ||
port map( | ||
clk_i => clk_i, | ||
rst_i => rst_i, | ||
vld_i => vld_o, | ||
dat_i => dat_o, | ||
dat_o => datup_o, | ||
vld_o => vldup_o | ||
); | ||
|
||
-- Count the number of valid input samples between valid output samples | ||
count_valid_dw_proc : process(clk_i) | ||
begin | ||
if rising_edge(clk_i) then | ||
assert count_ok report "###ERROR### :Test DW Failed: Number of valid input samples between valid outputs does not match the downsampling ratio." severity error; | ||
if rst_i = '1' then | ||
valid_count <= 0; | ||
count_ok <= true; -- Reset status | ||
elsif vld_i = '1' then | ||
valid_count <= valid_count + 1; -- Count valid input samples | ||
if vld_o = '1' then | ||
-- When a valid output is produced, check the count of valid inputs | ||
if valid_count < (DOWNSAMPLE_RATE_c - 1) or valid_count > (DOWNSAMPLE_RATE_c + 1) then | ||
count_ok <= false; -- Flag an error if the count does not match | ||
else | ||
count_ok <= true; | ||
end if; | ||
valid_count <= 0; -- Reset count for the next segment | ||
end if; | ||
end if; | ||
end if; | ||
end process; | ||
|
||
-- Count the number of valid input samples between valid output samples | ||
count_valid_up_proc : process(clk_i) | ||
begin | ||
if rising_edge(clk_i) then | ||
assert countup_ok report "###ERROR### :Test UP Failed: Number of valid input samples between valid outputs does not match the upsampling ratio." severity error; | ||
if rst_i = '1' then | ||
validup_count <= 0; | ||
-- Reset status | ||
countup_ok <= true; | ||
elsif vld_o = '1' then | ||
-- Count valid input samples | ||
validup_count <= validup_count + 1; | ||
if vldup_o = '1' then | ||
-- When a valid output is produced, check the count of valid inputs | ||
if validup_count < (UP_SAMPLING_RATE_c-1) or validup_count > (UP_SAMPLING_RATE_c+1) then | ||
-- Flag an error if the count does not match | ||
countup_ok <= false; | ||
else | ||
countup_ok <= true; | ||
end if; | ||
-- Reset count for the next segment | ||
validup_count <= 0; | ||
end if; | ||
end if; | ||
end if; | ||
end process; | ||
|
||
end architecture; |