RTOS 001: SD-Card

Today we will be delving into the ThreadX RTOS using the FileX system to read and write to an SD-Card.

It took a very long time to get this code working. There are a lot of options you have to set, and some things you can’t do, or you break the code.

Also note that this code was built using SSP v1.1.3.

First create a new project using the S7G2-DK BSP (no RTOS included).

After the Synergy Configuration comes up, open the BSP tab, scroll down to the bottom of the Properties window and change RTOS being used from “No RTOS” to ThreadX.

On the Treads tab, add a new thread. Add the following components to the new thread:

Framework->File System->FileX on fx
Framework->File System->Block Media Framework on sf_block_media_sdmmc
Framework->File System->FileX Port Block Media Framework on sf_el_fx
Driver->Storage->SD/MMC Driver on r_sdmmc

If you are using SSP v1.1.3, if you add FileX on fx, it will add the other required components.

Lastly, you MUST add a Transfer Driver. For this example add a new Transfer Driver on r_dtc.

Select the SD/MMC driver and change the Channel to 0 (if defaults to 1). Also set the priority for all three ICU entries to Priority 13.

Select the g_fx_media and change Format media during initialization to Disabled. If this is enabled, the startup takes a LONG time. There is no quick format here, it is done sector by sector. Instead, put the SD Card in your computer or camera and do a quick format using the FAT file system.

The total sectors also does not need to be modified, although the number is probably incorrect. This is important if you do want to format the card.

You will also need to add a a UART Driver and configure it for Channel 8 with no DTC drivers (see earlier posts for details if you have not done this before).

Next you will need to set the DK’s switches.

The following switches should be ON:
S5-1 (DRAM)
S5-4 (PMOD)
S5-7 (JTAG)

S101-4 (SD)

All other switches should be OFF.

Add includes for stdio.h, string.h, and stdbool.h

#include "new_thread.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

Also add the following defines and functions for UART:

// Buffer Size
#define OUTPUT_BUFFER_SIZE 1024

// Buffers
char outputBuffer[OUTPUT_BUFFER_SIZE];

// Flags
volatile bool transmitComplete;

int _write(int file, char *buffer, int count);
int _write(int file, char *buffer, int count)
{
    // As far as I know, there isn't a way to retrieve how many
    // bytes were send on using the uart->write function if it does not return
    // SSP_SUCCESS (unless we want to use the tx interrupt function and a global counter
    // so, we will send each character one by one instead.
    int bytesTransmitted = 0;

    for (int i = 0; i < count; i++) { // Start Transmission transmitComplete = false; g_uart.p_api->write (g_uart.p_ctrl, (uint8_t const *) (buffer + i), 1);
        while (!transmitComplete)
        {
        }

        bytesTransmitted++;
    }

    return bytesTransmitted;
}

// Callback Function for UART interrupts
void user_uart_callback(uart_callback_args_t * p_args)
{
    // Get Event Type
    switch (p_args->event)
    {
        // Transmission Complete
        case UART_EVENT_TX_COMPLETE:
            transmitComplete = true;
        break;
        default:
        break;
    }
}

Inside the new_thread_entry function, we need to create some variables to hold the data we will read and write to the SD-Card as well as storing the filename:

    CHAR writeBuffer[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementu.";
    CHAR destFilename[] = "my_test_file.txt";
    UCHAR readBuffer[1024];
    ULONG bytesRead;
    UINT error;
    ULONG mediaSpaceAvailable;

Next, Open the UART, disable output buffering, clear the TTY100 screen, and print the lesson header.

    // Open UART
    g_uart.p_api->open (g_uart.p_ctrl, g_uart.p_cfg);

    // Disable Output Buffering
    setvbuf ( stdout, NULL, _IONBF, OUTPUT_BUFFER_SIZE);

    // Use TTY100 commands to clear screen and reset screen pointer
    printf ("\033[2J"); // Clear Screen
    printf ("\033[H"); // Return Home
    printf ("\033[3J"); // Clear Back Buffer

    // Print Header
    printf ("RTOS 001: SD-Card\r\n\r\n");

Next we will read the number of available bytes from the SD-Card and print out the information.

    // Media is opened during the auto-generated startup code (which sucks, it would be nice to have control over this).

    // Get the number of available bytes
    error = fx_media_space_available (&g_fx_media, &mediaSpaceAvailable);
    if (FX_SUCCESS != error)
    {
        printf ("An error occurred while accessing the media free space. Error Code: 0x%02x.", error);
        while (1)
            ;
    }

    printf ("Media Information\r\n");
    printf ("\tFree Space: %lu bytes\r\n", mediaSpaceAvailable);

Next, we will check if the file my_test_file.txt exists. If it does, we will open the file, read up to 1024 bytes, and print them to the screen. To ensure the printf works as expected, we will manually add a null terminator to the end of the read data.

    // Try to open our file for reading. If successful, read up to 1024 bytes and print them out.
    error = fx_file_open(&g_fx_media, &g_my_file, (CHAR *)destFilename, FX_OPEN_FOR_READ);
    if (FX_SUCCESS == error)
    {
        error = fx_file_read(&g_my_file, readBuffer, sizeof(readBuffer), &bytesRead);
        if (FX_SUCCESS == error)
        {
            readBuffer[bytesRead - 1] = '\0';
            printf("Read %lu bytes from %s. Contents: %s\r\n", bytesRead, destFilename, readBuffer);
            fx_file_close (&g_my_file);
        }
    }

We will now create the file for writing. If the file already exists, we will delete it, then re-create it.

    // There is no way to check if a file exists by filename (we can loop through each directory entry to see if the file exists)
    // So instead, we will try to create the file. If the method returns FX_ALREADY_CREATED, we know the file exists, so we
    // should delete it.
    //
    // Another approach would be to truncate the file then open it instead of delete and create
    printf ("\r\nCreating file %s...", (CHAR *)destFilename);

    error = fx_file_create (&g_fx_media, (CHAR *) destFilename);
    if (FX_ALREADY_CREATED == error)
    {
        printf ("ERROR\r\n\tFile exists. Deleting...");
        error = fx_file_delete (&g_fx_media, (CHAR *) destFilename);
        if (FX_SUCCESS != error)
        {
            printf ("ERROR!");
            while (1)
                ;
        }
        else
        {
            printf ("OK!\r\n");

            // We've deleted the file, so lets try to create it again
            printf ("Creating File...");
            error = fx_file_create (&g_fx_media, (CHAR *) destFilename);

        }
    }

    // Check if the file was created
    if (FX_SUCCESS != error)
    {
        printf ("ERROR!");
        while (1)
            ;
    }
    else
    {
        printf ("OK!\r\n");
    }

If everything has gone OK to this point, we can open the file for writing, write our data, then close the file, flush the SD-Card, and finally close the SD-Card.

    // Open the file for writing
    printf("Opening file %s for writing...", (CHAR * )destFilename);
    error = fx_file_open(&g_fx_media, &g_my_file, (CHAR * )destFilename, FX_OPEN_FOR_WRITE);
    if (FX_SUCCESS != error)
    {
        printf ("ERROR!");
        while (1)
            ;
    }
    else
    {
        printf ("OK!\r\n");
    }

    // Write the buffer to the file
    printf("Writing data to file...");
    error = fx_file_write (&g_my_file, &writeBuffer, strlen (writeBuffer));
    if (FX_SUCCESS != error)
    {
        printf ("ERROR!");
        while (1)
            ;
    }
    else
    {
        printf ("OK!\r\n");
    }

    // Close the file
    printf("Closing file...");
    error = fx_file_close (&g_my_file);
    if (FX_SUCCESS != error)
    {
        printf ("ERROR!");
        while (1)
            ;
    }
    else
    {
        printf ("OK!\r\n");
    }

    // Flush the media
    printf("Flushing Media...");
    error = fx_media_flush (&g_fx_media);
    if (FX_SUCCESS != error)
    {
        printf ("ERROR!");
        while (1)
            ;
    }
    else
    {
        printf ("OK!\r\n");
    }

    // Close Media
    printf("Closing Media...");
    error = fx_media_close (&g_fx_media);
    if (FX_SUCCESS != error)
    {
        printf ("ERROR!");
        while (1)
            ;
    }
    else
    {
        printf ("OK!\r\n");
    }

Finally, we will enter a loop and sleep.

    // Sleep
    while (1)
    {
        tx_thread_sleep (1);
    }

Now that we have a basic example going, here are a few observations. First, there are function definitions in the FileX API to list the contents of a directory and get the file/directory information for each entry.

For some reason however, if you do list the directory contents, it breaks the ability to open a file for reading. I’ve tried resetting the root directory, closing and reopening the media. Each time, the app either freezes or goes into the default error handler.

I’ll be contacting the Renesas support again and see if we can find out why things are not working as expected.

That’s it for today’s lesson! As always, the full code is on GitHub.

Advertisements

2 thoughts on “RTOS 001: SD-Card

  1. hi for this lesson on top, u say MUST add a Transfer Driver. For this example add a new Transfer Driver on r_dtc.
    but i never see u configuration for the dtc.
    can i know more about the DTC function?
    can use this function stay alone?
    quite and simple?
    thank you

    Like

    1. I haven’t dug much into the DTC objects yet. They were added in v1.1.0 and are also included in the UART module as well. Once I dig into them more, I’ll end up writing a post about them. At the moment I am focused on sensors.

      Thanks for reading! If you have any ideas for future posts, please let me know!

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s