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/EK-TM4C123GXL: USB pendrive data logging

Part Number: EK-TM4C123GXL
Other Parts Discussed in Thread: ENERGIA, CC2650

Tool/software: Code Composer Studio

Hello guys,

I'm trying to save data from TM4C123 to USB Pendrive. I need to log 7 inputs from a experimental off-road vehicle:

  • 4 Brake Discs temperatures (NTC sensors)
  • CVT temperature (PT100)
  • The engine RPM (pulses generated by a circuit containing a 555 timer)
  • Speed (utilizing an inductive sensor)

Haven't begun experimenting logging these yet, I need to understand better how can I put data to USB stick first. So I'm utilizing a code provided by  which can be found here:

https://github.com/krithik/tiva-usb-host-msc

I modified the code to put data into my pendrive (I use a external power source connected to GND and 5V pins, so no debugging). Here is a working example:

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

//------------------------------------------
// TivaWare Header Files
//------------------------------------------
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/rom.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/timer.h"
#include "driverlib/udma.h"
#include "driverlib/rom.h"
#include "driverlib/pin_map.h"
#include "ustdlib.h"
#include "usblib/usblib.h"
#include "usblib/usbmsc.h"
#include "usblib/host/usbhost.h"
#include "usblib/host/usbhmsc.h"
#include "third_party/fatfs/src/ff.h"
#include "third_party/fatfs/src/diskio.h"
#include "driverlib/uart.h"
#include "inc/hw_ints.h"
#include "utils/uartstdio.h"

bool deviceispresent = false;

static FIL g_sFileObject;

//
// Defines the size of the buffers that hold the path, or temporary
// data from the USB disk.  There are two buffers allocated of this size.
// The buffer size must be large enough to hold the int32_test expected
// full path name, including the file name, and a trailing null character.
//
//*****************************************************************************
#define PATH_BUF_SIZE   80

//*****************************************************************************
//
// Defines the number of times to call to check if the attached device is
// ready.
//
//*****************************************************************************
#define USBMSC_DRIVE_RETRY      4

//*****************************************************************************
//
// This buffer holds the full path to the current working directory.
// Initially it is root ("/").
//
//*****************************************************************************
static char g_cCwdBuf[PATH_BUF_SIZE] = "/";

//*****************************************************************************
//
// The following are data structures used by FatFs.
//
//*****************************************************************************
static FATFS g_sFatFs;
static DIR g_sDirObject;
static FILINFO g_sFileInfo;

//*****************************************************************************
//
// A structure that holds a mapping between an FRESULT numerical code,
// and a string representation.  FRESULT codes are returned from the FatFs
// FAT file system driver.
//
//*****************************************************************************

typedef struct
{
    FRESULT fresult;
    char *pcResultStr;
}
tFresultString;

//*****************************************************************************
//
// A macro to make it easy to add result codes to the table.
//
//*****************************************************************************
#define FRESULT_ENTRY(f)        { (f), (#f) }

//*****************************************************************************
//
// A table that holds a mapping between the numerical FRESULT code and
// it's name as a string.  This is used for looking up error codes and
// providing a human-readable string.
//
//*****************************************************************************
tFresultString g_sFresultStrings[] =
{
 FRESULT_ENTRY(FR_OK),
 FRESULT_ENTRY(FR_DISK_ERR),
 FRESULT_ENTRY(FR_INT_ERR),
 FRESULT_ENTRY(FR_NOT_READY),
 FRESULT_ENTRY(FR_NO_FILE),
 FRESULT_ENTRY(FR_NO_PATH),
 FRESULT_ENTRY(FR_INVALID_NAME),
 FRESULT_ENTRY(FR_DENIED),
 FRESULT_ENTRY(FR_EXIST),
 FRESULT_ENTRY(FR_INVALID_OBJECT),
 FRESULT_ENTRY(FR_WRITE_PROTECTED),
 FRESULT_ENTRY(FR_INVALID_DRIVE),
 FRESULT_ENTRY(FR_NOT_ENABLED),
 FRESULT_ENTRY(FR_NO_FILESYSTEM),
 FRESULT_ENTRY(FR_MKFS_ABORTED),
 FRESULT_ENTRY(FR_TIMEOUT),
 FRESULT_ENTRY(FR_LOCKED),
 FRESULT_ENTRY(FR_NOT_ENOUGH_CORE),
 FRESULT_ENTRY(FR_TOO_MANY_OPEN_FILES),
 FRESULT_ENTRY(FR_INVALID_PARAMETER),
};

//*****************************************************************************
//
// A macro that holds the number of result codes.
//
//*****************************************************************************
#define NUM_FRESULT_CODES (sizeof(g_sFresultStrings) / sizeof(tFresultString))

//*****************************************************************************
//
// Error reasons returned by ChangeToDirectory().
//
//*****************************************************************************
#define NAME_TOO_LONG_ERROR 1
#define OPENDIR_ERROR       2

//*****************************************************************************
//
// The number of SysTick ticks per second.
//
//*****************************************************************************
#define TICKS_PER_SECOND 100
#define MS_PER_SYSTICK (1000 / TICKS_PER_SECOND)

//*****************************************************************************
//
// A counter for system clock ticks, used for simple timing.
//
//*****************************************************************************
static uint32_t g_ui32SysTickCount;

//*****************************************************************************
//
// Holds global flags for the system.
//
//*****************************************************************************
static uint32_t g_ui32Flags = 0;


//*****************************************************************************
//
// Storage for the filenames.
//
//*****************************************************************************
#define NUM_LIST_STRINGS 48
const char *g_ppcDirListStrings[NUM_LIST_STRINGS];

//*****************************************************************************
//
// Storage for the names of the files in the current directory.  Filenames
// are stored in format "(D) filename.ext" for directories or "(F) filename.ext"
// for files.
//
//*****************************************************************************
#define MAX_FILENAME_STRING_LEN (4 + 8 + 1 + 3 + 1)
char g_pcFilenames[NUM_LIST_STRINGS][MAX_FILENAME_STRING_LEN];

//*****************************************************************************
//
// Storage for the strings which appear in the status box at the bottom of the
// display.
//
//****************************************************************************
#define NUM_STATUS_STRINGS 6
#define MAX_STATUS_STRING_LEN (36 + 1)
char g_pcStatus[NUM_STATUS_STRINGS][MAX_STATUS_STRING_LEN];


//*****************************************************************************
//
// Flag indicating that some USB device is connected.
//
//*****************************************************************************
#define FLAGS_DEVICE_PRESENT    0x00000001

//*****************************************************************************
//
// Hold the current state for the application.
//
//*****************************************************************************
volatile enum
{
    //
    // No device is present.
    //
    STATE_NO_DEVICE,

    //
    // Mass storage device is being enumerated.
    //
    STATE_DEVICE_ENUM,

    //
    // Mass storage device is ready.
    //
    STATE_DEVICE_READY,

    //
    // An unsupported device has been attached.
    //
    STATE_UNKNOWN_DEVICE,

    //
    // A mass storage device was connected but failed to ever report ready.
    //
    STATE_TIMEOUT_DEVICE,

    //
    // A power fault has occurred.
    //
    STATE_POWER_FAULT
}
g_eState;

//*****************************************************************************
//
// The size of the host controller's memory pool in bytes.
//
//*****************************************************************************
#define HCD_MEMORY_SIZE         128

//*****************************************************************************
//
// The memory pool to provide to the Host controller driver.
//
//*****************************************************************************
uint8_t g_pHCDPool[HCD_MEMORY_SIZE];


//*****************************************************************************
//
// The instance data for the MSC driver.
//
//*****************************************************************************
tUSBHMSCInstance *g_psMSCInstance = 0;

//*****************************************************************************
//
// Declare the USB Events driver interface.
//
//*****************************************************************************
DECLARE_EVENT_DRIVER(g_sUSBEventDriver, 0, 0, USBHCDEvents);

//*****************************************************************************
//
// The global that holds all of the host drivers in use in the application.
// In this case, only the MSC class is loaded.
//
//*****************************************************************************
static tUSBHostClassDriver const * const g_ppHostClassDrivers[] =
{
 &g_sUSBHostMSCClassDriver,
 &g_sUSBEventDriver
};

//*****************************************************************************
//
// This global holds the number of class drivers in the g_ppHostClassDrivers
// list.
//
//*****************************************************************************
static const uint32_t g_ui32NumHostClassDrivers =
        sizeof(g_ppHostClassDrivers) / sizeof(tUSBHostClassDriver *);

//*****************************************************************************
//
// The control table used by the uDMA controller.  This table must be aligned
// to a 1024 byte boundary.  In this application uDMA is only used for USB,
// so only the first 6 channels are needed.
//
//*****************************************************************************
#if defined(ewarm)
#pragma data_alignment=1024
tDMAControlTable g_psDMAControlTable[6];
#elif defined(ccs)
#pragma DATA_ALIGN(g_psDMAControlTable, 1024)
tDMAControlTable g_psDMAControlTable[6];
#else
tDMAControlTable g_psDMAControlTable[6] __attribute__ ((aligned(1024)));
#endif

//*****************************************************************************
//
// Define a pair of buffers that are used for holding path information.
// The buffer size must be large enough to hold the longest expected
// full path name, including the file name, and a trailing null character.
// The initial path is set to root "/".
//
//*****************************************************************************
#define PATH_BUF_SIZE   80

//*****************************************************************************
//
// Define the maximum number of files that can appear at any directory level.
// This is used for allocating space for holding the file information.
// Define the maximum depth of subdirectories, also used to allocating space
// for directory structures.
// Define the maximum number of characters allowed to be stored for a file
// name.
//
//*****************************************************************************
#define MAX_FILES_PER_MENU 64
#define MAX_SUBDIR_DEPTH 32


//----------------------------------------
// Prototypes
//----------------------------------------
void hardware_init(void);
static bool FileInit(void);
void SysTickHandler(void);
static const char *StringFromFresult(FRESULT fresult);
static void MSCCallback(tUSBHMSCInstance *ps32Instance, uint32_t ui32Event, void *pvData);
static int printFileStructure (void);

//---------------------------------------------------------------------------
// main()
//---------------------------------------------------------------------------
void main(void)
{
    uint32_t ui32DriveTimeout, ui32SysClock;

    //
    // Set the main system clock to run from the PLL at 50MHz
    // Processor clock is calculated with (pll/2)/4 - > (400/2)/4 = 50
    // NOTE: For USB operation, it should be a minimum of 20MHz
    //
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    //habilita TIMER0
    SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));

    //configura o TIMER0 como periódico
    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    //define o TIMER0 para zerar a contagem a cada 1s
    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() -1);

    //desabilita e limpa interrupções pendentes
    IntDisable(INT_TIMER0A);
    TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    IntPendClear(INT_TIMER0A);
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    //define prioridade ao interrupt que atualiza o painel
    IntPrioritySet(INT_TIMER0A, 0x20);

    //configura interrupt para gerar após o timeout (após zerar a contagem)
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    //habilita os interrupts
    IntEnable(INT_TIMER0A);

    //mantém num loop enquanto o interrupt não é habilitado
    while(!IntIsEnabled(INT_TIMER0A));

    //
    // Get the System Clock Rate
    // 50 MHz
    //
    ui32SysClock = SysCtlClockGet();

    // Enable USB0
    //
    // PB0 ---- USB ID ----> GND (Hardware)
    // PB1 ---- USB VBUS
    // PD4 ---- USB D+
    // PD5 ---- USB D-
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    SysCtlUSBPLLEnable();

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    //
    // Initialize the USB stack for host mode only.
    //
    USBStackModeSet(0, eUSBModeForceHost, 0);

    //
    // Register the host class drivers.
    //
    USBHCDRegisterDrivers(0, g_ppHostClassDrivers, g_ui32NumHostClassDrivers);

    //
    // Configure SysTick for a 100Hz interrupt.
    // Systick Period = 5000000 / 100 -> 500000
    //
    SysTickPeriodSet(SysCtlClockGet() / TICKS_PER_SECOND);
    SysTickEnable();
    SysTickIntEnable();

    //
    // Enable the uDMA controller and set up the control table base.
    // The uDMA controller is used by the USB library.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    uDMAEnable();
    uDMAControlBaseSet(g_psDMAControlTable);

    // Initialize UART0 (brought out to the console via the DEBUG USB port)
    // RX --- PA0
    // TX --- PA1
    // NOTE: Uses the UARTstdio utility
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTClockSourceSet(UART0_BASE, (UART_CLOCK_SYSTEM));
    UARTStdioConfig(0, 115200, SysCtlClockGet());
    IntEnable(INT_UART0);
    UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

    // Enable all Interrupts.
    IntMasterEnable();

    UARTprintf("Hardware Initialized\r\n");

    //
    // Initially wait for device connection.
    //
    g_eState = STATE_NO_DEVICE;

    //
    // Open an instance of the mass storage class driver.
    //
    g_psMSCInstance = USBHMSCDriveOpen(0, MSCCallback);

    //
    // Initialize the drive timeout.
    //
    ui32DriveTimeout = USBMSC_DRIVE_RETRY;

    //
    // Initialize the USB controller for host operation.
    //
    USBHCDInit(0, g_pHCDPool, HCD_MEMORY_SIZE);

    //
    // Initialize the fat file system.
    //
    FileInit();

    UARTprintf("FAT File System Module Initialized\r\n");

    //habilita ambos TIMERA e TIMERB
    TimerEnable(TIMER0_BASE, TIMER_A);

    char something[16];
    snprintf(something, sizeof(something), "Something,\r\n");

    //
    // Enter an (almost) infinite loop for reading and processing commands from
    // the user.
    //
    while(1)
    {
        //
        // Call the USB stack to keep it running.
        //
        USBHCDMain();

        switch(g_eState)
        {
        case STATE_DEVICE_ENUM:
        {
            //
            // Take it easy on the Mass storage device if it is slow to
            // start up after connecting.
            //
            if(USBHMSCDriveReady(g_psMSCInstance) != 0)
            {
                //
                // Wait about 500ms before attempting to check if the
                // device is ready again.
                //
                // 1 machine cycle takes (1/50*10^6) seconds
                // SysCtlDelay uses 3 machine cycles, so it would be 3*(1/50*10^6) seconds
                // Total Delay -> (Time Taken for 3 machine cycles) * Count Value
                //
                // Therefore, [(3/50*10^6) * (50*10^6/(3*2))] = 1/2 second
                //
                //
                SysCtlDelay(ui32SysClock / (3 * 2));

                //
                // Decrement the retry count.
                //
                ui32DriveTimeout--;

                //
                // If the timeout is hit then go to the
                // STATE_TIMEOUT_DEVICE state.
                //
                if(ui32DriveTimeout == 0)
                {
                    g_eState = STATE_TIMEOUT_DEVICE;
                }
                break;
            }

            UARTprintf("USB Mass Storage Device Ready\r\n");

            deviceispresent = true;

            //
            // Getting here means the device is ready.
            // Reset the CWD to the root directory.
            //
            g_cCwdBuf[0] = '/';
            g_cCwdBuf[1] = 0;

            //
            // Fill the list box with the files and directories found.
            //
            if(!printFileStructure())
            {
                //
                // If there were no errors reported, we are ready for
                // MSC operation.
                //
                g_eState = STATE_DEVICE_READY;
            }

            //
            // Set the Device Present flag.
            //
            g_ui32Flags = FLAGS_DEVICE_PRESENT;
            break;
        }

        //
        // If there is no device then just wait for one.
        //
        case STATE_NO_DEVICE:
        {
            if(g_ui32Flags == FLAGS_DEVICE_PRESENT)
            {
                //
                // Clear the Device Present flag.
                //
                g_ui32Flags &= ~FLAGS_DEVICE_PRESENT;
            }
            break;
        }

        //
        // An unknown device was connected.
        //
        case STATE_UNKNOWN_DEVICE:
        {
            //
            // If this is a new device then change the status.
            //
            if((g_ui32Flags & FLAGS_DEVICE_PRESENT) == 0)
            {
                // Indicate unknown device is present.
                UARTprintf("Unknown Device was connected \r\n");
            }

            //
            // Set the Device Present flag.
            //
            g_ui32Flags = FLAGS_DEVICE_PRESENT;
            break;
        }

        //
        // The connected mass storage device is not reporting ready.
        //
        case STATE_TIMEOUT_DEVICE:
        {
            //
            // If this is the first time in this state then print a
            // message.
            //
            if((g_ui32Flags & FLAGS_DEVICE_PRESENT) == 0)
            {
                // Indicate timeout when trying to connect
                UARTprintf("Unknown device \r\n");

            }

            //
            // Set the Device Present flag.
            //
            g_ui32Flags = FLAGS_DEVICE_PRESENT;
            break;
        }

        //
        // Something has caused a power fault.
        //
        case STATE_POWER_FAULT:
        {
            break;
        }
        default:
        {
            break;
        }
        }

        if(deviceispresent)
        {
            UINT bw;

            if(f_open(&g_sFileObject, "123.txt", FA_WRITE | FA_OPEN_ALWAYS) == FR_OK)
            {
                f_lseek(&g_sFileObject, g_sFileObject.fsize);
                f_write(&g_sFileObject, something, sizeof(something), &bw);
                f_close(&g_sFileObject);
            }
        }
    }
}


//*****************************************************************************
//
// Initializes the file system module.
//
// \param None.
//
// This function initializes the third party FAT implementation.
//
// \return Returns \e true on success or \e false on failure.
//
//*****************************************************************************
static bool FileInit(void) {
    //
    // Mount the file system, using logical disk 0.
    //
    if(f_mount(0, &g_sFatFs) != FR_OK)
    {
        return(false);
    }
    return(true);
}

//*****************************************************************************
//
// This is the handler for this SysTick interrupt.  It simply increments a
// counter that is used for timing.
//
//*****************************************************************************
void SysTickHandler(void) {
    //
    // Update our tick counter.
    //
    g_ui32SysTickCount++;
}

//*****************************************************************************
//
// This function returns a string representation of an error code
// that was returned from a function call to FatFs.  It can be used
// for printing human readable error messages.
//
//*****************************************************************************
static const char * StringFromFresult(FRESULT fresult) {
    uint32_t ui32Idx;

    //
    // Enter a loop to search the error code table for a matching
    // error code.
    //
    for(ui32Idx = 0; ui32Idx < NUM_FRESULT_CODES; ui32Idx++)
    {
        //
        // If a match is found, then return the string name of the
        // error code.
        //
        if(g_sFresultStrings[ui32Idx].fresult == fresult)
        {
            return(g_sFresultStrings[ui32Idx].pcResultStr);
        }
    }

    //
    // At this point no matching code was found, so return a
    // string indicating unknown error.
    //
    return("UNKNOWN ERR");
}

//*****************************************************************************
//
// This is the callback from the MSC driver.
//
// \param ui32Instance is the driver instance which is needed when communicating
// with the driver.
// \param ui32Event is one of the events defined by the driver.
// \param pvData is a pointer to data passed into the initial call to register
// the callback.
//
// This function handles callback events from the MSC driver.  The only events
// currently handled are the MSC_EVENT_OPEN and MSC_EVENT_CLOSE.  This allows
// the main routine to know when an MSC device has been detected and
// enumerated and when an MSC device has been removed from the system.
//
// \return None
//
//*****************************************************************************
static void MSCCallback(tUSBHMSCInstance *ps32Instance, uint32_t ui32Event, void *pvData) {
    //
    // Determine the event.
    //
    switch(ui32Event)
    {
    //
    // Called when the device driver has successfully enumerated an MSC
    // device.
    //
    case MSC_EVENT_OPEN:
    {
        //
        // Proceed to the enumeration state.
        //
        g_eState = STATE_DEVICE_ENUM;

        break;
    }

    //
    // Called when the device driver has been unloaded due to error or
    // the device is no longer present.
    //
    case MSC_EVENT_CLOSE:
    {
        //
        // Go back to the "no device" state and wait for a new connection.
        //
        g_eState = STATE_NO_DEVICE;

        //
        // Re-initialize the file system.
        //
        FileInit();

        break;
    }

    default:
    {
        break;
    }
    }
}


//*****************************************************************************
//
// This is the generic callback from host stack.
//
// pvData is actually a pointer to a tEventInfo structure.
//
// This function will be called to inform the application when a USB event has
// occurred that is outside those related to the mass storage device.  At this
// point this is used to detect unsupported devices being inserted and removed.
// It is also used to inform the application when a power fault has occurred.
// This function is required when the g_USBGenericEventDriver is included in
// the host controller driver array that is passed in to the
// USBHCDRegisterDrivers() function.
//
//*****************************************************************************
void USBHCDEvents(void *pvData) {
    tEventInfo *pEventInfo;

    //
    // Cast this pointer to its actual type.
    //
    pEventInfo = (tEventInfo *)pvData;

    //
    // Process each kind of event
    //
    switch(pEventInfo->ui32Event)
    {
    //
    // An unknown device has been connected.
    //
    case USB_EVENT_UNKNOWN_CONNECTED:
    {
        //
        // An unknown device was detected.
        //
        g_eState = STATE_UNKNOWN_DEVICE;
        break;
    }

    //
    // The unknown device has been been unplugged.
    //
    case USB_EVENT_DISCONNECTED:
    {
        //
        // Unknown device has been removed.
        //
        g_eState = STATE_NO_DEVICE;
        break;
    }

    //
    // A bus power fault was detected.
    //
    case USB_EVENT_POWER_FAULT:
    {
        //
        // No power means no device is present.
        //
        g_eState = STATE_POWER_FAULT;
        break;
    }

    default:
    {
        break;
    }
    }
}


//*****************************************************************************
// Prints the file structure on UART.
//*****************************************************************************
static int printFileStructure (void) {

    uint32_t ui32ItemCount;
    FRESULT fresult;

    //
    // Open the current directory for access.
    //
    fresult = f_opendir(&g_sDirObject, g_cCwdBuf);

    //
    // Check for error and return if there is a problem.
    //
    if(fresult != FR_OK)
    {
        //
        // Ensure that the error is reported.
        //
        UARTprintf("Error from USB disk:\r\n");
        UARTprintf((char *)StringFromFresult(fresult));
        UARTprintf("\r\n");
        return(fresult);
    }

    ui32ItemCount = 0;

    //
    // Enter loop to enumerate through all directory entries.
    //
    for(;;)
    {
        //
        // Read an entry from the directory.
        //
        fresult = f_readdir(&g_sDirObject, &g_sFileInfo);

        //
        // Check for error and return if there is a problem.
        //
        if(fresult != FR_OK)
        {
            UARTprintf("Error from USB disk:\r\n");
            UARTprintf((char *)StringFromFresult(fresult));
            UARTprintf("\r\n");
            return(fresult);
        }

        //
        // If the file name is blank, then this is the end of the
        // listing.
        //
        if(!g_sFileInfo.fname[0])
        {
            break;
        }

        //
        // Add the information on the console
        //
        if(ui32ItemCount < NUM_LIST_STRINGS)
        {
            usnprintf(g_pcFilenames[ui32ItemCount], MAX_FILENAME_STRING_LEN,
                      "(%c) %s", (g_sFileInfo.fattrib & AM_DIR) ? 'D' : 'F',
                              g_sFileInfo.fname);
            UARTprintf(g_pcFilenames[ui32ItemCount]);
            UARTprintf("\r\n");
        }

        //
        // Move to the next entry in the item array we use to populate the
        // list box.
        //
        ui32ItemCount++;
    }

    //
    // Made it to here, return with no errors.
    //
    return(0);
}

void Timer0IntHandler(void)
{
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
}

Now, I'm having many kinds of problems.

  • If I try to write anything to the USB pendrive outside main() function (e.g. timer ISR), the pendrive blinks indicating that is busy but no data is written into.
  • If I write a long string, like "1234567891011121314151617181982021222324252627282930\r\n", it writes garbage, like the print below:
  • If I write "Something,\r" with a char[25], it writes like this:
  • If I write a float using snprintf(something, sizeof(something), "%.4f\r\n", floatnum), it doesn't write anything. It wrote the "Something,", but after changing the string to a float, it stopped writing:

What I need is to generate this output:

Any help on that? Logging via USB seem the hardest thing to do on a Tiva...

And yes, I verified the qs-logger example many times. It's very hard to comprehend since there's a million things running together, I wonder why there's not a example for the EK boards.

Many thanks!

  • Helder Sales said:
    ...qs-logger example many times. It's very hard to comprehend since there's a million things running together

    Yet - the code you've "copied/pasted" (Not placed w/the Forum's "Syntax Highlighter") which renders the code far easier to read/absorb than the "dulled out" image you've provided) arrives with (many) of those same (near million things) objections - does it not?    

    Would it not make sense for you to request aid from that code's author?   (provided by )

    Many would place far more hope/faith in this vendor's code!    ("qs-logger" - as you note)       After proper review - you should be able to "disable and/or bypass" those elements of qs-logger - which are "outside your needs" and which add complication - should you not?      

    Your choice - instead - to adopt a (largely) unknown/unverified code source - which then evidences "issues" - and then to return (here) for rescue - proves circular (even poetic) - does it not?

  • cb1_mobile said:
    Yet - the code you've "copied/pasted" (Not placed w/the Forum's "Syntax Highlighter") which renders the code far easier to read/absorb than the "dulled out" image you've provided) arrives with (many) of those same (near million things) objections - does it not?

    Sorry, I didn't get it. You mean the screenshots or the code?

    cb1_mobile said:
    Would it not make sense for you to request aid from that code's author?   (provided by )

    Well, it is a "port of the usb msc example provided by TI for Connected Launchpad", so it shouldn't be too different. But never thought of that, honestly.

    cb1_mobile said:
    Many would place far more hope/faith in this vendor's code!    ("qs-logger" - as you note)       After proper review - you should be able to "disable and/or bypass" those elements of qs-logger - which are "outside your needs" and which add complication - should you not?

    Why can't just be a code for the EK boards? Reviewing the qs-logger is very difficult, I tried many times. I don't know where I'm doing wrong. Actually, my lack of knowlegde of USB might be the case, but I do not have the time nor the money to buy books to learn USB communications. It might seem exaggerated, but can't I have any realiable source, or just any help to comprehend the USB basics just to implement a simple logger? I don't need anything else with USB.

    Since there's almost no example of USB logging (found only energia and SD examples), I should do what? Persist at the qs-logger like there's no tomorrow? There might be a way, something I'm missing. Even a keyword would help maybe.

    P.S. I don't think I can follow KISS directive on this problem, or KISS dictates that I have to learn something before this?

  • Helder Sales said:
    Yet - the code you've "copied/pasted"

    When posting under "Use Rich formatting" - multiple "icon enhancements" appear above the post's data frame.    Third from the right, bottom row  " </> " enables you to insert the code w/Syntax "high-lighted" making it both darker, properly indented, thus far easier for your "helpers" to read.

    Helder Sales said:
    so it shouldn't be too different.

    Yet - it is long, and the code's contrast is dulled - AND - it does not meet your objectives.     Really - who (other than vendor staff here) or the alien code's author - is qualified to judge, "It shouldn't be too different."    That's highly wishful - you really should follow up w/the code's author.

    Helder Sales said:
    Why can't just be a code for the EK boards?

    Vendor employs its best judgement as to what best benefits their target audience.

    You note your struggle w/USB - but also your reluctance to admit "KISS" - to build (some) competence w/in USB.     Use of this forum's Search Box (up top) should reveal many poster questions - many "solutions" and seems a "KISS appropriate" method to assist you.

    You must think of your "helper audience."    Vendor agents KNOW this subject - the proper person can well assist w/"qs-logger" - I doubt they'd scan through the "mass of dulled out ALIEN code!"     (Alien code is both outside their experience & charter!)

    My intent is not to be mean/uncaring - I have offered multiple suggestions (such as contact the code's author - better still - review the various qs-logger postings - gleaned via forum's search box.)    BTW - that IS KISS - as you stray - so too your delay, frustration & on-going, lack of progress.  

  • cb1_mobile said:
    When posting under "Use Rich formatting" - multiple "icon enhancements" appear above the post's data frame.    Third from the right, bottom row  " </> " enables you to insert the code w/Syntax "high-lighted" making it both darker, properly indented, thus far easier for your "helpers" to read.

    But I inserted the code using that. I've copy/pasted and enabled "Collapse" option. I just don't know how to make it darker, you mean black background or something?

    cb1_mobile said:
    You must think of your "helper audience."    Vendor agents KNOW this subject - the proper person can well assist w/"qs-logger" - I doubt they'd scan through the "mass of dulled out ALIEN code!"     (Alien code is both outside their experience & charter!)

    I've overestimated them. I have no idea about their experience, but you have a point.

    cb1_mobile said:
    You note your struggle w/USB - but also your reluctance to admit "KISS" - to build (some) competence w/in USB.     Use of this forum's Search Box (up top) should reveal many poster questions - many "solutions" and seems a "KISS appropriate" method to assist you.

    My intent is not to be mean/uncaring - I have offered multiple suggestions (such as contact the code's author - better still - review the various qs-logger postings - gleaned via forum's search box.)    BTW - that IS KISS - as you stray - so too your delay, frustration & on-going, lack of progress.

    KISS has many faces it seems. I'll try reading the forum's posts, and contacting the code's author if everything else fails. It feels a shot in the dark, but I don't see any choice. I'll have to pass through headaches it seems, but nothing is for free, isn't it?

    No offense taken; I'm grateful that you took your time to point out what I'm doing wrong, even if it's not code related. There's much to learn besides programming it seems...

  • Helder Sales said:
    (Alien code is both outside their experience & charter!)

    Those are "my words" you've quoted - and surely vendor experience (must) center (and peak) around what's found here - not some (little/unknown/questionable) outside source.    Your word choice (overest) is unfair - and not diplomatic - what if  "all" posters sought such "unlimited read/review of  "alien code" - on a (near) daily basis?     Especially when the vendor has provided a reasonable & highly detailed (full project) example!     (this is what was meant by my guidance, "Think of your "helper audience.")      Vendor agents here are talented & experienced AND properly focused upon "their" devices - you seek to "deflect" them from their "sweet-spot!"  

    You appear to have, "given up" in the attempt to reach out to the alienware author - you "never know" - and such effort (may) make your request here (a bit) more acceptable.   (maybe)

    There appear to be multiple USB code examples w/in the API - your investigation should include these - as well.     (vendor's "clear" publicizing & listing of these examples (and other tech data) (may) require (some) re-think...)

    I'm not familiar w/ "qs-logger" - (my firm designs similar - but w/Cortex M7 - thus "no need/interest") - yet surely the code & hw supplied w/in that program should work.   (you note changes - I'd restart w/only the unmodified code - so that you & helpers start from - and remain upon - the same page!)

    As a small, tech biz owner - your initial post had all the earmarks of "avoidance" - fear of USB (likely) caused you to deflect/delay.       And when "starting late" - pressure builds - becomes highest - and the reach for "shortcuts" peaks - yet RARELY (i.e. almost never) Succeeds!   (especially when such shortcuts are "alien.")

    Your presentation of your "bit narrowed" attempt to "log to USB drive" - with key results and/or issues clearly presented - will (likely) prove far more enticing to vendor staff - than "endless complaints."    (that's my job)      Such methodical - step-by-step presentation - fully embodies "KISS" - and while vendor would (likely) never admit it - they too appreciate the "laser focus" & resultant clarity - which so often result...

  • cb1_mobile said:
    Those are "my words" you've quoted - and surely vendor experience (must) center (and peak) around what's found here - not some (little/unknown/questionable) outside source.    Your word choice (overest) is unfair - and not diplomatic - what if  "all" posters sought such "unlimited read/review of  "alien code" - on a (near) daily basis?     Especially when the vendor has provided a reasonable & highly detailed (full project) example!     (this is what was meant by my guidance, "Think of your "helper audience.")      Vendor agents here are talented & experienced AND properly focused upon "their" devices - you seek to "deflect" them from their "sweet-spot!"

    What I meant, and what I understood, is that vendor agents doesn't necessarily have all the knowledge to deal with "alien codes". I'm sure they're talented & experienced.

    cb1_mobile said:
    I'm not familiar w/ "qs-logger" - (my firm designs similar - but w/Cortex M7 - thus "no need/interest") - yet surely the code & hw supplied w/in that program should work.   (you note changes - I'd restart w/only the unmodified code - so that you & helpers start from - and remain upon - the same page!)

    But the example is for the $149 DK board, mine is the simpler EK version. I can't use it unmodified because I don't have the larger board. 

    cb1_mobile said:
    Your presentation of your "bit narrowed" attempt to "log to USB drive" - with key results and/or issues clearly presented - will (likely) prove far more enticing to vendor staff - than "endless complaints."    (that's my job)      Such methodical - step-by-step presentation - fully embodies "KISS" - and while vendor would (likely) never admit it - they too appreciate the "laser focus" & resultant clarity - which so often result...

    Thank you, I've learned that seeing countless "inadequate" posts (also their impacts on the problem's resolutions) and you recomendations. As for the highligher, how it is looking? My code is showing like this when expanded: 

  • Bom dia Helder,

    I believe you need to slice down your problem. You have a few different tasks for your goal:

    1) To write something into a USB stick already comprises two different tasks: configuring the USB-OTG as an external memory device, and to get a file system running.

    Did you succeed in getting the USB port to properly work a storage device? Do you understand the requirements for such and have you configured all what is needed?

    Did you elect a file system? I believe FAT is the most simple and universal available for the Tiva family, isn't that so? Did you decide on what kind of file you will use? How will that file be named, what will be the content's structure?

    After these two things are solved, see if you can save "HELLO USB CARD 01, HELLO USB CARD 02" to your stick and properly open that in your PC later.

    2) Dealing with your sensors readings:

    Do you have an internal structure for your sensors' values? This is NOT the same ASC thing that will be on your stick, agree? It is more likely to be a structure such as:

    {
    int32_t temp1;
    int32_t temp2;
    int32_t temp3;
    int32_t temp4;
    int32_t rpm;
    float speed;
    }

    More likely, each of your sensors will probably contain additional data that are internal only, but will not be needed in the final output log.

    After both items are solved and organized, then you can sprintf the structure into a clear looking ASC line, and save such line to your USB stick.

    Regards

    Bruno

  • Boa tarde Bruno,

    I do not understand all the things (like why there has to be a DMA set for USB, at least in the host_msc examples from DK123 and EK1294), and all the settings (backtracking all of them doesn't lead me to all the answers). But it did work at a certain point the program I'm using. It just doesn't work outside main() function, with long strings and passing floats to strings with snprintf() .

    I use the FAT32 format, can't use the FAT because I don't have a pendrive smaller than 8GB. I tested and saved the "HELLO USB CARD 01, HELLO USB CARD 02\r\n" with filename "123.txt":

    About the sensors, I've my other project split into various source and header files, to make it easier to isolate problems. The interrupt handlers are all separated, and I've 5 timers running into different speeds. One of them I'm using to pass the variables into a string and send it to UART (I'm planning to use the pendrive into this timer ISR).

    i'm using snprintf(string, sizeof(string), "%.4f,%.4f,%.4f,%.4f,%.4f,%02u,%02u,\r\n", g_temperaturaDisco1, g_temperaturaDisco1, g_temperaturaDisco1, g_temperaturaDisco1, g_temperaturaCVT, g_velocidade, g_rpm);


    There's an advantage using structs in this case? I never use them TBH.

  • Hi Helder,

    That's great to hear that a major part of the issue is solved. You ARE already able to write data to your usb key, in the proper FAT32 file format, and choose the filename you want.

    I can feel your pain about trying to understand some of the examples, particularly when they mix "obscure" things such as DMA... I am sure that, as examples, those programs have extremely unnecessary complexity! Can't you find just the actual "commands that do the things you need", and write your own SIMPLE "log to USB" high-level library from scratch using those commands?
    (As an example, consider the out-of-the box serial-to-bluetooth example that comes with CC2650 lauchpads: you'd be amazed to see how short the program to do that can actually be, compared to the myriad of interlocked files and uncalled routines of the original "multi-purpose" code!)

    As for the structure, I just find it easier to visualize and manage measurements (and sensor measurement IS the thing we do most in our company) when we put them all together in a organized structure. One aspect is really visual: it is easier to manage currentCarValues.disc1Temp, currentCarValues.cvtTemp, etc. A second point is that the use of a structure makes it easier to create other "instances" of your data, for example averageCarValues.disc1Temp, averageCarValues.cvtTemp, or maybe frozenScreenValues.disc1Temp while the "main current" values remain being updated and processed.

    Later, the structure can also be used to pass data to other boards or targets (we never convert binary numbers to text before transporting information, we use the original bytes carried exactly as they are stored in the defined structure). Of course that ain't the best solution to visualize something in a spreadsheet - but it is better for lots of other things, particularly avoiding to waste comm bandwidth.

    Saudações

    Bruno