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.

CC1352R: I2S 24 Bit word size

Part Number: CC1352R

This should actually be a response to e2e.ti.com/.../i2s-24-bit-output-problem-on-cc1310, but unfortunately this thread is already closed.

I was already shocked when I saw this 5 year old post, as I stumbled upon the same problem. My mic has a 24 bit word size and when I compare the actual data on the bus with a logic analyzer and compare it with the results in the byte buffer I can clearly see that of the 3 bytes of each word only 2 were read.

The reason seems to be within the SDK, the call to I2S_startClocks sets the content of I2S:AIFFMTCFG to the wrong setting, although a 24 bit word size has been selected in the I2S_Params. The solution is luckily not too hard:

    I2S_startClocks(i2sHandle);
    uint32_t *registerAddress = (uint32_t*)0x4002100C; // address of I2S0:AIFFMTCFG
    uint32_t registerValue = *registerAddress;
    registerValue |= (1 << 7); // bit MEM_LEN_24
    *registerAddress = registerValue;

Regards,
benediktibk

  • Hi Benediktibk,

    1. What version of the SDK are you testing with?

    2. Can you attach a logic trace showing this, preferably along side what you were expecting to see. 

  • Hi Marie,

    it looks like I cannot attach something to a post? Weird, but anyway, then without pictures! ;-)

    When I configure a buffer size of 6 (2x24 bit word samples) I can read out the following bytes via logic analyzer:
    0xC1E728
    0xC2FB46

    The content of the buffer is:
    0xE7
    0xC1
    0xFB
    0xC2
    0x00
    0x00

    Obviously, the LSB bytes are missing.

    I'm using the SDK version 4.40.04.04.

    Btw, I found out that the content of I2S:AIFDMACFG is incorrect as well for 24 bit words. This value is set for a buffer size of 240 to 119 (240/2 - 1), which would be the frame count for 16 bits. A setting, which made my day yesterday pretty annoying, as I tried to figure out what ****s up my memory. The solution is fixing this register value as well manually:

    uint32_t *aifdmacfg = (uint32_t*)(0x40021000 + 0x04);
    *aifdmacfg = (BUFSIZE/3 - 1);

    Overall this solves my problems, so I'm happy with it. But do you think this could get fixed in the SDK itself?

    Regards,
    benediktibk

  • Hi benediktibk,

    Thanks for your question, we'll try and reproduce this issue here and get back to you with an update. 

    Thanks, 
    Elin 

  • Hi benediktibk,

    Apologies for the delay on this thread. 

    Thanks for reporting this, I have filed an internal ticket to get this validated. 

    Thanks, 
    Elin

  • Thanks for the Update.

    benediktibk

  • Hi benediktibk, 

    We are trying to reproduce your issue but are unable to do so using the default parameters. Can you share the full list of I2S parameters you use? It should look something like this: 

    I2S_Params params;
    I2S_Params_init(&params);
    params.samplingFrequency = 8000;
    params.memorySlotLength = I2S_MEMORY_LENGTH_16BITS;
    params.moduleRole = I2S_MASTER;
    params.trueI2sFormat = (bool)true;
    params.invertWS = (bool)true;
    params.isMSBFirst = (bool)true;
    params.isDMAUnused = (bool)false;
    params.samplingEdge = I2S_SAMPLING_EDGE_RISING;
    params.beforeWordPadding = 0;
    params.bitsPerWord = 16;
    params.afterWordPadding = 0;
    params.fixedBufferLength = 1;
    params.SD1Channels = I2S_CHANNELS_STEREO;
    params.phaseType = I2S_PHASE_TYPE_DUAL;
    i2sHandle = I2S_open(CONFIG_I2S_0, &params);

    Thanks, 
    Elin 

  • I just saw you are setting the parameter memorySlotLength, something which I did not yet stumble upon. Maybe this is the difference. Anyway, this is the whole example, already including the work arounds. So to reproduce you would just have to remove the register-setting-action:

    #include <stdint.h>
    #include <stddef.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <string.h>
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <semaphore.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/I2S.h>
    #include <ti/display/Display.h>
    #include "ti_drivers_config.h"

    #define SAMPLE_RATE       8000
    #define NUMBUFS           4
    #define BUFSIZE           240

    static sem_t semDataReadyForTreatment;

    List_List i2sReadList;
    List_List treatmentList;

    static uint8_t buf1[BUFSIZE];
    static uint8_t buf2[BUFSIZE];
    static uint8_t buf3[BUFSIZE];
    static uint8_t buf4[BUFSIZE];
    static uint8_t* i2sBufList[NUMBUFS] = {buf1, buf2, buf3, buf4};

    I2S_Transaction i2sTransaction1;
    I2S_Transaction i2sTransaction2;
    I2S_Transaction i2sTransaction3;
    I2S_Transaction i2sTransaction4;
    static I2S_Transaction *i2sTransactionList[NUMBUFS] = { &i2sTransaction1,  &i2sTransaction2,  &i2sTransaction3, &i2sTransaction4 };
    uint32_t *aifdmacfg;
    uint32_t *aifinptr;
    uint32_t *aifinptrnext;
    I2S_Handle i2sHandle;
    Display_Handle displayHandle;
    #define COMPLETESAMPLEBUFFERSIZE 8000*1
    int32_t sampleBuffer[BUFSIZE/3];
    int32_t completeSampleBuffer[COMPLETESAMPLEBUFFERSIZE];
    size_t completeSampleBufferPosition;
    char displayBuffer[130];

    int32_t readFromBufferInt24LittleEndian(uint8_t *buffer, size_t *currentBufferPosition) {
        int32_t result;

        result = 0;
        result |= *(buffer + *currentBufferPosition + 2) << 24;
        result |= *(buffer + *currentBufferPosition + 1) << 16;
        result |= *(buffer + *currentBufferPosition + 0) << 8;
        result >>= 8;

        *currentBufferPosition += 3;
        return result;
    }

    static float calculateSoundPressureLevelInDb(uint64_t squareSum, unsigned int sampleCount) {
        const float microphoneScalingFactor = 6486;
        const uint32_t int24Max = 8388608;
        float sumScaled = (squareSum * microphoneScalingFactor) / int24Max;
        float sumScaledAndAverage = sumScaled / sampleCount;
        float rms = sqrt(sumScaledAndAverage);
        return 20 * log10(rms);
    }

    static void addToSquareSum(uint64_t *squareSum, int32_t sample) {
        *squareSum += sample * sample;
    }

    static void errCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {
    }

    static void writeCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {

    }

    static void readCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {
        if(transactionPtr->queueElement.prev == 0) {
            return;
        }

        List_Elem *transactionFinished = List_get(&i2sReadList);
        List_put(&treatmentList, (List_Elem*)transactionFinished);
        sem_post(&semDataReadyForTreatment);
    }

    void receiveOneSecond() {
        completeSampleBufferPosition = 0;
        List_clearList(&i2sReadList);
        List_clearList(&treatmentList);

        for(size_t k = 0; k < NUMBUFS; k++) {
            I2S_Transaction *current = i2sTransactionList[k];
            I2S_Transaction_init(current);
            current->bufPtr  = i2sBufList[k];
            current->bufSize = BUFSIZE;
            List_put(&i2sReadList, (List_Elem*)current);
        }

        I2S_setReadQueueHead(i2sHandle, (I2S_Transaction*) List_head(&i2sReadList));

        Display_printf(displayHandle, 1, 0, "starting the I2S clocks");
        I2S_startClocks(i2sHandle);
        uint32_t *registerAddress = (uint32_t*)0x4002100C;
        uint32_t registerValue = *registerAddress;
        registerValue |= (1 << 7);
        registerValue |= 0x18;
        *registerAddress = registerValue;
        Display_printf(displayHandle, 1, 0, "waiting for 5s to provide time to start logic analyzer");
        sleep(5);
        GPIO_write(CONFIG_GPIO_SYNC, CONFIG_GPIO_LED_ON);

        *aifdmacfg = (BUFSIZE/3 - 1);
        I2S_startRead(i2sHandle);
        size_t frameCounter = 0;
        uint64_t microphoneResultSquareSum = 0;
        int32_t sampleMax = INT32_MIN;
        int32_t sampleMin = INT32_MAX;

        while (true) {
            sem_wait(&semDataReadyForTreatment);

            I2S_Transaction* transactionToTreat = (I2S_Transaction*) List_get(&treatmentList);

            if(transactionToTreat == 0) {
                Display_printf(displayHandle, 1, 0, "no transaction to read available, causing a crash");
                return;
            }

            int32_t sample;
            uint8_t *buffer = (uint8_t*)transactionToTreat->bufPtr;
            memset(sampleBuffer, 0, sizeof(sampleBuffer));
            size_t sampleBufferIndex;

            for (size_t i = 0; i < transactionToTreat->bufSize;) {
                sampleBufferIndex = i/3;
                sample = readFromBufferInt24LittleEndian(buffer, &i);
                sampleBuffer[sampleBufferIndex] = sample;
                completeSampleBuffer[completeSampleBufferPosition] = sample;
                completeSampleBufferPosition++;

                if (sample > sampleMax) {
                    sampleMax = sample;
                }

                if (sample < sampleMin) {
                    sampleMin = sample;
                }
            }

            for (size_t i = 0; i < sizeof(sampleBuffer); ++i) {
                sample = (float)sampleBuffer[i];
                addToSquareSum(&microphoneResultSquareSum, sample);
            }

            frameCounter++;

            if (frameCounter >= 100) {
                unsigned int resultMeanIndB = calculateSoundPressureLevelInDb(microphoneResultSquareSum, sizeof(sampleBuffer) * frameCounter);
                GPIO_toggle(CONFIG_GPIO_GREEN_2);
                snprintf(displayBuffer, sizeof(displayBuffer), "spl: %u dB, rms: 0x%02X%02X%02X%02X%02X%02X%02X%02X, sample min: %li, sample max: %li",
                         resultMeanIndB,
                         (uint8_t)((((microphoneResultSquareSum >> 4 * 8) & 0xFF000000)) >> 3 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 4 * 8) & 0x00FF0000)) >> 2 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 4 * 8) & 0x0000FF00)) >> 1 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 4 * 8) & 0x000000FF)) >> 0 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 0 * 8) & 0xFF000000)) >> 3 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 0 * 8) & 0x00FF0000)) >> 2 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 0 * 8) & 0x0000FF00)) >> 1 * 8),
                         (uint8_t)((((microphoneResultSquareSum >> 0 * 8) & 0x000000FF)) >> 0 * 8),
                         sampleMin,
                         sampleMax);
                Display_printf(displayHandle, 1, 0, displayBuffer);
                frameCounter = 0;
                microphoneResultSquareSum = 0;
                sampleMax = INT32_MIN;
                sampleMin = INT32_MAX;

                if (resultMeanIndB > 30) {
                    GPIO_write(CONFIG_GPIO_RED, CONFIG_GPIO_LED_ON);
                }
                else {
                    GPIO_write(CONFIG_GPIO_RED, CONFIG_GPIO_LED_OFF);
                }

                GPIO_write(CONFIG_GPIO_SYNC, CONFIG_GPIO_LED_OFF);
                I2S_stopClocks(i2sHandle);

                Display_printf(displayHandle, 1, 0, "all samples:");


                for (size_t i = 0; i < COMPLETESAMPLEBUFFERSIZE; i += 16) {
                    size_t displayBufferPosition = 0;
                    memset(displayBuffer, 0, sizeof(displayBuffer));

                    for (size_t j = 0; j < 16; ++j) {
                        uint32_t currentSample = (uint32_t)completeSampleBuffer[i + j];
                        int writtenBytes = snprintf(
                                displayBuffer + displayBufferPosition,
                                sizeof(displayBuffer) - displayBufferPosition,
                                "%02X%02X%02X%02X",
                                (uint8_t)(currentSample >> 3 * 8),
                                (uint8_t)(currentSample >> 2 * 8),
                                (uint8_t)(currentSample >> 1 * 8),
                                (uint8_t)(currentSample >> 0 * 8));

                        if (writtenBytes != 8) {
                            Display_printf(displayHandle, 1, 0, "crazy stuff happened");
                            return;
                        }

                        displayBufferPosition += writtenBytes;
                    }
                    Display_printf(displayHandle, 1, 0, displayBuffer);
                }

                for (size_t i = 0; i < COMPLETESAMPLEBUFFERSIZE; ++i) {
                    int32_t currentSample = completeSampleBuffer[i];
                    Display_printf(displayHandle, 1, 0, "%li", currentSample);
                }

                return;
            }

            List_put(&i2sReadList, (List_Elem*)transactionToTreat);
        }
    }

    void *mainThread(void *arg0) {
        I2S_init();
        GPIO_init();

        GPIO_setConfig(CONFIG_GPIO_RED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_GREEN_1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_GREEN_2, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_SYNC, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_write(CONFIG_GPIO_GREEN_1, CONFIG_GPIO_LED_ON);

        sem_init(&semDataReadyForTreatment, 0, 0);

        aifdmacfg = (uint32_t*)(0x40021000 + 0x04);
        aifinptr = (uint32_t*)(0x40021000 + 0x24);
        aifinptrnext = (uint32_t*)(0x40021000 + 0x20);

        I2S_Params i2sParams;
        I2S_Params_init(&i2sParams);
        i2sParams.samplingFrequency = SAMPLE_RATE;
        i2sParams.fixedBufferLength = BUFSIZE;
        i2sParams.writeCallback = writeCallbackFxn;
        i2sParams.readCallback = readCallbackFxn;
        i2sParams.errorCallback = errCallbackFxn;
        i2sParams.SD0Use = I2S_SD0_INPUT;
        i2sParams.SD1Use = I2S_SD1_DISABLED;
        i2sParams.SD0Channels = I2S_CHANNELS_MONO; // we get only the right channel from the microphone in this hardware configuration
        i2sParams.bitsPerWord = 24;
        i2sParams.trueI2sFormat = true;
        i2sParams.isMSBFirst = true;
        i2sParams.isDMAUnused = true;
        i2sParams.beforeWordPadding = 0;
        i2sParams.afterWordPadding = 8;
        i2sParams.moduleRole = I2S_MASTER;
        i2sParams.samplingEdge = I2S_SAMPLING_EDGE_RISING;
        i2sParams.phaseType = I2S_PHASE_TYPE_DUAL;
        i2sParams.startUpDelay = 0;
        i2sParams.invertWS = false;
        i2sHandle = I2S_open(CONFIG_I2S_0, &i2sParams);

        Display_Params params;
        Display_Params_init(&params);
        displayHandle = Display_open(Display_Type_UART, &params);
        Display_clear(displayHandle);

        receiveOneSecond();
        Display_printf(displayHandle, 1, 0, "shutting down");
        I2S_close(i2sHandle);
        GPIO_write(CONFIG_GPIO_GREEN_1, CONFIG_GPIO_LED_OFF);
        while(true);
    }

    Regards,
    Benedikt

  • I just gave it a try with setting memorySlotLength to I2S_MEMORY_LENGTH_24BITS. This fixes the issue with AIFDMACFG, but WORD_LEN of AIFFMTCFG is still incorrect (set to 0).

    Regards,
    benediktibk

  • Hi benediktibk,

    Perfect, thanks for sharing. 

    Thanks, 
    Elin