In this lab, you will use the audio coder/decoder (CODEC) on the DE1-SoC to generate and filter noise from both an external source and an internal memory.
Sounds, such as speech and music, are signals that change over time. The amplitude of a signal determines the volume at which we hear it. The way the signal changes over time determines the type of sounds we hear. For example, an "ah" sound is represented by a waveform shown in Figure 1. The waveform is an analog signal, which can be stored in a digital form by using a relatively small number of samples that represent the analog values at certain points in time. The process of producing such digital signals is called sampling. The points in Figure 2 provide a sampled waveform. All points are spaced equally in time and they trace the original waveform.
![]() |
![]() |
The DE1-SoC is equipped with an audio CODEC capable of sampling sound from a microphone and providing it as an input to a circuit. By default, the CODEC provides 48000 samples per second (48 kHz), which is sufficient to accurately represent audible sounds (by the Nyquist-Shannon sampling theorem).
To simplify this lab, a system that can record and play back sounds on the board is provided as a "starter kit." The system comprises a Clock Generator, an Audio CODEC Interface, and an Audio/Video Configuration module (Figure 4). For this lab, we will assume that our audio will be split into two channels, left and right, that are intended to be played from multiple speakers (e.g., left and right earbuds/headphones).
The left column of signals in Figure 4 are the inputs and outputs of the system. These I/O ports supply the clock inputs and connect the Audio CODEC and Audio/Video Configuration modules to the corresponding peripheral devices on the DE1-SoC. The right column of signals connects the Audio CODEC Interface module to your circuit and allows your circuit to record sounds from a microphone and play them back via speakers.
readdata_left
and readdata_right
outputs
(i.e., 2 channels for 1 sample), but the data is only
valid when the read_ready
signal is asserted.
When you assert the read
signal, the current sample is
replaced by the next element one or more clock cycles later,
indicated by read_ready
being reasserted.
write_ready
signal.
Only when the Audio CODEC is ready for a write operation should
your circuit assert the write
signal to write a sample
from the writedata_left
and writedata_right
signals.
This operation stores a sample in a buffer inside of the Audio
CODEC Interface, which will then send the sample to the speakers at
the right time.
In this task, you will play a music file into the audio input of the DE1-SoC, which will simultaneously be played through the audio output of the device.
read
and
write
signals.
In this task, you will produce a static tone from memory. By storing the samples from a sound's waveform, you can play back those samples later to re-produce the sound. We have provided a Python script (code) which generates MIF files for a desired tone, which can then be loaded into memory. Information on how to use this Python script can be found in .
SW9=0
and your tone from memory (Task 2) when
SW9=1
.
While testing, you should switch between the tasks about halfway
through your recording.
In this task, you will learn a basic signal processing technique known as filtering. Filtering is a process of adjusting a signal (e.g., removing noise). Noise in a sound waveform is represented by small, but frequent changes to the amplitude of the signal.
A simple logic circuit that achieves the task of noise-filtering is an averaging Finite Impulse Response (FIR) filter. An averaging filter removes noise from a sound by averaging the values of adjacent samples. Conceptually, a basic FIR filter uses registers as delay blocks and computes the moving average from their outputs, as shown in Figure 5.
However, we can achieve the same result using a FIFO buffer and accumulator (i.e., a register whose input is the sum of the next incoming data value and its current stored value), as shown in Figure 6.
To compute the average of the last N samples, this circuit first divides the input sample by N. Then, the resulting value is stored in a First-In First-Out (FIFO) buffer of length N and added to the accumulator. To make sure the value in the accumulator is the average of the last N samples, the circuit subtracts the value that comes out of the FIFO, which represents the (N+1)th sample.
wire
and
logic
are, by default, unsigned data types but
we are using them for signed arithmetic:
assign divided = {{n{data[w-1]}}, data[w-1:n]};
data_out
multiplied by -1
instead of subtracting.
SW8
to select between filtered
(SW8=1
) and unfiltered (SW8=0
) audio to
output; this filtering should be able to interact with both Task 1
(SW9=0
) and Task 2 (SW9=1
).
Due by the end of Friday, submitted as a PDF on .
AUD
and I2C
signals is
unreasonable.
However, you should still include a top-level block diagram and
description.
Do NOT just include Figure 4 – we need to see/know what happens
in "Your Circuit"!Due within one week of the lab report deadline, but typically during your assigned demo slot or a scheduled office hour.
SW9
and
SW8
, with your FIR filter size N set to the "best"
length that you found.
You will need piano_noisy.mp3 uploaded.