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.

PSP audio driver messing with buffers? BUG or it's me?

Hi, working on a L137 from several weeks. Currently I'm using only the C6747 and not planning to use the ARM core.

After working a bit with my project I discovered a huge problem, that could be either a serious bug of the audio driver or a problem of mine in using it.

The driver I'm using is the example you find in psp013001\packages\ti\pspiom\examples\evmOMAPL137\audio called audioSample. I'm using DSP/BIOS 5.41 (bios_5_41_03_17)

The driver works frame-by-frame, you obtain a frame, it is a 16-bit signed integer Left-Right interleaved AFAIK. You unpack it and use it however you want. Then issue back a frame with the output.

THE PROBLEM:

sometimes (let's say 60% of the times) two consecutive audio frames are scrambled. What I mean:

- I take the frame and store it in a temp array, then use it.

- Next cycle I have a new frame and the old one I stored in the temp array. I plot them side by side and see that 60% of the times they are not correctly joined, there's a step. 40% of the times they join correctly, i.e. putting them side by side, it looks clear they come from the same signal.

So you would say: maybe the driver is missing some samples, but that's not the case, because MAGICALLY: if you plot the newest first and the oldest after, they join perfectly! So the driver gives me two consecutive buffers that are reverse-ordered!

What's more: the AUDIO WORKS flawlessly. I send a sinewave to the input and I record the same exact sine on output. So why the audio works fine if the data should not be fine? Normally I input some signal and throw it out without processing it, just copying the buffers but I also tried to use a Lo-pass filter and it worked fine.

Maybe it's the debugger that's not working ok? But I'm quite sure it is working fine because FIR filters have their output corrupted by the fact from a frame to the other, the previous states are not correctly joining the new ones. This problem affects all the processing and I can see bad results at the end.

I'll post you two images to make it clearer:

 

The first image shows two buffers concatenated. The green line shows where the step is. The second image show the concatenated version of the two buffers in reverse order: they join perfectly (green line).

Just to make it clear, the signal fed into the DSP is the one below (played in loop), so every smaller sine follows bigger  sine.

It is shaped this way so I can debug better.

Some pseudocode used for the debugging:

SIO_reclaim(rcv,...) // reclaim a buffer

buffer_unpack(rcv, f_in_L, f_in_R); //unpack the buffer into L and R channels f_in_L and f_in_R

my_processing(f_in_L, f_in_R, f_out_L, f_out_R);

storing_the_buffer(f_in_L, temp_f_in_L);

SIO_issue(...); // issue the processed buffer

I obtain the plots putting a breakpoint between buffer unpacking and before storing_the_buffer. This way I have the old buffer temp_f_in_L from the previous cycle of the audio task and I have the new frame f_in_L to be used for this cycle of the processing.

Some of you may ask me if my unpacking procedure is faulty: it is not. The same problem happens on the original rcv buffer (you just have to plot it using the correct options, displaying one 16-bit int data every 2).

Maybe I should start reading the whole code of the driver, but I have no time, I have to focus on the algorithm.

Just a question: is there a sample-by-sample driver for C6747 that is ready to use? I have a tutorial book from Chassaing on coding for TI processors but it's all sample-by-sample.

I hope I've been clear, ask me further questions if you wish.

  • Hi Leonardo,

    Can you send me your audioSample_io.c file with the function you used to separate the left and write channels so I can try to reporduce and understand the issue?

    There is another example using McASPinside the PSP:

    \pspdrivers_01_30_01\packages\ti\pspiom\examples\evmOMAPL137\mcaspDit\build\ccs3\mcaspDitSample.pjt

    but not sure if you want to look.

  • Hi Mariana,

    Below I post the code for audioSample_io.c, the routine for separating the channels is contained on bottom. I commented some lines for you, specifically leaving out the algorithm and just bypassing the processing by a copy of the input frames (f_in_L, f_in_R) on output (f_out_L, f_out_R). I also added the FRAMELEN define which was contained in an extern file.

    In the body of Audio_echo_Task you find two blocks code used for displaying the frames (commented with /* DEBUG and END DEBUG */).

    I hope this will compile on your system at once.

    In the meanwhile I'll try out the driver you suggested.

    Thanks and regards

     

    Leonardo

     


    /*
     * audioSample_io.c
     *
     * This file contains the test / demo code to demonstrate the Audio component 
     * driver functionality on DSP/BIOS 5.
     *
     *
    */


    /** \file     audioSample_io.c
     *
     *  \brief    sample application for demostration of audio playing
     *
     *  This file contains the implementation of the sample appliation for the
     *  demostartion of audio playing through the audio interface layer.
     *
     *             (C) Copyright 2008, Texas Instruments, Inc
     */

    /* ========================================================================== */
    /*                            INCLUDE FILES                                   */
    /* ========================================================================== */

    #include "stdio.h"
    #include "std.h"
    #include "sio.h"
    #include "iom.h"
    #include "mem.h"
    #include "log.h"
    #include "clk.h" // for benchmarking
    #include "ti/pspiom/platforms/evmOMAPL137/audio/Audio.h"
    #include "ti/pspiom/mcasp/Mcasp.h"
    #include "ti/sdo/edma3/drv/edma3_drv.h"

    //#include "algoritmo.h"
    //#include "globalMacros.h"
    #include "dsplib\include\DSPF_sp_blk_move.h"

    /* ========================================================================== */
    /*                          IMPORTED VARIABLES                                */
    /* ========================================================================== */

    extern Int edma3init();
    extern EDMA3_DRV_Handle hEdma;
    extern LOG_Obj trace;

    /* ========================================================================== */
    /*                          MACRO DEFINITIONS                                 */
    /* ========================================================================== */

    /*
     * Buffers placed in external memory are aligned on a 128 bytes boundary.
     * In addition, the buffer should be of a size multiple of 128 bytes for
     * the cache work optimally on the C6x.
     */

    #define BUFALIGN                128 /* alignment of buffer for use of L2 cache */
    #define FRAMELEN 256 // framelength

    /* my In/Out float BUFFERS */
    static float f_in_L[FRAMELEN], f_in_R[FRAMELEN], f_out_L[FRAMELEN], f_out_R[FRAMELEN];
    #pragma DATA_ALIGN(f_in_L,8); //double word alignment
    #pragma DATA_ALIGN(f_in_R,8);
    #pragma DATA_ALIGN(f_out_L,8);
    #pragma DATA_ALIGN(f_out_R,8);

    /** Number of serializers configured for record */
    #define RX_NUM_SERIALIZER       (1u)
    #define TX_NUM_SERIALIZER       (1u)

    #define BUFSIZE                 (FRAMELEN * sizeof(Ptr))

    #define NUM_BUFS                4   /* Num Bufs to be issued and reclaimed */

    /* inStream and outStream are stream handles created in main */
    static SIO_Handle inStream, outStream;

    /* ========================================================================== */
    /*                          FUNCTION PROTOTYPES                               */
    /* ========================================================================== */
    static Void createStreams();
    static Void audioPrime(); // prime audio streams
    static Void algoPrime();  // prime FIR coefficients and so on
    void get_LR_itof(const short * restrict in, float * restrict out_L, float * restrict out_R, int n); // unpack input rcv vector into [L][R] float vectors
    void put_LR_ftoi(const float * restrict in_L, const float * restrict in_R, short * restrict out, int n); // pack output [L][R] vectors for output into xmt

    /* ========================================================================== */

    Ptr buf[NUM_BUFS * 2];

    Mcasp_HwSetupData mcaspRcvSetup = {
            /* .rmask    = */ 0xFFFFFFFF, /* All the data bits are to be used     */
            /* .rfmt     = */ 0x000080F0, /*
                                           * 0 bit delay from framsync
                                           * MSB first
                                           * No extra bit padding
                                           * Padding bit (ignore)
                                           * slot Size is 32
                                           * Reads from DMA port
                                           * NO rotation
                                           */
            /* .afsrctl  = */ 0x00000000, /* burst mode,
                                           * Frame sync is one bit
                                           * Rising edge is start of frame
                                           * externally generated frame sync
                                           */
            /* .rtdm     = */ 0x00000001, /* slot 1 is active (DSP)               */
            /* .rintctl  = */ 0x00000003, /* sync error and overrun error         */
            /* .rstat    = */ 0x000001FF, /* reset any existing status bits       */
            /* .revtctl  = */ 0x00000000, /* DMA request is enabled or disabled   */
            {
                 /* .aclkrctl  = */ 0x00000000,
                 /* .ahclkrctl = */ 0x00000000,
                 /* .rclkchk   = */ 0x00000000
            }
    } ;

    Mcasp_HwSetupData mcaspXmtSetup = {
            /* .xmask    = */ 0xFFFFFFFF, /* All the data bits are to be used     */
            /* .xfmt     = */ 0x000080F0, /*
                                           * 0 bit delay from framsync
                                           * MSB first
                                           * No extra bit padding
                                           * Padding bit (ignore)
                                           * slot Size is 32
                                           * Reads from DMA port
                                           * NO rotation
                                           */
            /* .afsxctl  = */ 0x00000000, /* burst mode,
                                           * Frame sync is one bit
                                           * Rising edge is start of frame
                                           * externally generated frame sync
                                           */
            /* .xtdm     = */ 0x00000001, /* slot 1 is active (DSP)               */
            /* .xintctl  = */ 0x00000007, /* sync error,overrun error,clK error   */
            /* .xstat    = */ 0x000001FF, /* reset any existing status bits       */
            /* .xevtctl  = */ 0x00000000, /* DMA request is enabled or disabled   */
            {
                 /* .aclkxctl  = */ 0x00000000,
                 /* .ahclkxctl = */ 0x00000000,
                 /* .xclkchk   = */ 0x00000000
            },

    };


    /* McBsp channel parameters                                  */
    Mcasp_ChanParams  mcasp_chanparam[Audio_NUM_CHANS]=
    {
        {
            0x0001,                    /* number of serialisers      */
            {Mcasp_SerializerNum_0, }, /* serialiser index           */
            &mcaspRcvSetup,
            TRUE,
            Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */
            Mcasp_WordLength_32,
            NULL,
            0,
            NULL,
            NULL,
            1,                        /* number of TDM channels      */
            Mcasp_BufferFormat_1SER_1SLOT,
            TRUE,
            TRUE
        },
        {
            0x0001,                   /* number of serialisers       */
            {Mcasp_SerializerNum_5,},
            &mcaspXmtSetup,
            TRUE,
            Mcasp_OpMode_TDM,
            Mcasp_WordLength_32,      /* word width                  */
            NULL,
            0,
            NULL,
            NULL,
            1,                        /* number of TDM channels      */
            Mcasp_BufferFormat_1SER_1SLOT,
            TRUE,
            TRUE
        }
    };

    Audio_ChannelConfig audioChanParamsIN =
    {
       /*  channel 0 (RX)                                            */
        (Ptr)&mcasp_chanparam[0], 
        {   /* codec [0]                                              */
            {
                44100,  /* sampling rate for codec */
      10,  /* gain (%) for codec      */
                 0x00,
                 0x00
            }
        }
    };

    Audio_ChannelConfig audioChanParamsOUT =
    {        
        /*  channel 1 (TX)                                            */
        (Ptr)&mcasp_chanparam[1],      
        {
            /* codec [1]                           */
            {
                44100,  /* sampling rate           */
      80,  /* gain (%) for codec      */
                 0x00,
                 0x00
            }
        }
    };

    /*
     * ======== createStreams ========
     */
    static Void createStreams()
    {
        SIO_Attrs sioAttrs;

        sioAttrs   = SIO_ATTRS;
        sioAttrs.nbufs = NUM_BUFS;
        sioAttrs.align = BUFALIGN;
        sioAttrs.model = SIO_ISSUERECLAIM;

    mcasp_chanparam[0].edmaHandle = hEdma;
        mcasp_chanparam[1].edmaHandle = hEdma;

        /* open the I/O streams */
        outStream = SIO_create("/dioAudioOUT", SIO_OUTPUT, BUFSIZE, &sioAttrs);

        if (outStream == NULL)
        {
            LOG_printf(&trace,"\r\nCreate output stream FAILED.\n");
            return;
        }

        inStream = SIO_create("/dioAudioIN", SIO_INPUT, BUFSIZE, &sioAttrs);

        if (inStream == NULL)
        {
            LOG_printf(&trace,"\r\nCreate input stream FAILED.\n");
            return;
        }
    }

    /*
     * ======== audio streams prime ========
     */
    static Void audioPrime()
    {
        Int32        count = 0;

        /* Allocate buffers for the SIO buffer exchanges */
        for(count = 0; count < (NUM_BUFS ); count ++)
        {
            buf[count] = (Ptr)MEM_calloc(0, BUFSIZE * RX_NUM_SERIALIZER, BUFALIGN);
            if(NULL == buf[count])
            {
                LOG_printf(&trace,"\r\nMEM_calloc failed.\n");
            }
        }

        /* Allocate buffers for the SIO buffer exchanges */
        for(count = NUM_BUFS; count < (NUM_BUFS * 2); count ++)
        {
            buf[count] = (Ptr)MEM_calloc(0, BUFSIZE * TX_NUM_SERIALIZER, BUFALIGN);
            if(NULL == buf[count])
            {
                LOG_printf(&trace,"\r\nMEM_calloc failed.\n");
            }
        }

        for(count = 0; count < NUM_BUFS; count ++)
        {
            /* Issue the first & second empty buffers to the input stream */
            SIO_issue(inStream, buf[count], BUFSIZE * RX_NUM_SERIALIZER, NULL);
        }

        for(count = NUM_BUFS; count < (NUM_BUFS * 2); count ++)
        {
            SIO_issue(outStream, buf[count], BUFSIZE * TX_NUM_SERIALIZER,NULL);
        }
    }


    /* ========================================================================== */
    /*                        ECHO TASK + PROCESSING                              */
    /* ========================================================================== */
    float fip[FRAMELEN], fop[FRAMELEN], vec2display[4/*2*/*FRAMELEN]/*, inv_vec2display[2*FRAMELEN]*/;
    Int16 rcv_store[FRAMELEN*4];

    #pragma DATA_ALIGN(fip,8); //double-word align
    #pragma DATA_ALIGN(fop,8);

    Void Audio_echo_Task()
    {
        Int32 frameCount = 0;
        Int nmadus = 0;
        Ptr rcv,xmt;
    Int16 i = 0;
    Uint32 benchmark = 0;
    Uint32 bcmk3, bcmk4;
    int dbgcnt = 0;

        /* initialise the edma library                                            */
        edma3init();

        /* Call createStream function to create I/O streams                       */
        createStreams();

        /* Call prime function to do priming                                      */
        audioPrime();

    /* Priming coeffs for algorithm */
    //algoPrime();

        /* Forever loop to continously receviec and transmit audio data           */
        while(1)
        {
    bcmk3 = CLK_gethtime();
            nmadus = SIO_reclaim(inStream, (Ptr *)&rcv, NULL);
            
            /* Reclaim full buffer from the input stream */
            if (nmadus < 0)
            {
                LOG_printf(&trace,"\r\nError reclaiming full buffer from the input stream\n");
            }

            /* Reclaim empty buffer from the output stream to be reused */
            nmadus = SIO_reclaim(outStream, (Ptr *)&xmt, NULL);
            if (nmadus < 0)
            {
                LOG_printf(&trace,"\r\nError reclaiming empty buffer from the output stream\n");
            }
    /* DEBUG
    DSPF_sp_blk_move((float*) rcv, (float*) &rcv_store[dbgcnt*2*FRAMELEN], FRAMELEN);
    dbgcnt++;
    if ( dbgcnt > 1 ) dbgcnt = 0;
    END DEBUG */

    /* convert: itof, L&R (data are stored as 16bit int: [16bit right][16bit left] interleaved */
    get_LR_itof(rcv, f_in_L, f_in_R, FRAMELEN); // f = float

    /* CHIAMO L'ALGORITMO, questo sostituisce memcpy perché processa rcv e lo copia in xmt */
    //algoritmo(f_in_L, f_in_R, f_out_L, f_out_R, FRAMELEN);
    /* DEBUG */
    /* DSPF_sp_blk_move(fip, vec2display, FRAMELEN);
    DSPF_sp_blk_move(f_in_L, &vec2display[FRAMELEN], FRAMELEN);

    DSPF_sp_blk_move(f_in_L, inv_vec2display, FRAMELEN);
    DSPF_sp_blk_move(fip, &inv_vec2display[FRAMELEN], FRAMELEN);

    DSPF_sp_blk_move(f_in_L, &vec2display[dbgcnt*FRAMELEN], FRAMELEN);
    dbgcnt++;
    if ( dbgcnt > 3 ) dbgcnt = 0;

    DSPF_sp_blk_move(f_in_L, fip, FRAMELEN);
    DSPF_sp_blk_move(f_out_L, fop, FRAMELEN); */
    /* END DEBUG */

    /* Utils */
    //for(i=0; i<FRAMELEN; i++) f_in_L[i] = 0; // mute Left
    //for(i=0; i<FRAMELEN; i++) f_in_R[i] = 0; // mute Right

    memcpy(f_out_L, f_in_L, FRAMELEN * sizeof(float)); //bypass algorithm
    memcpy(f_out_R, f_in_R, FRAMELEN * sizeof(float)); //bypass algorithm

    /* reconvert ftoi, L&R */
    put_LR_ftoi(f_out_L, f_out_R, xmt, FRAMELEN);

            /* Issue full buffer to the output stream    */
            if (SIO_issue(outStream, xmt, BUFSIZE * TX_NUM_SERIALIZER, NULL)
       != SYS_OK)
            {
                LOG_printf(&trace,"\r\nFailed to issue empty buffer to stream\n");
            }

            /* Issue an empty buffer to the input stream */
            if (SIO_issue(inStream, rcv, BUFSIZE * RX_NUM_SERIALIZER, NULL)
       != SYS_OK)
            {
                LOG_printf(&trace,"\r\nFailed to issue empty buffer to stream\n");
            }

    frameCount++; // used to send some data to UART when needed
        }
    }

    /* ========================================================================== */
    /*                     AUDIO CODEC DATA CONVERSION                            */
    /* ========================================================================== */

    /*  The format used in this application for samples from audio codec is interleaved this way:
     * [Right 16bit][Left 16bit][Right 16bit]... if you do ptr++ you shift to the next 
     * location, i.e. 32bit over, I need shifting it 16bits to get the next L/R sample,
     * so: _SHIFT = 1, e.g. if the 'in' ptr is of type shortit shifts 16bit (short=16bit)
     */
    #define _SHIFT 1

    void get_LR_itof(const short * restrict in, float * restrict out_L, float * restrict out_R, int n){
    _nassert((int)in % 128 == 0);
    _nassert((int)out_L % 128 == 0);
    _nassert((int)out_R % 128 == 0);

    #pragma MUST_ITERATE(FRAMELEN,FRAMELEN,FRAMELEN)
    while(n--){
    *out_L = (float)(*in);
    in+=_SHIFT; out_L++;
    *out_R = (float)(*in); 
    in+=_SHIFT; out_R++;
    }
    }

    void put_LR_ftoi(const float * restrict in_L, const float * restrict in_R, short * restrict out, int n){
    _nassert((int)in_L % 128 == 0);
    _nassert((int)in_R % 128 == 0);
    _nassert((int)out % 128 == 0);

    #pragma MUST_ITERATE(FRAMELEN,FRAMELEN,FRAMELEN)
    while(n--){
    *out = (short)(*in_L); 
    out+=_SHIFT; in_L++;
    *out = (short)(*in_R); 
    out+=_SHIFT; in_R++;
    }
    }



    /* ========================================================================== */
    /*                                END OF FILE                                 */
    /* ========================================================================== */

     

  • Mariana, the mcaspDITsample is only for output. it probably would take me a lot of time to rework it to use also input Rx data...

    Thanks anyway

  • Hi Leonardo,

    I could not reproduce the issue.

    One thing I can tell you is that the debugger/graphic interferes a lot with the DSP - to plot the graphic the DSP is stopped for a while, so that is why you are not seeing two consecutive frames with the debugger. Not using the graphic and looking at the output at the oscilloscope is the way to make sure that nothing is being lost - and you already saw that there is not frame lost if you do that.