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.

MSP430FR5994: need help understanding how a method in the out-of-box example works

Part Number: MSP430FR5994

Hello everyone

I need help understanding the sendDataSDCard() function method from the out-of-box example code for the MSP430FR5994 launchpad. The code is located in the SDCardLogMode translation unit and is copied below. This function reads a log file from the SD Card and sends it to a PC GUI app. My big two questions are

  1. How did sendDataSDCad() find an existing log file (it appears to create a new log) and
  2. Why are the first 5 strings discarded when the file is opened (assuming they are discarded) ?

My detailed walk through and understanding (immediately below) may help locate were I am confused (confusion is underneath in red).

 

  1. Assign HAL_SDCard callbacks to sdCardLib
  2. Check for sdcard
  3. Construct a logfile name by incrementing numLogFiles (a persistent variable)
  • Here is my first tripping point. Wouldn’t this be a new file with empty data?
  • If numLogFiles was reset somewhere before sendDataSDCard() then it could point to a real log file but (thankfully) doesn’t appear so.
  • If my understanding is wrong and this does point to an existing log file why are the first 5 strings discarded (assuming that they are)? Is it possible that this is a FatFs requirement when accessing a file? If not, the header below doesn’t look like it is 5 strings (but it’s possible that some unprintable characters (/r, /t, /n) were discarded).

“                              SDCard Logging Start Time: “ + Timestamp “temperature and Voltage (12-bit ADC raw data):”

  1. Open the file. If successful, set numData = 0. If not successful, then skip the next five f_gets() strings (up to 32 bytes) and then starts counting the number of remaining strings. Store count in numDat.
    • Is there anything to count?

2 Close the file

3 Condition GPIO pins for UART operation.

    • Is the 900000 cycle delay to allow the UART to finish transmitting? Why not poll the Tx Flag instead to allow for different Baud rates?

4 Send the numDat count to the PC GUI App.

    • The comment above says “send FRAM index”. No FRAM involved here. Maybe a residual from a copy n’ paste?

5 Open the file again and toss the next 5 buffers (strings)

    • The text files (read using a PC) don’t appear to have 5 strings before temp/voltage data.

6 Then for each string in numDat: Break into substrings using the “ “ delimiter. First substring holds both the timestamp and Temp reading. Second string holds only the battery voltage.

    • Is the comment “// Read TimeStamp from SDCard Log file” another stale copy n’ paste residual? It doesn’t make sense here.

thank you for your help

jim

void sendDataSDCard()
{
    //Plugin SDcard interface to SDCard lib
    SDCardLib_init(&sdCardLib, &sdIntf_MSP430FR5994LP);

    //Detect SD card
    SDCardLib_Status st = SDCardLib_detectCard(&sdCardLib);
    if (st == SDCARDLIB_STATUS_NOT_PRESENT) {
    	SDCardLib_unInit(&sdCardLib);
    	mode = '0';
    	noSDCard = 1;
    	return;
    }

    // Construct log file's name
    if (numLogFiles == 0) numLogFiles++;
    strcpy(filename, "data_log/log_");
    char num[5];
    itoa(numLogFiles, num, 10);
    strcat(filename, num);
    strcat(filename, ".txt");

    uint16_t numData = 0;

    rc = f_open(&fil, filename, FA_READ | FA_OPEN_EXISTING);
    if (rc) {
    	numData = 0;
    }
    else {
		f_gets(buffer, MAX_BUF_SIZE, &fil);
		f_gets(buffer, MAX_BUF_SIZE, &fil);
		f_gets(buffer, MAX_BUF_SIZE, &fil);
		f_gets(buffer, MAX_BUF_SIZE, &fil);
		f_gets(buffer, MAX_BUF_SIZE, &fil);

		while (f_gets(buffer, MAX_BUF_SIZE, &fil) != NULL)
		{
			numData++;
		}
    }

    rc = f_close(&fil);

	// Select UART TXD on P2.0
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN0, GPIO_SECONDARY_MODULE_FUNCTION);

    // Send FRAM Index
    EUSCI_A_UART_transmitData(EUSCI_A0_BASE, (uint8_t)((numData)>>8));
    EUSCI_A_UART_transmitData(EUSCI_A0_BASE, (uint8_t)(numData));

    __delay_cycles(900000);

    rc = f_open(&fil, filename, FA_READ | FA_OPEN_EXISTING);
    if (rc) {
    	f_close(&fil);
    	SDCardLib_unInit(&sdCardLib);
    	return;
    }

    f_gets(buffer, MAX_BUF_SIZE, &fil);
    f_gets(buffer, MAX_BUF_SIZE, &fil);
    f_gets(buffer, MAX_BUF_SIZE, &fil);
    f_gets(buffer, MAX_BUF_SIZE, &fil);
    f_gets(buffer, MAX_BUF_SIZE, &fil);

    uint16_t i;
    char *dataStr;
    int data;

    for (i=0;i<numData;i++)
    {
        // Reads TimeStamp from SDCard log file
        f_gets(buffer, MAX_BUF_SIZE, &fil);
        dataStr = strtok(buffer, " ");
        data = atoi(dataStr);
    	// Send logged Temperature Sensor ata
    	EUSCI_A_UART_transmitData(EUSCI_A0_BASE, (uint8_t)(data>>8));
    	EUSCI_A_UART_transmitData(EUSCI_A0_BASE, (uint8_t)(data));

        dataStr = strtok(NULL, " ");
        data = atoi(dataStr);
    	// Send logged Battery Monitor data
    	EUSCI_A_UART_transmitData(EUSCI_A0_BASE, (uint8_t)(data>>8));
    	EUSCI_A_UART_transmitData(EUSCI_A0_BASE, (uint8_t)(data));
    }
    rc = f_close(&fil);
    SDCardLib_unInit(&sdCardLib);

    GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN0);

    mode = '0';
}

 

  • > rc = f_open(&fil, filename, FA_READ | FA_OPEN_EXISTING);
    This tells me it expects these files to already exist. There must be code elsewhere which writes the files, which should tell you what the data format is.
  • Hi Bruce,
    the log files exist from a previous operations. the construct log file name code uses a persistent variable, numLogFiles, as a file counter to create names.
    If I assume that numLogFile holds the log number of the last file created by the previous operation, then a proper filename is constructed to access that last file. But if there are no files (an error) it increments the numLogFile count and creates a file name that doesn't exist. Downstream when f_open() doesn't find the file, it returns rc = 4 which sets numData to 0. Which I guess its OK if nothing is sent to PC GUI App but it seems strange to propagate an error downstream.
    The big stumbling area for me is when f_open() succeeds. Why does it issue the five f_gets() before counting the remaining buffers? The only thing I think of is that the SPI interface requires data to be sent in order to receive data and the five f_gets() provide enough SPI clks for the FatFS to send CMDs to retrieve file data. But this is a guess on my part which I am not comfortable with (the HAL_SDCARD seems to provide for these additional cycles to retrieve data but maybe there is more going on).
    It also seems that to f_read or f_write to the SDCard needs to be in 32 byte chunks (a sector size ?). But again, I haven't been able to confirm this. The storeLogMode() only writes a word at a time which seems fine. Still checking.
    do you have any insights to help guide me?

    thanks jim
  • I don't know anything about this application. I'm just going by the code you've posted and some history with ChaN's FATFS (which bears a "remarkable similarity").

    I don't see where this code creates any files. If the file it expects doesn't exist, it sends numData=0 to (I suppose) a Host PC, which then knows not to expect any more data.

    I encourage you to find the code that creates these log files (I suspect it's nearby) to see what the file format is.
  • Hi Bruce,
    first, thank you for trying to help. I figured it out. The five f_gets() advance the pointer to the start of data. f_gets() retrieves a string up to 32 bytes (including \0) or until it encounters a newline "\n". The header consists of five lines when counting by newlines - hence the 5 f_gets().

**Attention** This is a public forum