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.

RTOS/LAUNCHXL-CC26X2R1: Audio quality for LJF(Left justified mode)

Part Number: LAUNCHXL-CC26X2R1
Other Parts Discussed in Thread: TLV320AIC3254

Tool/software: TI-RTOS

Hi ,

We are looking forward to the 3.20 SDK, but we have some functions need to verify first, please refer to the following data flow:

We can stream audio data to peer device, but the output sound is very noisy(we known the root cause is that new I2S driver doesn't support true I2S format )

In the old I2S driver, it provides the parameters fro setting I2S delay mode:

#define I2SCC26XX_FormatLJF 0
/*! \sa I2SCC26XX_FormatLJF */
#define I2SCC26XX_FormatI2SandDSP 1
/*! \sa I2SCC26XX_FormatLJF */
#define I2SCC26XX_FormatRJFmin 2
/*! \sa I2SCC26XX_FormatLJF */
#define I2SCC26XX_FormatRJFmax 255

After changed to LJF mode, the noise level becomes smaller. we can hear the normal sounds, but it has a little background noise.

Do you have any suggestions to us???

Thanks.

BR

Trevor

  • Hi Trevor,

    I would suggest testing at each component of the diagram above to see where the noise is introduced.

    For example, if you just sample from the microphone and playback those samples do you hear noise or is it only introduced after streaming over BLE?

    Additionally, have you changed the settings of the codec to expect LJF "PCM" format (i.e. no 1 bit data delay).

    Another way you can validate that you are receiving data properly is to use another Launchpad to generate an I2S stream of known bits (e.g. 0x0001, 0x0002, etc)

    and be sure that you are in fact receiving the frames properly in your application, this removes the external codec from the equation. If you are receiving the bits correctly, then the issue lies in the codec settings.

  • Hi Sean, 

    Regarding 's comment : If you are making the same error at reading and writing errors will compensate each other.

    I think that we don't need to modify the codec's setting(i2s_echo example also has not been changed to LJF mode).

    I tried to send a sin tone(generated by programming), and there is no noise in the output sound.

    Thanks.

    BR

    Trevor

  • Hi Trevor,

     and I discussed this locally and we clarified the following: if you are just echoing the buffers (e.g. i2secho example) then the one bit offset will not make a difference. However, if you are to treat the buffers at all (such as sending over BLE), then it would be best if you change the codec settings to use LJF mode.

    Clement showed you how to do it here:

    AudioCodec_regWrite(TI3254_AUDIO_IF_1_REG, 0xC0);  // 0xC0 16bit, LJF, BCLK is input to the device, WCLK is input to the device

    Also, when sending the packets over BLE can you embed a sequence number in the frames to be sure that you are not dropping any packets?

  • Hi Sean,

    I tried to change to LJF mode in AIC3254, but I got the same result.

    I also checked the sequence ID, which only dropped a few packets. This is not the root cause, because the noise is continuous.


    I uploaded the recording file. Do you have any thoughts?

    Thanks.

    BR

    Trevor 

  • Trevor,

    Changing to LJF was none the less a good change to make.

    You mention that loopback is working correctly, but sending over BLE introduces noise. Can you give more detail about your BLE signal chain?

    Do you compress the audio, etc? Can you share the relevant functions where you receive audio from I2S and send to BLE and the inverse on the receive side?

  • Hi Sean, 

    We use the 2M PHY to transmit the audio raw data.

    I just ported the TI audio_profile_dle to Rev # E(Sender).

    In default  TI audio_profile_dle profile, it has two types of audio streams(ADPCM & mSBC), and I addED the RAW PCM type in profile. 

    Regarding RAW stream, the payload length is 244(including a 4-byte sequence ID). so the I2S frame is 120(same as mSBC).

    Thanks.

    BR

    Trevor



  • Hi Sean, 

    Do you know if the PCM data stored type is the same in both the old and new I2S driver?

    According to my previous experience, the stored type affects the audio quality.

    For example:

    If we use the signed data type to store the PCM data. 

    play -t raw -r 16000 -e unsigned -b 16 -c 1 pcm.raw   >>>>>> It will make noise

    play -t raw -r 16000 -e signed -b 16 -c 1 pcm.raw       >>>>>>>Without any noise

    BR

    Trevor

  • Hi 

    Add more information:

    1. If I unplug the line-in cable form sender. The receiver does not have any noise

    2. If I plug in the Line-in cable into sender,  then just play the silence. The receiver does not have any noise

    Thanks.

    BR

    Trevor

  • Hi 

    Regarding this http://e2e.ti.com/support/audio/f/6/t/448767 thread, we are worried about the new I2S driver is not standard. But I known the TI will release 3.20 SDK, Have you tried collected the PCM data from LaunchPad on the 3.20 SDK and verified it on third-party player? If yes, I think we can ignore this issue.

    Thanks.

    BR

    Trevor

  • Hi Trevor,

    Replying to your messages in order:

    >> Do you know if the PCM data stored type is the same in both the old and new I2S driver?

    Yes, the driver doesn't impose a storage type on the samples. From the driver perspective they are stored as void*. (ref  I2S_Transaction in I2S.h).

    The memory is managed by the DMA, I2S merely manages sending pointers to the hardware. This is described in detail for the CC26x2/CC13x2 here:

    CC13x2/26x2 TRM

    So in summary the I2S driver will simply pass along what the hardware has sampled based on the state of the DIN pin when the active BCLK pulse occurs.

    However, higher level processing algorithms will care about the data representation e.g. wavplayer, etc. 

    We have also observed (confirmed by your linked e2e post) that the TLV320AIC3254 on the CC3200AUBOOST will produce signed data, so it is correct to call wavplay with the signed argument. However, if there is an issue where the driver is not setup to sample the codec correctly (e.g. missing sign bit) then you will in fact have noise because the sample is not being stored correctly.

    The most important part is that the codec and the I2S driver are using the same serial interface settings. We have verified this by generating different serial waveforms (e.g. patters on BCLK, MCLK, etc) and verified that the correct data is produced by the driver.

    >> we are worried about the new I2S driver is not standard

    The new driver is standard, and will work for your case. It is simply missing the "true I2S" format support which will be introduced in SDK 3.20.

    As a work around you should use LJF mode.

  • Hi Sean,

    I will check this on 3.2 SDK, could you provide the exact release date of the 3.2 SDK?

    Thanks.

    BR

    Trevor

  • Hi Trevor,

    SDK v3.2 will be released by the end of the month.

    Regards,

  • Hi Trevor,

    FYI, SDK v3.20.00.68 has been released: http://www.ti.com/tool/download/SIMPLELINK-CC13X2-26X2-SDK

    Regards,

  • Hi Clément,

    After updating the latest SDK, I got the same result(please check the previous recording file ).

    Have you tried collected the PCM data from LaunchPad on the 3.20 SDK and verified it on third-party player?

    I am going to record the PCM data on SDcard, Will update the result for you later.

    Thanks.

    BR

    Trevor

  • Trevor,

    Can you precise the settings you are now using for the codec and for the I2S driver?

    Regards,

  • Hi Clément,

    After doing some experiments, I found this is my fault. Please see the following code:

    Please take a look at readCallbackFxn() function, the buffer sequence I sent is (0,1,2,3,4,5,6,7,0,1,2,3 ~~~~~~~~), it will produce the noise.

    But if I moved the sequence(7,0,1,2,3,4,5,6,7,0,1,2) in recordThred(), there will be no noise. 

    In the TI example, it will process the previous transaction, but I checked that the first buffer is always empty(you can double check it), so I decided not to deal with the pervious transaction, but it will produce the noise. I still don't know what the root cause is???critical section  ????

    List_List i2sList;
    List_List treatmentList;
    I2S_Handle i2sHandle;
    
    static int16_t buf1[AUDIO_BUFSIZE];
    static int16_t buf2[AUDIO_BUFSIZE];
    static int16_t buf3[AUDIO_BUFSIZE];
    static int16_t buf4[AUDIO_BUFSIZE];
    static int16_t buf5[AUDIO_BUFSIZE];
    static int16_t buf6[AUDIO_BUFSIZE];
    static int16_t buf7[AUDIO_BUFSIZE];
    static int16_t buf8[AUDIO_BUFSIZE];
    static int16_t* i2sBufList[AUDIO_NUMBUFS] = {buf1, buf2, buf3, buf4, buf5, buf6, buf7, buf8};
    
    I2S_Transaction i2sTransaction1;
    I2S_Transaction i2sTransaction2;
    I2S_Transaction i2sTransaction3;
    I2S_Transaction i2sTransaction4;
    I2S_Transaction i2sTransaction5;
    I2S_Transaction i2sTransaction6;
    I2S_Transaction i2sTransaction7;
    I2S_Transaction i2sTransaction8;
    static I2S_Transaction *i2sTransactionList[AUDIO_NUMBUFS] = {&i2sTransaction1, &i2sTransaction2, &i2sTransaction3,
                                                           &i2sTransaction4, &i2sTransaction5, &i2sTransaction6,
                                                           &i2sTransaction7, &i2sTransaction8};
    
    static g_index=0;
    
    static void readCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {
       if(streamVariables.streamType==AUDIO_CMD_START_RAW)
        {
            uint8_t *pIndex = ICall_malloc(sizeof(uint8_t));
            if (pIndex)
            {
                *pIndex = g_index;
                if (ProjectZero_enqueueMsg(AUDIO_DATA, pIndex) != SUCCESS)
                {
                  ICall_free(pIndex);
                }
            }
            else
            {
                Log_error0("Got readCallbackFxn errors");
            }
    
        }
        g_index++;
        if(g_index == AUDIO_NUMBUFS)
            g_index=0;
    
    
    }
    
    
    static int8_t I2SInitStream()
    {
        I2S_Params i2sParams;
    
    
        /* Call driver init functions */
        I2S_init();
        /*
         *  Open the I2S driver
         */
        //Initialize I2S opening parameters
        I2S_Params_init(&i2sParams);
        i2sParams.samplingFrequency     =  16000;
        i2sParams.fixedBufferLength     =  (AUDIO_BUFSIZE * 2);
        i2sParams.readCallback          =  readCallbackFxn ;
        i2sParams.errorCallback         =  errCallbackFxn;
        i2sParams.SD1Channels           =  I2S_CHANNELS_MONO;
        i2sParams.SD0Channels           =  I2S_CHANNELS_MONO;
        i2sParams.SD0Use                =  I2S_SD0_DISABLED;
    
        i2sHandle = I2S_open(Board_I2S0, &i2sParams);
    
        uint8_t k;
        for(k = 0; k < AUDIO_NUMBUFS; k++) {
            I2S_Transaction_init(i2sTransactionList[k]);
            i2sTransactionList[k]->bufPtr  = i2sBufList[k];
            i2sTransactionList[k]->bufSize = (AUDIO_BUFSIZE * 2);
            List_put(&i2sList, (List_Elem*)i2sTransactionList[k]);
        }
        List_tail(&i2sList)->next = List_head(&i2sList); /* I2S buffers are queued in a ring-list */
        List_head(&i2sList)->prev = List_tail(&i2sList);
    
        I2S_setReadQueueHead(i2sHandle, &i2sTransaction1);
    
        return true;
    }
    
    
    Void * recordThread()
    {
              events = Event_pend();
              while(1)
              {
                  int offset = *(uint8_t*)(pMsg->pData);
    
                  res = f_write(&file_object, (int8_t *)i2sBufList[offset] ,(AUDIO_BUFSIZE*2), &bw);
                  if (res != FR_OK || bw < (AUDIO_BUFSIZE*2)) {
                      Log_error1("-E- f_write pb: 0x%X\n\r", res);
                      return;
                  }
              }
    
    }

    BR

    Trevor

  • Hi Clément,

    I just add the following code in recordThread() for moving sequence.

    int offset = *(uint8_t*)(pMsg->pData);
    offset--;
    if(offset < 0)
    offset = 7;

    BR

    Trevor

      

  • Hi Clément,

    Could you help to clarify the issue?

    You can see that I have eight I2S_Transaction (i2sTransaction1 -i2sTransaction8) and I set the i2sTransaction1(buf1) as the first read-transaction. In readCallbackFxn(), I have confirmed that the first transaction is i2sTransaction1(buf1),  but I can't deal with this transaction, I must to use the previous one, otherwise it will generate noise.

    Thanks.

    BR

    Trevor

  • Hi,

    When you receive a read/write callback, the transaction (buffer) pointed by transactionPtr is *NOT* the transaction finished but the transaction that just began.

    In other word, if you access the data in the transactionPtr’s buffer you have good chance to run into problems. To avoid this, the data that should be used is the data stored in the buffer of the transaction before transactionPtr.

    I enclosed a small picture showing this:

    Best regards,

  • Hi Clément, 

    I got it, thanks for your detailed explanation.

    BR

    Trevor