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.

RTOS/TM4C123GH6PM: How to change the number of fatfs files that may be open concurrently.

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: SYSBIOS,

Tool/software: TI-RTOS

Using CCS I have written a C program to control a robot/metal lathe/chop-saw.

All of the I/O is interrupt driven and works very well.

The heart of the program consists of a command string interpreter.

The command strings can arrive by serial port or can be read from files on the SD card.

The interpreter reads commands round robin fashion from up to 10 open files and uses each file's position pointer as a virtual "program counter" so that such commands as ONGOTO, GOSUB, GOTO etc. have been quite easily implemented.

In effect it is a "multi tasking" interpreter. The whole thing works extremely well interpreting almost 5000 commands/sec, more than fast enough.

BUT, a problem arises whenever I try to open more than 7 files, i.e. a NULL is returned when it tries to open an 8th file.

Either I haven't specified enough of the right kind of RAM  in .CFG (stack or heap or wherever it is that the file buffers are located) OR

my attempts to change _FS_SHARE in ffconf.h are not taking effect even though I click on 'Build All' and 'Clean... Build the entire workspace"

What should I do to allow opening of up to 15 files concurrently?

Your help will be greatly appreciated. Thanks. Dave

p.s. Here's a sample of code my interpreter processes. When 'load' tries to open Q.BOB a NULL is returned.

  • Hi David,
    Your problem description is much deeper than what I know about the FATFS. Have you tried to increase the heap and stack size first and will be make a difference (i.e. allowing you to open the 8th file)?

    Can you also clarify if you are using the TI-RTOS FATFS and TI-RTOS SD Card drivers? If yes, then I will forward you question to our TI-RTOS experts for advice.
  • Hi Charles,

    I have tried maximizing first the heap, then the stack then both about equal but all to no effect.

    I'll attach my .cfg file. Maybe you can spot something I've messed up.

    In ffconf.h...

    #ifndef _FFCONF
    #define _FFCONF 8255 /* Revision ID */

    I edited these...


    #define _VOLUMES 1
    /* Number of volumes (logical drives) to be used. */

    #define _FS_SHARE 15 /* 0:Disable or >=1:Enable */
    /* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
    defines how many files can be opened simultaneously. */


    /cfs-file/__key/communityserver-components-multipleuploadfilemanager/3bfe50e9_2D00_41fa_2D00_4aec_2D00_be39_2D00_00708ddb1be3-150397-complete/BOB.cfg

    Thanks Charles
  • Hi David,
    You have not answered me if you are using TI-RTOS FATFS and TI-RTOS SD Card drivers. If you are using TI-RTOS can you send the .cfg file? Thanks.
  • Hi Charles,

    Here is a copy and paste of the .cfg.

    /*
     * Copyright (c) 2014, 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.
     */

    /*
     *  ======== fatsd.cfg ========
     */

    /* ================ General configuration ================ */
    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    //var Diags = xdc.useModule('xdc.runtime.Diags');
    //var Error = xdc.useModule('xdc.runtime.Error');
    //var Log = xdc.useModule('xdc.runtime.Log');
    var Main = xdc.useModule('xdc.runtime.Main');
    var Memory = xdc.useModule('xdc.runtime.Memory');
    var System = xdc.useModule('xdc.runtime.System');
    var Swi = xdc.useModule('ti.sysbios.knl.Swi');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    Clock.swiPriority = 7;
    Clock.timerId = 0;
    var Hwi = xdc.useModule('ti.sysbios.family.arm.m3.Hwi');
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var FatFs = xdc.useModule('ti.sysbios.fatfs.FatFS');
    var Seconds = xdc.useModule('ti.sysbios.hal.Seconds');
    //var LoggerRunMode = xdc.useModule('ti.uia.loggers.LoggerRunMode');
    //var TimestampProvider = xdc.useModule('ti.sysbios.family.arm.lm4.TimestampProvider');
    //var ti_sysbios_hal_Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
    /*
     *  Program.stack is ignored with IAR. Use the project options in
     *  IAR Embedded Workbench to alter the system stack size.
     */
    if (!Program.build.target.$name.match(/iar/)) {
        /*
         *  Reducing the system stack size (used by ISRs and Swis) to reduce
         *  RAM usage.
         */
    Program.stack = 4096;
    }

    Program.stack = 4096;
    /*
     * Comment this line to allow module names to be loaded on the target.
     * The module name strings are placed in the .const section. Setting this
     * parameter to false will save space in the .const section.  Error and
     * Assert messages will contain an "unknown module" prefix instead
     * of the actual module name.
     */
    Defaults.common$.namedModule = false;

    /*
     * Minimize exit handler array in System.  The System module includes
     * an array of functions that are registered with System_atexit() to be
     * called by System_exit().
     */
    System.maxAtexitHandlers = 2;

    /* ================ System configuration ================ */
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    System.SupportProxy = SysMin;

    /* Enable Semihosting for GNU targets to print to CCS console */
    if (Program.build.target.$name.match(/gnu/)) {
        var SemiHost = xdc.useModule('ti.sysbios.rts.gnu.SemiHostSupport');
    }
    System.extendedFormats = '%$L%$S%$F%f';
    /* ================ BIOS configuration ================ */
    /*
     * Disable unused BIOS features to minimize footprint.
     */
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    BIOS.libType = BIOS.LibType_Debug;
    /* Reduce the heap size */
    BIOS.heapSize = 13540;
    // BIOS.logsEnabled = true;
    // BIOS.assertsEnabled = true;

    var TIRTOS = xdc.useModule('ti.tirtos.TIRTOS');
    TIRTOS.libType = TIRTOS.LibType_NonInstrumented;
    TIRTOS.useSDSPI = true;
    TIRTOS.useGPIO = false;
    TIRTOS.useI2C = false;
    TIRTOS.useSPI = false;
    var clock4Params0 = new Clock.Params();
    clock4Params0.instance.name = "clock_ArmServos_Handle";
    clock4Params0.period = 10;
    clock4Params0.startFlag = false;
    Program.global.clock_ArmServos_Handle = Clock.create("&clock_ArmServos", 2, clock4Params0);
    var clock5Params0 = new Clock.Params();
    clock5Params0.instance.name = "clock_ScanningServo_Handle";
    clock5Params0.period = 50;
    clock5Params0.startFlag = false;
    clock5Params0.arg = null;
    Program.global.clock_ScanningServo_Handle = Clock.create("&clock_ScanningServo", 5, clock5Params0);
    var clock5Params1 = new Clock.Params();
    clock5Params1.instance.name = "clock_Location_Handle";
    clock5Params1.period = 100;
    clock5Params1.startFlag = false;
    Program.global.clock_Location_Handle = Clock.create("&clock_Location", 4, clock5Params1);
    var clock6Params = new Clock.Params();
    clock6Params.instance.name = "clock_MillisecTimer_Handle";
    clock6Params.period = 1;
    clock6Params.startFlag = false;
    Program.global.clock_MillisecTimer_Handle = Clock.create("&clock_MillisecTimer", 1, clock6Params);
    var clock6Params0 = new Clock.Params();
    clock6Params0.instance.name = "clock_PID_Handle";
    clock6Params0.period = 1;
    Program.global.clock_PID_Handle = Clock.create("&clock_PID", 1, clock6Params0);
    var clock7Params = new Clock.Params();
    clock7Params.instance.name = "clock_AtoDTimer_Handle";
    clock7Params.period = 10;
    clock7Params.startFlag = false;
    Program.global.clock_AtoDTimer_Handle = Clock.create("&clock_AtoDTimer", 3, clock7Params);
    var swi0Params = new Swi.Params();
    swi0Params.instance.name = "swiConvertAnalogValues_Handle";
    swi0Params.priority = 4;
    Program.global.swiConvertAnalogValues_Handle = Swi.create("&swiConvertAnalogValues", swi0Params);
    var task0Params = new Task.Params();
    task0Params.instance.name = "TheCoreTask_Handle";
    task0Params.stackSize = 5000;
    task0Params.priority = 1;
    Program.global.TheCoreTask_Handle = Task.create("&TheCoreTask", task0Params);
    var hwi0Params = new Hwi.Params();
    hwi0Params.instance.name = "UART1_ISR_Handle";
    hwi0Params.enableInt = true;
    hwi0Params.priority = 35;
    Program.global.UART1_ISR_Handle = Hwi.create(22, "&UART1_ISR", hwi0Params);
    var hwi1Params = new Hwi.Params();
    hwi1Params.instance.name = "UART5_PIXYCAM_ISR_Handle";
    hwi1Params.priority = 34;
    hwi1Params.enableInt = true;
    Program.global.UART5_PIXYCAM_ISR_Handle = Hwi.create(77, "&UART5_PIXYCAM_ISR", hwi1Params);
    var hwi2Params = new Hwi.Params();
    hwi2Params.instance.name = "ADC0_FIFO_Full_ISR_Handle";
    hwi2Params.priority = 33;
    Program.global.ADC0_FIFO_Full_ISR_Handle = Hwi.create(30, "&hwi_ADC0_FIFO_Full_ISR", hwi2Params);
    var hwi3Params = new Hwi.Params();
    hwi3Params.instance.name = "ADC1_FIFO_Full_ISR_Handle";
    hwi3Params.priority = 33;
    Program.global.ADC1_FIFO_Full_ISR_Handle = Hwi.create(64, "&hwi_ADC1_FIFO_Full_ISR", hwi3Params);

    Task.idleTaskVitalTaskFlag = false;
    Task.enableIdleTask = false;

  • Hi David,
    Thanks for the .cfg file. I will forward your question to our TI-RTOS experts for assistance.
  • Hi David,

    _FS_SHARE is for the number of threads that can share a file....not the number of unique files that be open. That is unlimited (per FatFS website)

    Filesystem type: FAT, FAT32(rev0.0) and exFAT(rev1.0).

    Number of open files: Unlimited. (depends on available memory)

    Number of volumes: Upto 10.

    Volume size: Upto 2 TB at 512 bytes/sector.

    File size: Upto 4 GB - 1 on FAT volume and virtually unlimited on exFAT volume.

    Cluster size: Upto 128 sectors on FAT volume and upto 16 MB on exFAT volume.

    Sector size: 512, 1024, 2048 and 4096 bytes.

    I think something else is going on. In a task, can you just have a loop that opens N unique files and see if that works?

    Todd

  • Hi Todd, re: "In a task, can you just have a loop that opens N unique files and see if that works?"

    Yes, this is what my program is doing...

    Now:

    Program.stack = 2048;

    task0Params.stackSize = 5000; (My one and only Task)

    BIOS.heapSize = 15360;

    SRAM Memory Allocation is 32,572(99%)

    More possibly relevant...

    I can 'load' 7 files into scriptList[]. Attempting to load an 8th causes 'false' to return from fileExists().

    Cheers

  • Is there any chance that the filename in the TOKENPTRS[] array for file number 7 is incorrect (ie a typo) and doesn't exist in the file system?

    Alan
  • Hi Alan,

    I tested this by swapping the order of P.BOB and Q.BOB in the 'load' parameter list.

    In that case Q.BOB gets loaded and fileExists() returns false when trying to open P.BOB.

    My heap use is practically non existent.

    The only use of it is for storing each scripts local variables and labels in linked lists.

    Here's a quite out of date image (but still capturing the essence) of what I'm attempting...

    Thanks Alan

    Cheers

  • As you are using the stand C library APIs, I think you're bumping into a C RTS library FOPEN_MAX limitation.

    If you can find the stdio.h file you're using, search for the definition of FOPEN_MAX. This should give you an idea of what needs to be done to increase the number of files you can have open simultaneously. I think it is likely to be 10. In your case, the first 3 are taken up by STDIN, STDOUT, and STDERR. Leaving 7 left for you. But that's just an educated guess...

    I found this info here:

    www.cplusplus.com/.../

    Alan
  • Hi Alan,

    Yes, FOPEN_MAX was set to 10. I changed it to 15... Here's a picture of the situation...

    In the mean time I've been working out the bugs and it's perfect now! (a statement that always makes my buddy laugh).

    I know, eventually, we'll figure it out.

    Thanks for the suggestions. I'm just about to read the 'cplusplus' link you gave.

    Cheers

    Dave

  • david genge said:
    Yes, FOPEN_MAX was set to 10. I changed it to 15... Here's a picture of the situation...

    I think you have to change _NSTREAM as well as _NFILE -  see Compiler/TMS320C6674: RTFS File Descriptors > 17 open at a time?

    The referenced thread is for the TI C6000 compiler, but think the same principal applies to the TI ARM compiler.

  • david genge said:
    Yes, FOPEN_MAX was set to 10. I changed it to 15...

    Given that the picture shows that _ftable only has 10 entries it looks like the compiler run time library wasn't re-built after _NFILE was changed.

    When a source file is changed in the compiler run time library source directory is changed, the library isn't automatically re-built when you build your CCS project. To force the run time library to be rebuilt after _NFILE and _NSTREAM have been increased:

    a. In the linker .map file of your project find a line of the following form which identifies which library file is used from the compiler:

        /home/mr_halfword/ti/ccs830/ccsv8/tools/compiler/ti-cgt-arm_18.1.4.LTS/lib/rtsv7M4_T_le_v4SPD16_eabi.lib

    b. Delete the above file.

    c. Re-build your CCS project and there should be output of the following form from the linker indicating that the library is being built:

    <Linking>
    warning #10366-D: automatic library build: using library "/home/mr_halfword/ti/ccs830/ccsv8/tools/compiler/ti-cgt-arm_18.1.4.LTS/lib/rtsv7M4_T_le_v4SPD16_eabi.lib" for the first time, so it must be built.  This may take a few minutes.
    Creating library /tmp/TI_MKLIB57mlHN/rtsv7M4_T_le_v4SPD16_eabi.lib

    See Mklib for more information on how the run time library is built.

  • Hi Chester,
    Yaaay! That worked. Thanks ever so much Chester.
    What I did:
    Found the directory containing the files 'file.h' and 'stdio.h' in
    C:\ti\ccsv6\tools\compiler\ti-cgt-arm_5.2.5\lib\src
    and
    edited 'stdio.h' changing the _NFILE entry value from 10 to 15.
    edited 'file.h' changing the _NSTREAM entry value from 10 to 15.
    In directory: C:\ti\ccsv6\tools\compiler\ti-cgt-arm_5.2.5\lib
    copied, renamed then deleted file:
    tsv7M4_T_le_v4SPD16_eabi.lib
    In Code Composer Studio.Project.Clean selected my project, pressed the "Build the entire workspace" option button and clicked the OK button.
    Then I clicked the 'Debug' button to burn the project into the TM4C123GH6PM flash.
    When I opened the Memory Browser and entered '_ftable', voila! - there were the fifteen entries. Wheeeeee.
    BUT
    When I returned to the editor and clicked the build button this happened...

    "error #10099-D: program will not fit into available memory. run placement with alignment fails for section "DATA_GROUP" size 0xb9a . Available memory ranges:
    SRAM size: 0x8000 unused: 0xb48 max hole: 0xb48
    error #10010: errors encountered during linking; "Rob0.out" not built
    >> Compilation failure
    gmake: *** [Rob0.out] Error 1
    gmake: Target `all' not remade because of errors."

    So my next question is:
    Where does the system place each of those 15 x 512 = 7,680 bytes of file buffers, System stack, Task stack, Heap or Regular RAM?
    Thanks a million Chester,
    Cheers
    Dave

    Update: I juggled the RAM so It's working now, at least the first test shows more than 7 files loading.

  • Hi Chester,
    Everything works wonderfully.
    I moved the array of 10 file pointers one each into each of the virtual CPUs.
    More appropriate location for 'program counters', yes.
    I'm clicking the 'This resolved my issue' now.
    Again, thanks very much for your very good help.
    Cheers
    Dave