Commit ecc3a212 authored by Friedrich Beckmann's avatar Friedrich Beckmann
Browse files

added audio interface with echo example

Based on the echo example I build an audio interface which provides
the audio interface with parallel data.
parent 0ae54564
# Pin Configuration
set_location_assignment PIN_B12 -to CLOCK_24
set_location_assignment PIN_R22 -to KEY0
set_location_assignment PIN_A3 -to I2C_SCLK
set_location_assignment PIN_B3 -to I2C_SDAT
set_location_assignment PIN_A6 -to AUD_ADCLRCK
set_location_assignment PIN_B6 -to AUD_ADCDAT
set_location_assignment PIN_A5 -to AUD_DACLRCK
set_location_assignment PIN_B5 -to AUD_DACDAT
set_location_assignment PIN_B4 -to AUD_XCK
set_location_assignment PIN_A4 -to AUD_BCLK
set_location_assignment PIN_R20 -to LEDR[0]
set_location_assignment PIN_R19 -to LEDR[1]
set_location_assignment PIN_U19 -to LEDR[2]
set_location_assignment PIN_Y19 -to LEDR[3]
set_location_assignment PIN_T18 -to LEDR[4]
set_location_assignment PIN_V19 -to LEDR[5]
set_location_assignment PIN_Y18 -to LEDR[6]
set_location_assignment PIN_U18 -to LEDR[7]
set_location_assignment PIN_R18 -to LEDR[8]
set_location_assignment PIN_R17 -to LEDR[9]
## ----------------------------------------------------------------------------
## Script : makefile
## ----------------------------------------------------------------------------
## Author : Johann Faerber, Friedrich Beckmann
## Company : University of Applied Sciences Augsburg
## ----------------------------------------------------------------------------
## Description: This makefile allows automating design flow with Quartus,
## it is based on a design directory structure described in
## ../makefile
## ----------------------------------------------------------------------------
SIM_PROJECT_NAME = de1_audio
PROJECT = $(SIM_PROJECT_NAME)
# Here the VHDL files for synthesis are defined.
include ../../sim/$(SIM_PROJECT_NAME)/makefile.sources
# Add the toplevel fpga vhdl file
SOURCE_FILES = $(SYN_SOURCE_FILES)
include ../makefile
PROJECT = de1_audio
include ./makefile.sources
# Add here the testbench file
SOURCE_FILES = $(SYN_SOURCE_FILES) \
../../src/t_$(PROJECT).vhd
include ../makefile
SYN_SOURCE_FILES = \
../../src/adcintf.vhd \
../../src/bclk.vhd \
../../src/dacintf.vhd \
../../src/fsgen.vhd \
../../src/i2c_sub.vhd \
../../src/i2c.vhd \
../../src/i2c_write.vhd \
../../src/mclk.vhd \
../../src/memory.vhd \
../../src/ringbuf.vhd \
../../src/audio.vhd \
../../src/de1_audio.vhd
--Copyright 2013 Friedrich Beckmann, Hochschule Augsburg
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- ADC (Analog to Digital Converter) Interface
-- Shifts in 16 bits and provides the data in parallel
-- When all 16 bits are shifted in, the valid_o output is set to "1" for one clock cycle
entity adcintf is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
en_i : in std_ulogic;
valid_o : out std_ulogic;
data_o : out std_ulogic_vector(15 downto 0);
start_i : in std_ulogic;
ser_dat_i : in std_ulogic);
end;
architecture rtl of adcintf is
type state_t is (idle_s, shift_s, done_s);
signal state, new_state : state_t;
signal idx : integer range 0 to 15;
signal data : unsigned(15 downto 0);
signal idx_inc : std_ulogic;
signal idx_reset : std_ulogic;
signal data_shift : std_ulogic;
begin
seq_p : process(clk_i, reset_ni)
begin
if reset_ni = '0' then
idx <= 0;
data <= (others => '0');
state <= idle_s;
elsif rising_edge(clk_i) then
if data_shift = '1' then
data <= shift_left(data,1);
data(0) <= ser_dat_i;
end if;
if idx_reset = '1' then
idx <= 0;
elsif idx_inc = '1' and idx < 15 then
idx <= idx + 1;
end if;
state <= new_state;
end if;
end process seq_p;
statem_comb_p : process(state, idx, start_i, en_i)
begin
idx_inc <= '0';
idx_reset <= '0';
new_state <= state;
data_shift <= '0';
valid_o <= '0';
case state is
when idle_s =>
if start_i = '1' and en_i = '1' then
new_state <= shift_s;
idx_reset <= '1';
end if;
when shift_s =>
if en_i = '1' then
idx_inc <= '1';
data_shift <= '1';
if idx = 15 then
new_state <= done_s;
end if;
end if;
when done_s =>
valid_o <= '1';
new_state <= idle_s;
when others =>
new_state <= idle_s;
end case;
end process statem_comb_p;
data_o <= std_ulogic_vector(data);
end; -- architecture
--Copyright 2021 Friedrich Beckmann, Hochschule Augsburg
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
entity audio is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
i2c_sclk_o : out std_ulogic;
i2c_dat_i : in std_ulogic;
i2c_dat_o : out std_ulogic;
aud_adclrck_o : out std_ulogic;
aud_adcdat_i : in std_ulogic;
aud_daclrck_o : out std_ulogic;
aud_dacdat_o : out std_ulogic;
aud_xck_o : out std_ulogic;
aud_bclk_o : out std_ulogic;
adc_data_o : out std_ulogic_vector(15 downto 0);
adc_valid_o : out std_ulogic;
dac_data_i : in std_ulogic_vector(15 downto 0);
dac_strobe_o : out std_ulogic);
end;
architecture struct of audio is
component i2c_sub is
port (
clk_i: in std_ulogic;
reset_ni: in std_ulogic;
i2c_clk_o: out std_ulogic;
i2c_dat_o: out std_ulogic;
i2c_dat_i: in std_ulogic
);
end component;
component adcintf is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
en_i : in std_ulogic;
valid_o : out std_ulogic;
data_o : out std_ulogic_vector(15 downto 0);
start_i : in std_ulogic;
ser_dat_i : in std_ulogic);
end component;
component dacintf is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
load_i : in std_ulogic;
data_i : in std_ulogic_vector(15 downto 0);
en_i : in std_ulogic;
ser_dat_o : out std_ulogic);
end component;
component bclk is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
bclk_o : out std_ulogic;
bclk_falling_edge_en_o : out std_ulogic);
end component;
component fsgen is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
bclk_falling_edge_en_i : in std_ulogic;
fs_o : out std_ulogic);
end component;
component mclk is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
mclk_o : out std_ulogic);
end component;
signal framesync : std_ulogic;
signal bclk_falling_edge_en : std_ulogic;
signal adc_valid : std_ulogic;
signal dac_data, adc_data : std_ulogic_vector(15 downto 0);
begin
i2c_sub_i0 : i2c_sub
port map (
clk_i => clk_i,
reset_ni => reset_ni,
i2c_clk_o => i2c_sclk_o,
i2c_dat_o => i2c_dat_o,
i2c_dat_i => i2c_dat_i);
mclk_i0 : mclk
port map(
clk_i => clk_i,
reset_ni => reset_ni,
mclk_o => aud_xck_o);
bclk_i0 : bclk
port map (
clk_i => clk_i,
reset_ni => reset_ni,
bclk_o => aud_bclk_o,
bclk_falling_edge_en_o => bclk_falling_edge_en);
fsgen_i0 : fsgen
port map (
clk_i => clk_i,
reset_ni => reset_ni,
bclk_falling_edge_en_i => bclk_falling_edge_en,
fs_o => framesync);
dacintf_i0 : dacintf
port map (
clk_i => clk_i,
reset_ni => reset_ni,
load_i => framesync,
data_i => dac_data_i,
en_i => bclk_falling_edge_en,
ser_dat_o => aud_dacdat_o);
adcintf_i0 : adcintf
port map (
clk_i => clk_i,
reset_ni => reset_ni,
valid_o => adc_valid_o,
data_o => adc_data_o,
start_i => framesync,
en_i => bclk_falling_edge_en,
ser_dat_i => aud_adcdat_i);
aud_daclrck_o <= framesync;
aud_adclrck_o <= framesync;
dac_strobe_o <= framesync and bclk_falling_edge_en;
end; -- architecture
--Copyright 2013 Friedrich Beckmann, Hochschule Augsburg
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Bitclock generator
entity bclk is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
bclk_o : out std_ulogic;
bclk_falling_edge_en_o : out std_ulogic);
end;
architecture rtl of bclk is
signal clk_counter : integer range 0 to 47;
signal bclk_rising_edge_en : std_ulogic;
signal bclk_falling_edge_en : std_ulogic;
begin
bclk_cnt_p : process(clk_i, reset_ni)
begin
if reset_ni = '0' then
clk_counter <= 0;
elsif rising_edge(clk_i) then
if clk_counter = 47 then
clk_counter <= 0;
else
clk_counter <= clk_counter + 1;
end if;
end if;
end process bclk_cnt_p;
edge_comb_p : process(clk_counter)
begin
bclk_rising_edge_en <= '0';
bclk_falling_edge_en <= '0';
if clk_counter = 47 then
bclk_rising_edge_en <= '1';
end if;
if clk_counter = 23 then
bclk_falling_edge_en <= '1';
end if;
end process edge_comb_p;
bclk_p : process(clk_i, reset_ni)
begin
if reset_ni = '0' then
bclk_o <= '0';
elsif rising_edge(clk_i) then
if bclk_rising_edge_en = '1' then
bclk_o <= '1';
elsif bclk_falling_edge_en = '1' then
bclk_o <= '0';
end if;
end if;
end process bclk_p;
bclk_falling_edge_en_o <= bclk_falling_edge_en;
end; -- architecture
--Copyright 2013 Friedrich Beckmann, Hochschule Augsburg
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- DAC (Digital to Analog Converter) Interface
-- Loads a word in parallel and shifts it out as serial bit stream
-- The data needs to be shifted out twice. This is required as
-- the audio interface needs stereo data.
entity dacintf is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
load_i : in std_ulogic;
data_i : in std_ulogic_vector(15 downto 0);
en_i : in std_ulogic;
ser_dat_o : out std_ulogic);
end;
architecture rtl of dacintf is
signal idx : integer range 0 to 31;
signal data : unsigned(15 downto 0);
begin
load_and_shift_p : process(clk_i, reset_ni)
begin
if reset_ni = '0' then
idx <= 0;
data <= (others => '0');
elsif rising_edge(clk_i) then
if load_i = '1' and en_i = '1' then
data <= unsigned(data_i);
idx <= 0;
elsif en_i = '1' and idx < 31 then
data <= rotate_left(data,1);
idx <= idx + 1;
end if;
end if;
end process load_and_shift_p;
ser_dat_o <= data(15);
end; -- architecture
--Copyright 2013,2021 Friedrich Beckmann, Hochschule Augsburg
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library altera;
use altera.altera_primitives_components.all;
entity de1_audio is
port (
CLOCK_24: in std_ulogic;
KEY0: in std_ulogic;
I2C_SCLK: out std_ulogic;
I2C_SDAT: inout std_logic;
AUD_ADCLRCK: out std_ulogic;
AUD_ADCDAT: in std_ulogic;
AUD_DACLRCK: out std_ulogic;
AUD_DACDAT: out std_ulogic;
AUD_XCK: out std_ulogic;
AUD_BCLK: out std_ulogic;
LEDR: out std_ulogic_vector(9 downto 0));
end;
architecture struct of de1_audio is
component audio is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
i2c_sclk_o : out std_ulogic;
i2c_dat_i : in std_ulogic;
i2c_dat_o : out std_ulogic;
aud_adclrck_o : out std_ulogic;
aud_adcdat_i : in std_ulogic;
aud_daclrck_o : out std_ulogic;
aud_dacdat_o : out std_ulogic;
aud_xck_o : out std_ulogic;
aud_bclk_o : out std_ulogic;
adc_data_o : out std_ulogic_vector(15 downto 0);
adc_valid_o : out std_ulogic;
dac_data_i : in std_ulogic_vector(15 downto 0);
dac_strobe_o : out std_ulogic);
end component;
component ringbuf is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
en_i : in std_ulogic;
data_i : in std_ulogic_vector(15 downto 0);
data_o : out std_ulogic_vector(15 downto 0));
end component;
signal clk, reset_n : std_ulogic;
signal i2c_dat_o : std_ulogic;
signal i2c_dat_i : std_ulogic;
signal adc_valid : std_ulogic;
signal dac_strobe : std_ulogic;
signal dac_data, adc_data : std_ulogic_vector(15 downto 0);
begin
reset_n <= KEY0;
clk <= CLOCK_24;
audio_i0 : audio
port map (
clk_i => clk,
reset_ni => reset_n,
i2c_sclk_o => I2C_SCLK,
i2c_dat_i => i2c_dat_i,
i2c_dat_o => i2c_dat_o,
aud_adclrck_o => AUD_ADCLRCK,
aud_adcdat_i => AUD_ADCDAT,
aud_daclrck_o => AUD_DACLRCK,
aud_dacdat_o => AUD_DACDAT,
aud_xck_o => AUD_XCK,
aud_bclk_o => AUD_BCLK,
adc_data_o => adc_data,
adc_valid_o => adc_valid,
dac_data_i => dac_data,
dac_strobe_o => dac_strobe);
ringbuf_i0 : ringbuf
port map (
clk_i => clk,
reset_ni => reset_n,
en_i => adc_valid,
data_i => adc_data,
data_o => dac_data);
LEDR(9 downto 0) <= std_ulogic_vector(abs(signed(dac_data(15 downto 6))));
-- i2c has an open-drain ouput
i2c_dat_i <= I2C_SDAT;
i2c_data_buffer_i : OPNDRN
port map (a_in => i2c_dat_o, a_out => I2C_SDAT);
end; -- architecture
--Copyright 2013 Friedrich Beckmann, Hochschule Augsburg
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Frame Sync Generator
-- The framesync is active for one bitclock cycle
entity fsgen is
port (
clk_i : in std_ulogic;
reset_ni : in std_ulogic;
bclk_falling_edge_en_i : in std_ulogic;
fs_o : out std_ulogic);
end;
architecture rtl of fsgen is
signal counter : integer range 0 to 63;
begin
fs_cnt_p : process(clk_i, reset_ni)
begin
if reset_ni = '0' then