BF706 UART DMA Terminal for Audio and FIR filter Control

This has yet to be my most complex Tutorial and I hope not the final one...I call it Audio Filter control. In fact it is many things in one. I have finally achieved UART immortality by being able to control everything from it. I can turn LED on and OFF. Set the BLINK Rate among many different rates, turn Audio ON and OFF and lastly, turn a Cross-Over filter ON or OFF. You might want to turn the LED OFF while the filter is executing or you might get weird feedback. I guess I'm not perfect, so nothing is stopping you from correcting my quickly written code that included the work of brilliant people here on the Forum. @PatrickG and @UweS to mention a few great minds...Lets move on, shall we ?!

This example can be a bit daunting, but it is really quite simple even underneath the surface. I have used Will Pirkle's excellent software called RackAFX to test my prototype whose simple parameters are passed passed in at the console. The only commands you need to know in this incarnation of the software are really: aud on / aud off /filt on / filt off.

Check out my other indepth tutorials for the other commands which are clearly obtained by typing term at the PUTTY terminal i.e.

The terminal is very self explanatory, so go ahead and experiment with the different terminal commands. The neat thing in this version is that you can simply engage a mode of the terminal that works for you by commenting or un-commenting one line at the top of the source! If you used the definition as you see below, it means you are running UART as DMA interrupt device. If you comment the line out you are only running interrupts RX and TX without DMA. The choice is yours! 

 // Comment out #define USE_UART_DMA to only engage UART in interrupt mode!
#define USE_UART_DMA

 

One you turn audio on via terminal command aud on you are on your way to play around with various instruments to feed audio into the line intput port and feed the output port to a scope, or head phones...

while the aud on or filt on is immediately typed at the PUTTY terminal console, you should see something on your scope that looks similar to either an audio signal passed in or perhaps an oscillator pulse from RackAFX.

If you engage UweS cross-over FIR filters, it can be done with filt on / filt off

I hope you found this tutorial useful. Let me know how it works out for you. As always I have attached the source code for it. If you can improve it and make it better also let me know how! I will evolve the terminal so that filter coefficients can be passed in automatically from a graphic environment. More on this later...

Cheers, 

Mario G.

Firmware Engineer

dreamsmatrix@gmail.com

Audio_Filter_Control.rar
  • Hi Mario, I have some questions about the IIR filter coding. I hope that you could give me some hints.

    1. What is the order of input data after I fetch them and put them into a circular buffer?

    i.e. If "I0=0x11800000;B0=I0;L0=3;", is it like " [I0] = x[3]; [++I0]=x[2]; [++I0]=x[1]" ?

    2. I modified the code of PatrickG to implement an IIR filter, and my goal was to make a second order bandstop IIR filter, which was used to remove a 1kHz sine wave audio(sample rate is 48kHz). But I found that my code didn't work for that. 

    My design procedures were as following:

    1) Use the FDAtool to get the coefficients or IIR filter

    2) Use the code in the attachment for BF706 EZM.  

    filter1.zip
  • The results of my code is that right channel totally deaf.

  • Here is the audio file I want to filter.

  • Hello Garven,

    you could start with BF706_Audio_Filter.zip from
    https://ez.analog.com/thread/90496
    and use the my function iir32_sos (a 32 bit biquad filter):

    inline int32_t iir32_sos(int32_t in, int32_t coeff[], int32_t mem[])
    {
        // coeff[5] = {b0, b1, b2, -a1, -a2}     /* Q2.30 format */

        int64_t temp64;
        int32_t out;

        temp64 =  (int64_t) coeff[0] * (int64_t) in;      // b[0] * x[k]
        temp64 += (int64_t) coeff[1] * (int64_t) mem[0];  // b[1] * x[k-1]
        temp64 += (int64_t) coeff[2] * (int64_t) mem[1];  // b[2] * x[k-2]
        temp64 += (int64_t) coeff[3] * (int64_t) mem[2];  // a[1] * y[k-1]
        temp64 += (int64_t) coeff[4] * (int64_t) mem[3];  // a[2] * y[k-2]

        out = (int32_t) (temp64 >> 30);         // quantization

        mem[1] = mem[0];                        // 2nd non-recursive state
        mem[0] = in;                            // 1st non-recursive state
        mem[3] = mem[2];                        // 2nd recursive state
        mem[2] = out;                           // 1st recursive state

        return out;
    }

    The function expects the coefficients to be in Q2.30 format, see
    https://en.wikipedia.org/wiki/Q_(number_format)
    https://en.wikipedia.org/wiki/Fixed-point_arithmetic
    For conversion to Q2.30 you have to multiply your coefficients by 2^30.
    The coefficients are in order b0, b1, b2, -a1, -a2. The coefficients a0 is skipped
    because it is 1 anyway (if not divide all coefficients by a0).

    In Matlab the conversion to this format is:
    b = [1 -1.9835497058195457 1] * 0.93848823149637828;    % Numerator*Gain
    a = [1 -1.8615380554997468 0.87697646299275644];        % Denominator
    coeff = round( [ b(1) b(2) b(3) -a(2) -a(3) ] * 2^30 ); % conversion to Q2.30
    fprintf(1, '%d,\n',coeff);

    You get a set of 5 coefficients in Q2.30 format
    static int32_t coeffs[5] = {
        1007694065,
        -1998811267,
        1007694065,
        1998811267,
        -941646307
    };

    static int32_t states[2][4]; // memory for IIR filter

    The filtering operation in audio_processing.cpp is:

    void audio_processing(int32_t audio_buffer[], int num_chans)
    {
        audio_buffer[0] = iir32_sos(audio_buffer[0], coeffs, states[0]);
        audio_buffer[1] = iir32_sos(audio_buffer[1], coeffs, states[1]);
    }

    Ready!

    Best Regards,
    Uwe S.

  • Oh,I love your explanation so much. I am particularly grateful to you for your timely help. I already downloaded your code and I encounter some problems when I use your method to design the IIR filter. 

    I modify the coefficients to build up a 2 stages notch filter, and the coefficients are as [1]. When I debugged the project and ran it in BF706-EZM, I found that the speaker gave out a random noise.  All the modifications are shown as [1] and [2]. I also upload the M filter, which I use to calculate the coefficients. By the way, I confirm that I use none-group-loop noise mode to test the code. 

    =============================[1]

    // Q=3 g=-20dB fs=1kHz fs=48kHz
    static int32_t notch_coeffs[5] = {
    1011500000, //
    -1992100000,
    997720000,
    -1992100000,
    -935520000
    };

    // Q=3 g=-20dB fs=3.5kHz fs=48kHz
    static int32_t secnotch_coeffs[5] = {
    891060000,
    -1561900000,
    850460000,
    -1561900000,
    667780000
    };

     

    =================================================[2]

    void audio_processing(int32_t audio_buffer[], int num_chans)
    {
    // notch filter : -20dB gain in fs=1kHz and -20dB gain in fs=3.5kHz
    audio_buffer[0] = iir32_sos(audio_buffer[0], notch_coeffs, hp_states[0]);
    audio_buffer[0] = iir32_sos(audio_buffer[0], secnotch_coeffs, hp_states[1]);

    // // notch filter : -20dB gain in fs=1kHz and -20dB gain in fs=3.5kHz
    audio_buffer[1] = iir32_sos(audio_buffer[1], notch_coeffs, lp_states[0]);
    audio_buffer[1] = iir32_sos(audio_buffer[1], secnotch_coeffs, lp_states[1]);
    }

    attachments.zip