Wiki

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
resources:tools-software:sharc-audio-module:baremetal:class-d-2-1-amp [11 Sep 2018 01:56] Dan Ledgerresources:tools-software:sharc-audio-module:baremetal:class-d-2-1-amp [26 Feb 2019 20:03] (current) Chad Wentworth
Line 1: Line 1:
 +====== Tutorial: Building a 2.1 Amplifier with the Class-D Module ======
  
-==== Generating Digital Filter Coefficients ====+The Class D Fin contains two stereo class D amplifiers providing four channels of output.  In this tutorial, we will use the Class D board to implement a 2.1 or 2.2 audio amplifier.  This will include 2 channels of standard audio and one channel for a subwoofer (LFE).
  
-To generate our digital filter coefficients for the low-pass filter for our subwoofer channel, we can use Python!  The scipy module contains a number of very useful Digital Signal Processing functions including those needed to create digital filters.+The SSM3582 has an option to combine a two channels into a single channel with more power.  This requires some modifications to the configuration file and the Class D amp board.  For this tutorial, we'll use one of the stereo channels as our sub channel.  However, should you need even more power, the option is there to combine two channels Refer to the SSM3582 datasheet for more information
  
-Also, if you don't have Python installed, you can use an online interpreter such as this one: https://www.onlinegdb.com/online_python_interpreter.  Paste the Python script below into the online interpreter and click the **Run** button.  The script will generate a little clip of C code with the array declarations for our filter coefficients.+We will send the incoming stereo audio from the 1/8" jacks to the first SSM3582 on the Class D board.  We'll pass this audio along unaffected as our stereo channels.  We'll then mix our incoming left and right channels together, run them through a low-pass filter, and send this to the second SSM3582 on the class board.  This will be our sub channel.
  
-<code python> +Connect a set of standard speakers to the speaker terminals for the first stereo pair on the Class D board, and connect a sub-woofer to either of the speaker terminals for the second stereo pair on the Class D board.
-from scipy import signal +
-import numpy as np +
-from pprint import *+
  
-fs = 48000.+Connect your Class D amp board via the A2B cable to the SHARC Audio Module The SLAVE port of the SHARC Audio Module should be connected to the MASTER port of the Class D amp board.
-nyq = 0.5*fs+
  
-# Cutoff frequency  +Configure the baremetal framework to use A2B and select the SAM->Class D tutorial.
-cutoff = 300 +
-filter_order = 8+
  
-# Genearte filter coefficients +<code c> 
-b, a = signal.butter(filter_order, cutoff/nyq)+#define ENABLE_A2B                                         TRUE
  
-Flip order of A coefficients and drop the first normalized 1.0 coefficient +#if (ENABLE_A2B
-a = np.flipud(a+/** 
-a = np.delete(a8)+ * If A2B is enabled, select the role that this SHARC Audio Module board 
 + * will play (TRUE = master nodeFALSE = slave node) 
 + */ 
 +    #define A2B_ROLE_MASTER                                TRUE
  
-# Generate C code 
-print("float pm lowpass_a_coeffs["+str(filter_order)+"] = {") 
-indx = 0 
-for coeff in a: 
-    line = "\t "+str(coeff)  
-    if indx < filter_order - 1: 
-        line += "," 
-    print(line) 
-    indx += 1 
-print("};") 
-print() 
-print("float pm lowpass_b_coeffs["+str(filter_order+1)+"] = {") 
-indx = 0 
-for coeff in b: 
-    line = "\t "+str(coeff)  
-    if indx < filter_order: 
-        line += "," 
-    print(line) 
-    indx += 1 
-print("};") 
-print() 
-print("float lowpass_state[9] = {0};") 
-</code> 
  
 +/**
 + * If this SHARC Audio Module board is a master, select an A2B topology
 + 
 + * Note that these topologies are created in SigmaStudio and stored
 + * within drivers/bm_a2b_driver/a2b_topologies. See documentation for a
 + * full description of these configurations.
 + * NOTE: SET ONLY ONE TO TRUE
 + */
 +    #if (A2B_ROLE_MASTER)
 +        #define A2B_TOPOLOGY_TDM8_SAM_to_SAM_2up_2down                       FALSE
 +        #define A2B_TOPOLOGY_TDM8_SAM_to_SAM_to_SAM_4up_4down                FALSE
 +        #define A2B_TOPOLOGY_TDM8_SAM_to_CLASSD_4down                        TRUE
  
 +        // Add your own pre-processor variables for custom A2B topologies here
  
-==== Implementing the Digital Filter ====+    #endif  // A2B_ROLE_MASTER
  
-CCES also comes with a set of libraries to perform efficient DSP processing on the SHARC processor.+#endif  // ENABLE_A2B 
 +</code>
  
-For the IIR we'll be implementing, we have two options.  We can either use the software library, or we can use the IIR hardware accelerator on the ADSP-SC589 processing.+==== Setting up our Biquad filters ==== 
 +We'll use a fourth order low-pass IIR filter with a cutoff frequency of 100Hz to remove the higher frequencies from our sub channel The easiest way to do this is to cascade two 2nd order identical biquad filters.  
  
-We'll start by using the software library since we have plenty of MIPS and IIR filters are small and efficient.+First, we'll to declare two instances of BIQUAD_FILTER and allocate some pm memory for our coefficients at the top of callback_audio_processing.cpp.
  
-The filters library in CCES includes a function called iir() that we'll be using.  If you search for iir in Help->Searchyou can find documentation for this function.+<code c> 
 +BIQUAD_FILTER lpf_stage1lpf_stage2; 
 +float pm coeffs_stage1[6], coeffs_stage2[6]; 
 +</code>
  
-Just like in the other tutorials, we'll be working entirely in callback_audio_processing.cpp on SHARC core 1. +Next, we'll need to initialize these instances in ''void processaudio_setup(void)'' like so:
- +
-At the top of this file, we'll include filter.h.  Note that filter.h includes block-based or vector-based filtering libraries while filters.h (pluralincludes sample-based filtering libraries.  We'll use the vector based libraries since they're a bit more efficient and our framework is already set up for processing blocks of audio.+
  
 <code c> <code c>
-#include <filter.h>+    filter_setup(&lpf_stage1, 
 +                BIQUAD_TYPE_LPF, 
 +                BIQUAD_TRANS_MED, 
 + coeffs_stage1, 
 +                100.0, 
 +                1.0, 
 +                1.0, 
 +                AUDIO_SAMPLE_RATE); 
 +    filter_setup(&lpf_stage2, 
 +                BIQUAD_TYPE_LPF, 
 +                BIQUAD_TRANS_MED, 
 + coeffs_stage2, 
 +                100.0, 
 +                1.0, 
 +                1.0, 
 +                AUDIO_SAMPLE_RATE);
 </code> </code>
  
-Above ''processaudio_callback()'', we'll add the code snippet that our Python script generated.  This will declare both our filter coefficients as well as a state line that will be used by the iir() library function.+==== Processing Audio and Sending to Class D Board via A2B  ====
  
-The script generates code that looks like this:+Finally, in ''void processaudio_callback(void)'', we're going to filter our audio and route the audio to the Class D board over the A2B bus.
  
-<code C+<code c
-float pm lowpass_a_coeffs[8]={ +void processaudio_callback(void) { 
-    0.8176608028570787, +    float filter_mixed[AUDIO_BLOCK_SIZE];
-    -6.705872978425353, +
-    24.06321770206317, +
-    -49.346069358244485, +
-    63.251430120196574, +
-    -51.89283337342353, +
-    26.611177558819215, +
-    -7.798710473837536 };+
          
-float pm lowpass_b_coeffs[9]={ +    // First we'll mix the L and R channels together  
-    1.9997340480065266e-14+    mix_2x1(audiochannel_0_left_inaudiochannel_0_right_in, filter_mixed); 
-    1.5997872384052218e-13, +     
-    5.599255334418276e-13+    // Nextwe'll apply the filters to this data in place 
-    1.1198510668836553e-12+    filter_read(&lpf_stage1filter_mixed, filter_mixed, AUDIO_BLOCK_SIZE); 
-    1.3998138336045703e-12+    filter_read(&lpf_stage2filter_mixed, filter_mixed, AUDIO_BLOCK_SIZE); 
-    1.1198510668836565e-12, +     
-    5.599255334418276e-13+    // Finallywe'll copy our input buffers to the first two A2B channels, and our filtered data to our second two A2B channels. 
-    1.5997872384052218e-13, +     
-    1.9997340480065266e-14 +    // Original stereo audio to our stereo speakers 
-}+    copy_buffer(audiochannel_0_left_in, audiochannel_a2b_0_left_out, AUDIO_BLOCK_SIZE)
- +    copy_buffer(audiochannel_0_right_in, audiochannel_a2b_0_right_out, AUDIO_BLOCK_SIZE);
-float lowpass_state[9] = {0}; +
-</code>+
  
 +    // Filtered audio to our sub speakers
 +    copy_buffer(filter_mixed, audiochannel_a2b_1_left_out, AUDIO_BLOCK_SIZE);
 +    copy_buffer(filter_mixed, audiochannel_a2b_1_right_out, AUDIO_BLOCK_SIZE);
  
 +</code>
  
 +----
 +{{navigation SHARC Audio Module#chaining-audio-elements|Chaining Audio Elements#.|Bare Metal Framework#simple-midi-synth|Simple MIDI Synthesizer}}
resources/tools-software/sharc-audio-module/baremetal/class-d-2-1-amp.txt · Last modified: 26 Feb 2019 20:03 by Chad Wentworth