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

enable

bool

0

waveform_type

uint8_t

8

step_height

uint16_t

16

0x04

frequency_divisor

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

../../../_images/calc_square.svg

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

../../../_images/calc_triangle.svg

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

../../../_images/calc_sawtooth.svg

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

../../../_images/wb_audio.svg

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 their audio_o outputs, resulting in a 16 bit audio_l and audio_r signal. The number is configured using the CFG_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;
}