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.

CCS/CC2652R: Unable to read from SD card importing fatsd example

Part Number: CC2652R
Other Parts Discussed in Thread: TLV320AIC3254, CC3200AUDBOOST, SYSCONFIG, CC3200

Tool/software: Code Composer Studio

Good afternoon:

We are working on an application to play an audio sample (saved on an SD card) and send it to CC3200AUDBOOST's TLV320AIC3254 codec.

I have tried the "fatsd" and "i2secho" examples separately and both work perfectly.The next step is to implement the code from "fatsd" into "i2secho" and this is where we are having problems since it seems that some kind of problem is happening when opening the SPI communication with the SD card.

Attached is the code:

I'm also attaching two screenshots from the logic analyzer so you can see the difference between running the example "fatsd" (first image) and our application (second image). Each line of the logic analyzer is:

- D4: MOSI

- D5: CLK

- D6: MISO

- D7: CS

As you can see, the SPI communication is not carried out, but the code shows the drive mounted correctly.

fopen() always return NULL on opening, but it is possible to see a voltage change level when SDFatFS_open() is called.

We suspect, after debugging, that the bus may be busy.

We have tried the following:

- Try to create instead of opening a file - Nothing (line 233 and followings)

- Try to re-nice SPI and DMA - Nothing

- Try to hardwire CS to GND - Nothing

- Try to disconnect SD reader module - The same

 We'd appreciate it if you could give us a hand with this problem:)

Greetings in advance.

/*
 * Copyright (c) 2015-2020, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== i2secho.c ========
 */
#include <file.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* POSIX Header files */
#include <pthread.h>
#include <semaphore.h>

#include <third_party/fatfs/ffcio.h>

/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2S.h>

#include <ti/display/Display.h>
#include <ti/drivers/SDFatFS.h>

/* Driver configuration */
#include "ti_drivers_config.h"
#include "AudioCodec.h"
#include <math.h>

#define THREADSTACKSIZE   2048

/* The higher the sampling frequency, the less time we have to process the data, but the higher the sound quality. */
#define SAMPLE_RATE                     44100   /* Supported values: 8kHz, 16kHz, 32kHz and 44.1kHz */
#define INPUT_OPTION                    AudioCodec_MIC_LINE_IN
#define OUTPUT_OPTION                   AudioCodec_SPEAKER_ALL

/* The more storage space we have, the more delay we have, but the more time we have to process the data. */
#define NUMBUFS         10      /* Total number of buffers to loop through */
#define BUFSIZE         256     /* I2S buffer size */

static Display_Handle display;

/* Set this to the current UNIX time in seconds */
const struct timespec ts = {
    .tv_sec = 1469647026,
    .tv_nsec = 0
};

/* Semaphore used to indicate that data must be processed */
static sem_t semDataReadyForTreatment;
char fatfsPrefix[] = "fat";
#define DRIVE_NUM 0

/* String conversion macro */
#define STR_(n)             #n
#define STR(n)              STR_(n)

/* Semaphore used to indicate that data must be processed */
static sem_t semDataReadyForTreatment;

/* Lists containing transactions. Each transaction is in turn in these three lists */
List_List i2sReadList;
List_List treatmentList;
List_List i2sWriteList;

/* Buffers containing the data: written by read-interface, modified by treatment, and read by write-interface */
static uint8_t buf1[BUFSIZE];
static uint8_t buf2[BUFSIZE];
static uint8_t buf3[BUFSIZE];
static uint8_t buf4[BUFSIZE];
static uint8_t buf5[BUFSIZE];
static uint8_t buf6[BUFSIZE];
static uint8_t buf7[BUFSIZE];
static uint8_t buf8[BUFSIZE];
static uint8_t buf9[BUFSIZE];
static uint8_t buf10[BUFSIZE];
static uint8_t* i2sBufList[NUMBUFS] = {buf1, buf2, buf3, buf4, buf5, buf6, buf7, buf8, buf9, buf10};

/* Transactions will successively be part of the i2sReadList, the treatmentList and the i2sWriteList */
I2S_Transaction i2sTransaction1;
I2S_Transaction i2sTransaction2;
I2S_Transaction i2sTransaction3;
I2S_Transaction i2sTransaction4;
I2S_Transaction i2sTransaction5;
I2S_Transaction i2sTransaction6;
I2S_Transaction i2sTransaction7;
I2S_Transaction i2sTransaction8;
I2S_Transaction i2sTransaction9;
I2S_Transaction i2sTransaction10;
static I2S_Transaction *i2sTransactionList[NUMBUFS] = {&i2sTransaction1,  &i2sTransaction2,  &i2sTransaction3,
                                                       &i2sTransaction4,  &i2sTransaction5,  &i2sTransaction6,
                                                       &i2sTransaction7,  &i2sTransaction8,  &i2sTransaction9,
                                                       &i2sTransaction10};

I2S_Handle i2sHandle;

static void errCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {
    /* The content of this callback is executed if an I2S error occurs */
    I2S_stopClocks(handle);
    I2S_close(handle);
}

static void writeCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {
    /*
     * The content of this callback is executed every time a write-transaction is started
     */

    /* We must consider the previous transaction (the current one is not over)  */
    I2S_Transaction *transactionFinished = (I2S_Transaction*)List_prev(&transactionPtr->queueElement);

    if(transactionFinished != NULL){
        /*
         * Remove the finished transaction from the write queue and feed
         * the read queue (we do not need anymore the data of this transaction)
         */
        List_remove(&i2sWriteList, (List_Elem*)transactionFinished);
        List_put(&i2sReadList, (List_Elem*)transactionFinished);

        /*
         * We do not need to queue transaction here:
         * treatment-function takes care of this :)
         */
    }
}

static void readCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) {
    /*
     * The content of this callback is executed every time a read-transaction
     * is started
     */

    /* We must consider the previous transaction (the current one is not over) */
    I2S_Transaction *transactionFinished = (I2S_Transaction*)List_prev(&transactionPtr->queueElement);

    if(transactionFinished != NULL){

        /* The finished transaction contains data that must be treated */
        List_remove(&i2sReadList, (List_Elem*)transactionFinished);
        List_put(&treatmentList, (List_Elem*)transactionFinished);

        /* Start the treatment of the data */
        sem_post(&semDataReadyForTreatment);

        /*
         * We do not need to queue transaction here:
         * writeCallbackFxn takes care of this :)
         */
    }
}

/*
 *  ======== echoThread ========
 */
#define M_PI 3.14159265358979323846
unsigned long generatePCMSample(unsigned long freq, unsigned long sample_freq, uint32_t* buffer, int buffer_tam) {
    int i;
    for (i = 0; i < buffer_tam / 8; i++) {
        buffer[i] = 0x0000FE00 + (0x0100 * sin((float)(2 * M_PI * freq * ((float)i / sample_freq))));
    }
    return (sample_freq / buffer_tam); // minium frecuency that can be full wave stored
}

//#define TEST_TAM 1
#define TEST_TAM (transactionToTreat->bufSize/2)
const char inputfile[] = "fat:"STR(DRIVE_NUM)":input.txt";
void *echoThread(void *arg0)
{
    SDFatFS_Handle sdfatfsHandle;
    FILE *src;

    // unsigned int bytesRead = 0;
    // unsigned int bytesWritten = 0;
    // unsigned int filesize;
    // unsigned int totalBytesCopied = 0;

    int result;

    GPIO_init();
    Display_init();
    SDFatFS_init();

    /* add_device() should be called once and is used for all media types */
    add_device(fatfsPrefix, _MSA, ffcio_open, ffcio_close, ffcio_read, ffcio_write, ffcio_lseek, ffcio_unlink, ffcio_rename);

    display = Display_open(Display_Type_UART, NULL);
    if (display == NULL) {
        /* Failed to open display driver */
        while (1);
    }
    GPIO_write(CONFIG_GPIO_0, CONFIG_GPIO_LED_ON );
    sdfatfsHandle = SDFatFS_open(CONFIG_SDFatFS_0, DRIVE_NUM);
    if (sdfatfsHandle == NULL) {
        Display_printf(display, 0, 0, "Error starting the SD card\n");
        while (1);
    }
    else {
        Display_printf(display, 0, 0, "Drive %u is mounted\n", DRIVE_NUM);
    }

    /**************************************************/
    //also tried with the following line:
    //src = fopen(inputfile, "w+");

    src = fopen(inputfile, "r");

    if (!src){
        Display_printf(display, 0, 0, "\nFile did not open");

    }
    else {
        Display_printf(display, 0, 0, "%s - opened",inputfile);
    }

    /* Initialize real-time clock */
    clock_settime(CLOCK_REALTIME, &ts);

    /* Initialize TLV320AIC3254 Codec on Audio BP */
    uint8_t status = AudioCodec_open();
    if( AudioCodec_STATUS_SUCCESS != status)
    {
        /* Error Initializing codec */
        while(1);
    }

    /* Configure Codec */
    status =  AudioCodec_config(AudioCodec_TI_3254, AudioCodec_16_BIT,
                                SAMPLE_RATE, AudioCodec_STEREO, AudioCodec_SPEAKER_ALL,
                                AudioCodec_MIC_LINE_IN);
    if( AudioCodec_STATUS_SUCCESS != status)
    {
        /* Error Initializing codec */
        while(1);
    }

    /* Volume control */
    AudioCodec_speakerVolCtrl(AudioCodec_TI_3254, AudioCodec_SPEAKER_HP, 75);
    AudioCodec_micVolCtrl(AudioCodec_TI_3254, AudioCodec_MIC_ONBOARD, 75);

    /* Prepare the semaphore */
    int retc = sem_init(&semDataReadyForTreatment, 0, 0);
    if (retc == -1) {
        while (1);
    }

    /*
     *  Open the I2S driver
     */
    I2S_Params i2sParams;
    I2S_Params_init(&i2sParams);
    i2sParams.samplingFrequency =  SAMPLE_RATE;
    i2sParams.fixedBufferLength =  BUFSIZE;
    i2sParams.writeCallback     =  writeCallbackFxn ;
    i2sParams.readCallback      =  readCallbackFxn ;
    i2sParams.errorCallback     =  errCallbackFxn;
    i2sHandle = I2S_open(CONFIG_I2S_0, &i2sParams);
    if (i2sHandle == NULL) {
        /* Error Opening the I2S driver */
        while(1);
    }

    /* Initialize the queues and the I2S transactions */
    List_clearList(&i2sReadList);
    List_clearList(&treatmentList);
    List_clearList(&i2sWriteList);

    uint8_t k;
    /* Half the transactions are initially stored in the read queue */
    for(k = 0; k < NUMBUFS/2; k++) {
        I2S_Transaction_init(i2sTransactionList[k]);
        i2sTransactionList[k]->bufPtr  = i2sBufList[k];
        i2sTransactionList[k]->bufSize = BUFSIZE;
        List_put(&i2sReadList, (List_Elem*)i2sTransactionList[k]);
    }

    /* The second half of the transactions is stored in the write queue */
    for(k = NUMBUFS/2; k < NUMBUFS; k++) {
        I2S_Transaction_init(i2sTransactionList[k]);
        i2sTransactionList[k]->bufPtr  = i2sBufList[k];
        i2sTransactionList[k]->bufSize = BUFSIZE;
        List_put(&i2sWriteList, (List_Elem*)i2sTransactionList[k]);
    }

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

    /* Start I2S streaming */
    I2S_startClocks(i2sHandle);
    I2S_startRead(i2sHandle);
    I2S_startWrite(i2sHandle);
    // srand(159633278);
    /* Treatment */

    uint8_t devNull;
    fread(&devNull, 1, 1, src);

    while(1){
        // unsigned long int p = 0;
        // int i = 0;

        /* Wait for transaction ready for treatment */
        retc = sem_wait(&semDataReadyForTreatment);
        if (retc == -1) {
            while (1);
        }

        // ((uint16_t *)(transactionToTreat->bufPtr))[i*2] = 0xff00 + i*2;

        I2S_Transaction* transactionToTreat = (I2S_Transaction*) List_head(&treatmentList);
        //fread(transactionToTreat->bufPtr, 1, transactionToTreat->bufSize/2, src);
        if(transactionToTreat != NULL){
            /*
             * Treatment:
             *   The higher the sampling frequency,
             *   the less time we have to process the data
             */
            #if SAMPLE_RATE > 16000
                /* No data processing */
            #elif SAMPLE_RATE > 8000
                /* Data processing */
                int16_t *buf = transactionToTreat->bufPtr;
                /* bufSize is expressed in bytes but samples to consider are 16 bits long */
                uint16_t numOfSamples = transactionToTreat->bufSize / sizeof(uint16_t);
                uint16_t n;
                /* We only modify Left channel's samples () */
                for(n=0; n<numOfSamples-2; n=n+2) {
                    /*
                     * Here we use a very basic filter
                     * (average to reduce noise level on left channel)
                     *
                     * Note: data coming from left channel and right channel
                     * are interleaved
                     */
                    buf[n] = (buf[n] + buf[n+2]) / 2;
                }
            #else
                /* Data processing */
                int16_t *buf = transactionToTreat->bufPtr;
                uint16_t numOfSamples = transactionToTreat->bufSize / sizeof(uint16_t);
                uint16_t n;
                /* We modify both channel's samples */
                for(n=0; n<numOfSamples-2; n=n+1) {
                    /*
                     * Here we use a very basic filter (average to reduce noise level)
                     *
                     * Note: data coming from left channel and right channel
                     * are interleaved
                     */
                    buf[n] = (buf[n] + buf[n+2]) / 2;
                }
            #endif

            /* Place in the write-list the transaction we just treated */
            List_remove(&treatmentList, (List_Elem*)transactionToTreat);
            List_put(&i2sWriteList, (List_Elem*)transactionToTreat);
        }
    }
}

/*
 *  ======== mainThread ========
 */

void *mainThread(void *arg0)
{
    pthread_t           thread0;
    pthread_attr_t      attrs;
    struct sched_param  priParam;
    int                 retc;
    int                 detachState;

    /* Call driver init functions */
    I2S_init();

/* On CC32XX, do not enable GPIO due to an LED/I2S pin conflict */
#if !(defined(DeviceFamily_CC3200) || defined(DeviceFamily_CC3220) || defined(DeviceFamily_CC3235))
    GPIO_init();

    /* Configure the LED pin */
    GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);

    /* Turn on user LED */
    GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
#endif

    /* Set priority and stack size attributes */
    pthread_attr_init(&attrs);
    priParam.sched_priority = 1;

    detachState = PTHREAD_CREATE_DETACHED;
    retc = pthread_attr_setdetachstate(&attrs, detachState);
    if (retc != 0) {
        /* pthread_attr_setdetachstate() failed */
        while (1);
    }

    pthread_attr_setschedparam(&attrs, &priParam);

    retc |= pthread_attr_setstacksize(&attrs, THREADSTACKSIZE);
    if (retc != 0) {
        /* pthread_attr_setstacksize() failed */
        while (1);
    }

    /* Create receive thread */
    retc = pthread_create(&thread0, &attrs, echoThread, NULL);
    if (retc != 0) {
        /* pthread_create() failed */
        while (1);
    }

    return (NULL);
}

int32_t fatfs_getFatTime(void)
{
    time_t seconds;
    uint32_t fatTime;
    struct tm *pTime;

    /*
     *  TI time() returns seconds elapsed since 1900, while other tools
     *  return seconds from 1970.  However, both TI and GNU localtime()
     *  sets tm tm_year to number of years since 1900.
     */
    seconds = time(NULL);

    pTime = localtime(&seconds);

    /*
     *  localtime() sets pTime->tm_year to number of years
     *  since 1900, so subtract 80 from tm_year to get FAT time
     *  offset from 1980.
     */
    fatTime = ((uint32_t)(pTime->tm_year - 80) << 25) |
        ((uint32_t)(pTime->tm_mon) << 21) |
        ((uint32_t)(pTime->tm_mday) << 16) |
        ((uint32_t)(pTime->tm_hour) << 11) |
        ((uint32_t)(pTime->tm_min) << 5) |
        ((uint32_t)(pTime->tm_sec) >> 1);

    return ((int32_t)fatTime);
}

Our i2s Moded code (non working) 

fatsd example (working)

  • Hello,

    alvaro torijano said:
    Try to disconnect SD reader module

    Which SD reader module are you using? Also which cc26x2 SDK version are you using? Have you tried porting the "i2secho" into "fatsd" example? I'm guessing that there is a problem the sysconfig / board files configuration.

    alvaro torijano said:
    /* On CC32XX, do not enable GPIO due to an LED/I2S pin conflict */
    #if !(defined(DeviceFamily_CC3200) || defined(DeviceFamily_CC3220) || defined(DeviceFamily_CC3235))

    Also, could you please confirm which device are you using? Is this a CC26x2 or a CC32xx?

      Thanks,

       David

  • Hello DavidL,

    I'm Alvaro's partner in this project. Thank you very much for your answer

    We are using CC26x2 board and last SDK version (4.10.00.78). We didn't try to import "i2secho" into "fatsd" example, but our next step in the project would be to import both examples into "simple_peripheral", so anyway, we need to import "fatsd". I will summarize how we worked with this project:

    First, we tested "i2secho" example using CC3200AUDBOOST board and works perfectly.

    Second, we tested "fatsd" example using custom micro SD board and works well for 2Gb SD card.

    Third, we imported "fatsd" example into "i2secho" (you can see code showed), copying needed functions and libraries to make the project works. Also we added to sysconfig GPIO, DMA, SD and SPI as it is in "fatsd" example (the checked hundred times and it is the same). Everything compiles well but SPI bus does not work (you can see that the rest of the program works well because I2S runs (D0, D1, D2, D3 of logic analyzer)

    We debugged few times and we thing that the problem is in src = fopen(inputfile, "r") (LINE 237). We also tryed with other commands instead of 'r', as src = fopen(inputfile, "w+") but does not work.

    I attach project file:

    i2secho_CC26X2R1_LAUNCHXL_tirtos_ccs.rar

    Thanks,

  • Hi Jorge,

      Sounds like a very cool project. But before jumping into the code, do you have a block diagram to understand how all the pieces go together?

    Or maybe a pin configuration list?

    Things become interesting when you start attaching them together, a good example is this TID - http://www.ti.com/tool/TIDM-1004  

    Jorge Herrera Santos1 said:
    Second, we tested "fatsd" example using custom micro SD board and works well for 2Gb SD card.

    Would it be possible to share more information on your micro SD board? 

       Best regards,

        David

  • Hello DavidL,

    DavidL said:

      Sounds like a very cool project. But before jumping into the code, do you have a block diagram to understand how all the pieces go together?

    Here you can see our block diagram:

    As you can see, there's no pin conflicts as you can see in the block diagram picture.

    DavidL said:

    Would it be possible to share more information on your micro SD board? 

    But the thing is that in "fatsd" example there's no problem to read/write files... Both examples works perfectly when tested separately. But when we join the code (fatsd into i2secho), SPI does not work.

    In picture below you can see SPI comparison between i2secho+fatsd (left) vs fatsd (right):

    Any idea of why the SPI transmission stops? Any suggestions?

    Best regards,

  • Hello Jorge,

      That's interesting, is your code hanging after this? Have looked into ROV to see if there is HW exceptions or any errors?

    Anyway, have you tried changing the initialization order? Initialize the SD card before the i2s, please wait until your are done with the SD initialization before initializing the i2s.

    Unfortunately, I do not have access to all of my boosterpacks at this time, so I'll not be able to try this on my side but hopefully we will be able to narrow this down with the ROV and switching the initialization order.

      Thanks,

       David