Audio hardware peripheral
Author: Tristan Kundrat 2025
Overview
The wishbone audio hardware module allows audio signals to be generated (audio synthesizer). The module is configured using simple registers.
The wb_audio top module consists of the following components:
wb_audio_single: Module generating one audio voice.
squarewave: Module generating a squarewave audio signal.
trianglewave: Module generating a trianglewave audio signal.
sawtoothwave: Module generating a sawtoothwave audio signal.
sinewave: Module generating a sinewave audio signal.*
counter: Configurable counter module used by all wave generating modules.
*) Hint: Sinewave generation is currently not implemented. The module was kept to have a starting point for adding new waveform types.
Interface specification
Register table
This table describes the registers and their function:
Byte Offset |
Name |
Type |
Bit Offset (in Word) |
---|---|---|---|
0x00 |
bool |
0 |
|
uint8_t |
8 |
||
uint16_t |
16 |
||
0x04 |
uint32_t |
0 |
Register description
Enable register
bool
Value |
Function |
---|---|
0 |
Disable generation of audio signal (Audio output is 0) and reset internal counter to 0 |
1 |
Enable generation of audio signal using register configuration |
Waveform type register
uint8_t
The SystemC module uses the following struct for enumerating the waveform types:
typedef enum
{
WF_SQUARE = 0,
WF_TRIANGLE,
WF_SAWTOOTH,
WF_SINE,
} e_waveform_t;
Enum value |
Integer value |
Function |
---|---|---|
WF_SQUARE |
0 |
Generate squarewave audio signal |
WF_TRIANGLE |
1 |
Generate trianglewave audio signal |
WF_SAWTOOTH |
2 |
Generate sawtoothwave audio signal |
WF_SINE |
3 |
Generate sinewave audio signal* |
*) Hint: Sinewave generation is currently not implemented. The module was kept to have a starting point for adding new waveform types.
Step height register
uint16_t
The step height is calculated differently based on the waveform type. The parameters mentioned are:
Parameter |
Mathematical symbol |
Type |
---|---|---|
Amplitude* |
\(A\) |
uint24_t |
Audio signal frequency |
\(f\) |
double |
Audio signal period length |
\(T\) |
double |
System clock frequency |
\(f_{clk}\) |
double |
System clock period length |
\(T_{clk}\) |
double |
Frequency divisor |
\(d\) |
uint32_t |
Step height |
\(s\) |
uint16_t |
*) Hint: The amplitude \(A\) is a value between 0x000000
(minimum)
and 0xFFFFFF
(maximum)
Squarewave step height
Fig. 36 Diagramm of a squarewave showing parameters for calculating the step height.
\(d = \frac{T}{T_{clk}} = \frac{f_{clk}}{f}\)
\(s = A\)
Trianglewave step height
Fig. 37 Diagramm of a trianglewave showing parameters for calculating the step height.
\(d = \frac{T}{T_{clk}} = \frac{f_{clk}}{f}\)
\(s = \frac{A \cdot 2}{d}\)
Sawtoothwave step height
Fig. 38 Diagramm of a sawtoothwave showing parameters for calculating the step height.
\(d = \frac{T}{T_{clk}} = \frac{f_{clk}}{f}\)
\(s = \frac{A}{d}\)
Sinewave step height
Sinewave generation is currently not implemented.
Frequency divisor register
uint32_t
This value is calculated using the following formula: \(d = \frac{T}{T_{clk}} = \frac{f_{clk}}{f}\)
Also see the chapter Step height register.
Modules
wb_audio
Fig. 39 Diagramm of the wb_audio
top module containing \(n\) voices.
-
SC_MODULE(m_wb_audio)
Audio module combining multiple synthesizer voices.
This module instantiates multiple
m_wb_audio_single
modules and adds theiraudio_o
outputs, resulting in a 16 bitaudio_l
andaudio_r
signal. The number is configured using theCFG_WB_AUDIO_EXP
macro, such that the number of wanted voices per channel (left/right) m = 2^(CFG_WB_AUDIO_EXP
).- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
wb_adr_i – [in] Wishbone Adress input
wb_dat_o – [out] Wishbone Data out
wb_dat_i – [in] Wishbone Data in
wb_we_i – [in] Wishbone Write-Enable in
wb_stb_i – [in] Wishbone Strobe in
wb_cyc_i – [in] Wishbone Cycle in
wb_ack_o – [out] Wishbone ACK input
wb_cti_i – [in] // Wishbone cycle type identifier (optional, for registered feedback)
wb_bte_i – [in] // Wishbone burst type extension (optional, for registered feedback)
wb_error_o – [out] // Wishbone termination w/ error (optional)
wb_rty_o – [out] // Wishbone termination w/ retry (optional)
audio_r – [out] 16 bit unsigned audio output (right channel)
audio_l – [out] 16 bit unsigned audio output (left channel)
wb_audio_single
-
SC_MODULE(m_wb_audio_single)
Wishbone Slave Module for one audio voice.
This module is the hardware-wishbone SLAVE unit for one voice of the audio synthesizer peripheral.
- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
wb_adr_i – [in] Wishbone Adress input
wb_dat_o – [out] Wishbone Data out
wb_dat_i – [in] Wishbone Data in
wb_we_i – [in] Wishbone Write-Enable in
wb_stb_i – [in] Wishbone Strobe in
wb_cyc_i – [in] Wishbone Cycle in
wb_ack_o – [out] Wishbone ACK input
wb_cti_i – [in] // Wishbone cycle type identifier (optional, for registered feedback)
wb_bte_i – [in] // Wishbone burst type extension (optional, for registered feedback)
wb_error_o – [out] // Wishbone termination w/ error (optional)
wb_rty_o – [out] // Wishbone termination w/ retry (optional)
base_offset_i – [in] base address offset, at which the modules registers can be accessed
audio_o – [out] 16 bit unsigned audio output
squarewave
-
SC_MODULE(m_squarewave)
Audio module generating a squarewave signal.
This module generates a squarewave signal with the frequency f and amplitude A. The input parameters are calculated like so (f_clk is the systems clock frequency):
frequency_divisor = f_clk / f
step_height = A- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
enable – [in] enable of the module
frequency_divisor – [in] f_clk/f
step_height – [in] amplitude
audio_signal – [out] 16 bit unsigned audio output
trianglewave
-
SC_MODULE(m_trianglewave)
Audio module generating a trianglewave signal.
This module generates a trianglewave signal with the frequency f and amplitude A. The input parameters are calculated like so (f_clk is the systems clock frequency):
frequency_divisor = f_clk / f
step_height = A * 2 / frequency_divisor- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
enable – [in] enable of the module
frequency_divisor – [in] f_clk/f
step_height – [in] amplitude * 2 / frequency_divisor
audio_signal – [out] 16 bit unsigned audio output
sawtoothwave
-
SC_MODULE(m_sawtoothwave)
Audio module generating a sawtoothwave signal.
This module generates a sawtoothwave signal with the frequency f and amplitude A. The input parameters are calculated like so (f_clk is the systems clock frequency):
frequency_divisor = f_clk / f
step_height = A / frequency_divisor- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
enable – [in] enable of the module
frequency_divisor – [in] f_clk/f
step_height – [in] amplitude / frequency_divisor
audio_signal – [out] 16 bit unsigned audio output
sinewave
-
SC_MODULE(m_sinewave)
Audio module generating a sinewave signal.
This module is an empty module, as generating a sinewave was seen as optional. It was kept here, as it serves as a starting point for adding other waveforms in the future.
- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
enable – [in] enable of the module
frequency_divisor – [in] ?
step_height – [in] ?
audio_signal – [out] 16 bit unsigned audio output
counter
-
SC_MODULE(m_counter)
Configurable counter module.
While enabled, this module counts from 0 to frequency_divisor, resets to 0 after and continues counting. This count can be accessed by the parameter count. When disabled, the count is set to 0. Every clock cycle, count is incremented by 1 (if enabled). The amplitude is reset to 0, when count is reset to 0. If enabled, every clock cycle the amplitude is recalculated as follows:
if negative_step is 0:
amplitude = amplitude + step_height
if negative_step is 1:
amplitude = amplitude - step_height- Author
Tristan Kundrat
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
enable – [in] enable of the module
frequency_divisor – [in] f_clk / f
step_height – [in] increment value per clock cycle
negative_step – [in] decrement amplitude instead of increment
amplitude – [out] current amplitude of output signal
count – [out] current count of underlying counter
Example code
These functions can be used to calculate and write values to the registers,
where CLK_FREQ_HZ is the systems clock frequency in Hz and regs
is the pointer
(address) of an audio voice v
, where
unsigned int *regs = (unsigned int *)(CFG_WB_AUDIO_ADDRESS + 0x08 * v)
:
void set_trianglewave(double frequency, unsigned int amplitude, volatile unsigned int *regs)
{
if (frequency < 0) return;
if (frequency == 0) {
regs[0] = 0;
regs[1] = 0;
return;
}
unsigned int freqdiv = (unsigned int)(CLK_FREQ_HZ / frequency);
unsigned int step_height = (unsigned int)(amplitude * 2 / freqdiv);
regs[1] = freqdiv;
regs[0] = (step_height << 16) | (WF_TRIANGLE << 8) | 1;
}
void set_squarewave(double frequency, unsigned int amplitude, volatile unsigned int *regs)
{
if (frequency < 0) return;
if (frequency == 0) {
regs[0] = 0;
regs[1] = 0;
return;
}
unsigned int freqdiv = (unsigned int)(CLK_FREQ_HZ / frequency);
regs[1] = freqdiv;
regs[0] = (amplitude << 16) | (WF_SQUARE << 8) | 1;
}
void set_sawtoothwave(double frequency, unsigned int amplitude, volatile unsigned int *regs)
{
if (frequency < 0) return;
if (frequency == 0) {
regs[0] = 0;
regs[1] = 0;
return;
}
unsigned int freqdiv = (unsigned int)(CLK_FREQ_HZ / frequency);
unsigned int step_height = (unsigned int)(amplitude / freqdiv);
regs[1] = freqdiv;
regs[0] = (step_height << 16) | (WF_SAWTOOTH << 8) | 1;
}
The following code is an example playing a 200 Hz Squarewave, 500 Hz Trianglewave and 1500 Hz Sawtoothwave at full amplitude, then turning off:
#define VOICE(NUM) ((unsigned int *)(CFG_WB_AUDIO_ADDRESS + 0x08 * NUM))
#define MAX_AMPLITUDE 0xFFFFFFU
// set_...wave functions here
int main(void)
{
set_squarewave(200.0, MAX_AMPLITUDE, VOICE(0));
set_trianglewave(500.0, MAX_AMPLITUDE, VOICE(1));
set_sawtoothwave(1500.0, MAX_AMPLITUDE, VOICE(2));
for (int i = 0; i < 100000; i++);
// When disabling, any set_ method can be used with frequency 0
set_squarewave(0.0, 0, VOICE(0));
set_squarewave(0.0, 0, VOICE(1));
set_squarewave(0.0, 0, VOICE(2));
return 0;
}