This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320C6748 LCDK Simple FIR-Filter with audio I/O

Other Parts Discussed in Thread: TMS320C6748

Hello everybody,

I studied electrical engineering at university and have a theoretical background, but unfortunately never had practical experiences. Therefore I got a TMS320C6748 LCDK and I wanted to implement a simple FIR filter that uses the onboard input jack, filters the signal and than outputs onto the output jack. Furthermore I want to bypass the filter when pressing a push button.


At first I wanted to go through the examples and see how things are structured and initialized, but I don´t even get these examples working. I get errors while building the example projects (e.g. FFT Example) that some references are missing e.g. dsplib.h although I did install the dsplib with default settings properly.

Moreover I searched the web for a simple fir filter example without any sucess that already initializes everything on the board where I can only modify the filter algorithm.

Any help is much appreciated. Thanks :-)

Kind regards,

Robin

  • Hi Robin,

    Thanks for your post.

    For C674x device, please check the supported kernel functions for C674x DSP_LIB from the below wiki:

    http://processors.wiki.ti.com/index.php/C674x_DSPLIB#Introduction

    For fixed point computation, the C674x core is fully compatible with the C64x+ DSPLIB, kindly check the c64x+ DSP library programmer's reference as below:

    http://www.ti.com/lit/ug/sprueb8b/sprueb8b.pdf

    For downloads of c66x, c67x, c64x, c64x+ & c674x DSP LIB, kindly refer the below link:

    http://www.ti.com/tool/sprc265

    After installing c674x DSP LIB., you could see the FIR filter example .CCS project in the below specified path:

    ~\dsplib_c674x_3_2_0_1\packages\ti\dsplib\src\DSPF_sp_fir_gen\c674\DSPF_sp_fir_gen_674LE_LE_COFF\

    Kindly refer the above example.

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.

    -------------------------------------------------------------------------------------------------------

  • Hi Sivaraj,

    thank you for your prompt answer and your suggestions!

    I tried to get the suggested example working. If I want to build the project (without any modification) I get some errors that the references cannot be resolved, although I included the paths of the dsplib. If I right-click on the *.c file and choose "build selected files" everything works without errors. But as soon as I click on debug (to send to the board) I get again the errors shown in the picture.

    What am I missing? And what about the warnings? Don´t have any idea where this comes from.

    Thank you, Sir!

  • We could get the mcaspPlayBk example working. We were also able to implement a FIR filter by hand. However, if we increase the filter length (<35 taps) we´ll get audio drop-outs or random noise. I guess this could be optimized by using other parameters in the initial parameters. Even it only works for Fs=24kHz

    Please see our code snipet:


    while(1)
    {


    if(lastFullRxBuf != lastSentTxBuf)
    {

    /*
    ** Start the transmission from the link paramset. The param set
    ** 1 will be linked to param set at PAR_TX_START. So do not
    ** update paRAM set1.
    */
    parToSend = PAR_TX_START + (parOffTxToSend % NUM_PAR);
    parOffTxToSend = (parOffTxToSend + 1) % NUM_PAR;
    parToLink = PAR_TX_START + parOffTxToSend;

    lastSentTxBuf = (lastSentTxBuf + 1) % NUM_BUF;
    secondLastSentTxBuf = (secondLastSentTxBuf + 1) % NUM_BUF;



    //FIR - it works for stereo until fs=24kHz, and just for one channel until 44100Hz and filterlength< 35taps//
    int i , j;
    float SampleR, SampleL, SumR, SumL;

    int NUM_SAMPLES_PER_AUDIO_BUF_2=NUM_SAMPLES_PER_AUDIO_BUF/2;


    for(i=0;i<HLEN-1;i++) {
    SumR=0;
    SumL=0;
    for(j=0;j<HLEN;j++) {
    if(i-j<0){
    SampleR=(short )*((int *)rxBufPtr[secondLastFullRxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * ( i - j) );
    SampleL=(short )*((int *)rxBufPtr[secondLastFullRxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * ( i - j) + 1 );
    } else{
    SampleR=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * ( i - j) );
    SampleL=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * ( i - j) + 1 );
    }
    SumR=SumR+SampleR*impulseResponse[j];
    SumL=SumL+SampleL*impulseResponse[j];
    }

    *((int*)txBufPtr[lastSentTxBuf] + 2 * i) = (short) SumR;
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i + 1) = (short) SumL;
    }



    for(i=HLEN-1; i<NUM_SAMPLES_PER_AUDIO_BUF_2; i++) {
    SumR=0;
    SumL=0;
    for(j=0;j<HLEN;j++){
    SampleR=(short)*((int*)rxBufPtr[lastFullRxBuf] + 2 * (i - j));
    SumR=SumR+SampleR*impulseResponse[j];

    SampleL=(short)*((int*)rxBufPtr[lastFullRxBuf] + 2 * (i - j) + 1);
    SumL=SumL+SampleL*impulseResponse[j];
    }
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i) = (short) SumR;
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i + 1) = (short) SumL;
    }


    int i;
    float SampleR, SampleL;

    int NUM_SAMPLES_PER_AUDIO_BUF_2=NUM_SAMPLES_PER_AUDIO_BUF/2;

    for(i=-HLEN+1;i<NUM_SAMPLES_PER_AUDIO_BUF_2;i++) {
    if(i<0){
    SampleR=(short )*((int *)rxBufPtr[secondLastFullRxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * i );
    SampleL=(short )*((int *)rxBufPtr[secondLastFullRxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * i + 1 );
    } else{
    SampleR=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * i );
    SampleL=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * i + 1 );
    }
    inputBuffer[i + HLEN - 1] = (float) SampleR;
    //printf("%f \n", SampleR);
    }*/

    //DSPF_sp_fir_gen((float *)inputBuffer, impulseResponse, (float *)outputBuffer, HLEN, 1000);




    //IIR

    /*int i , j;
    float SampleR, SampleL, SumR, SumL, OutputR, OutputL;
    int NUM_SAMPLES_PER_AUDIO_BUF_2=NUM_SAMPLES_PER_AUDIO_BUF/2;

    for(i=0;i<2;i++) {
    SumR=0;
    SumL=0;
    for(j=0;j<3;j++) {
    if(i-j<0){
    SampleR=(short )*((int *)rxBufPtr[secondLastFullRxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * ( i - j) );
    SampleL=(short )*((int *)rxBufPtr[secondLastFullRxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * ( i - j) + 1 );
    OutputR=(short )*((int *)txBufPtr[secondLastSentTxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * ( i - j) );
    OutputL=(short )*((int *)txBufPtr[secondLastSentTxBuf] + NUM_SAMPLES_PER_AUDIO_BUF + 2 * ( i - j) + 1 );
    } else{
    SampleR=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * ( i - j) );
    SampleL=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * ( i - j) + 1 );
    OutputR=(short )*((int *)txBufPtr[lastSentTxBuf] + 2 * ( i - j) );
    OutputL=(short )*((int *)txBufPtr[lastSentTxBuf] + 2 * ( i - j) + 1 );
    }
    SumR=SumR + SampleR * b[j] - OutputR * a[j];
    SumL=SumL + SampleL * b[j] - OutputL * a[j];
    }
    //printf("SampleR: %f | SumR: %f\n", SampleR, SumR);
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i) = (short) SumR;
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i + 1) = (short) SumL;
    }

    for(i=2;i<NUM_SAMPLES_PER_AUDIO_BUF_2;i++) {
    SumR=0;
    SumL=0;
    for(j=0;j<3;j++) {
    SampleR=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * ( i - j) );
    SampleL=(short )*((int *)rxBufPtr[lastFullRxBuf] + 2 * ( i - j) + 1 );
    OutputR=(short )*((int *)txBufPtr[lastSentTxBuf] + 2 * ( i - j) );
    OutputL=(short )*((int *)txBufPtr[lastSentTxBuf] + 2 * ( i - j) + 1 );

    SumR=SumR + SampleR * b[j] - OutputR * a[j];
    SumL=SumL + SampleL * b[j] - OutputL * a[j];
    }
    //printf("SampleR: %f | SumR: %f\n", SampleR, SumR);
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i) = (short) SumR;
    *((int*)txBufPtr[lastSentTxBuf] + 2 * i + 1) = (short) SumL;
    }*/




    /*
    ** Send the buffer by setting the DMA params accordingly.
    ** Here the buffer to send and number of samples are passed as
    ** parameters. This is important, if only transmit section
    ** is to be used.
    */
    BufferTxDMAActivate(lastSentTxBuf, NUM_SAMPLES_PER_AUDIO_BUF,
    (unsigned short)parToSend,
    (unsigned short)parToLink);
    }
    }
    }



    We have also tried to use the dsplib functions but are kind of stuck because the lib-function expects pointers of the input samples. Since we´re getting the audio samples interleaved we must separate them first, then do the calculations and then prepare them for the output, right?

    Any help is much appreciated. Thanks!
  • Hello again,

    could anyone please help me out? Sivaraj?

    Cannot find any documentation that answers my questions :-/

    Thanks!
  • Hi,

    I think, the e2e posts below would help you better in implementing FIR filter and there are few choices recommended by Mr. Randy on the below E2E post:

    https://e2e.ti.com/support/dsp/tms320c6000_high_performance_dsps/f/112/t/83162

    Also, there is a audio sample buffer attached (8623.audio.rar) in the below E2E post:

    https://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/50708

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.

    -------------------------------------------------------------------------------------------------------

  • Dear Sivaraj,

    thank you for your advice.

    I´m not sure if I got the explanations right. Therefore I try to explain my understandings:

    We´re talking about the mcsap example. We´re getting the input samples from the A/D stored interleaved into the buffer.
    float buffer = {L(n-2),R(n-2),L(n-1),R(n-1),L(n),R(n),...};

    Am I right to separate the Left and Right audio stream into separate vectors and use a dedicated DSP-LIB function each channel?
    float Left[Size] = {L(n-2), L(n-1),L(n),...};
    float Right[Size] ={R(n-2),R(n-1),R(n),...};

    If I assume the same audio processing, I can share the filter coefficients for both DSP-LIB functions?!
    float a[3] = {1, a1, a2 };
    float b[3] = {b0, b1, b2 };

    I´ve read that the first delay elements have to be precalculated like this
    delayL[0] = b_1 x[i-1] + b_2 x[i-2] - a_1 y[i-1] - a_2 y[i-2]
    delayL[1] = b_2 x[i-1] - a_2 y[i-1]

    Then finally call twice the DSP-Lib functions
    void DSPF_sp_biquad (Left, b, a, delayL, OutL, Size);
    void DSPF_sp_biquad (Right, b, a, delayR, OutR, Size);

    and afterwards add both outputs together
    float output = {OutL(n-2), OutR(n-2), OutL(n-1), OutR(n-1), OutL(n), OutR(n),...};

    And how about cascading more biquads or other filters? Just use the former outputs OutL and OutR as intermediate vectors for inputting the next filter stage?

    Thanks so much!
  • Campus,

    If the resources pointed out above have not helped you learn how to use the LCDK, then I recommend you go to TI.com and search for "c6748 workshop" (no quotes) and look for the C6000 Embedded Workshop. There are labs and student guide available, and videos that include explanations for much of the material.

    In the labs, if I remember correctly, you will build up to a system that has audio input and audio output. There may be code used that inserts or filters out some noise, and this can be controlled by a switch.

    These are good teachers who prepared this material. You will benefit greatly if you can go through the entire workshop and move through the progressive steps to achieve the end goal of knowledge.

    Regards,
    RandyP