Table of Contents

File System


The file system library is a subset of the full .NET file system support. Most examples should work with only minor changes. The internal drivers fully support FAT16 or FAT32 file systems, with no limitations beyond the FAT file system itself!

Note

The USB drive must have an MBR record, not a GPT table. FAT16 and FAT32 file systems are supported.

Fat File System

USB Mass Storage

This allows file access on USB devices with MSC class, such as USB memory sticks. See the USB page.

SD Card

SD and MMC cards are fully supported as detailed on the SD tutorial page. Additionally, SPI SD drivers are also supported through the ManagedFileSystem software utility drivers.

The example below requires the GHIElectronics.TinyCLR.IO and GHIElectronics.TinyCLR.Devices.Storage libraries and a device with an SD card.

var sd = StorageController.FromName(SC20100.StorageController.SdCard);
var drive = FileSystem.Mount(sd.Hdc);

//Show a list of files in the root directory
var directory = new DirectoryInfo(drive.Name);
var files = directory.GetFiles();

foreach (var f in files) {
    System.Diagnostics.Debug.WriteLine(f.Name);
}

//Create a text file and save it to the SD card.
var file = new FileStream($@"{drive.Name}Test.txt", FileMode.OpenOrCreate);
var bytes = Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString() +
    Environment.NewLine);

file.Write(bytes, 0, bytes.Length);

file.Flush();

FileSystem.Flush(sd.Hdc);

Low-level Access

You can access the raw underlying data of the storage provider by using the Provider property of the controller. Be careful when using this interface, however, as it bypasses any file system present and writes directly to the device. This is useful for implementing your own or otherwise unsupported file systems.

var controller = StorageController.FromName
        (SC20100.StorageController.SdCard);

controller.Provider.Open(); // open
controller.Provider.Read(address, buffer, 0, buffer.Length, TimeSpan.FromSeconds(5));
controller.Provider.Close(); // close


Tiny File System (TFS)

Tiny File System(TFS) can be used to access any memory storage as a file system. All that is needed is a basic driver to Read, Write, and Erase these storages.

Below is an example that uses the external flash through TFS.

Note

This example requires the GHIElectronics.TinyCLR.IO.TinyFileSystem

const int CLUSTER_SIZE = 1024;

var tfs = new TinyFileSystem(new QspiMemory(), CLUSTER_SIZE);
            
if (!tfs.CheckIfFormatted()) {
    //Do Format if necessary 
    tfs.Format();
}
else {
    // Mount tiny file system
    tfs.Mount();
}

//Open to write
using (var fsWrite = tfs.Create("settings.dat")) {
    using (var wr = new StreamWriter(fsWrite)) {
        wr.WriteLine("This is TFS test");
        wr.Flush();
        fsWrite.Flush();
    }
}

//Open to read
using (var fsRead = tfs.Open("settings.dat", FileMode.Open)) {
    using (var rdr = new StreamReader(fsRead)) {
        System.String line;
        
        while ((line = rdr.ReadLine()) != null) {
                Debug.WriteLine(line);
        }
    }
}

Below is a basic driver implementation utilizing QSPI external flash. It automatically sets the size appropriately depending on whether the deployment is extended or not, as explained on the External Flash page. It however gives you the option to fix the size to 2MB, as the remaining 8MB can optionally be used by InField Update.

public sealed class QspiMemory : IStorageControllerProvider
{
    public StorageDescriptor Descriptor => this.descriptor;
    const int SectorSize = 4 * 1024;

    private StorageDescriptor descriptor = new StorageDescriptor()
    {
        CanReadDirect = false,
        CanWriteDirect = false,
        CanExecuteDirect = false,
        EraseBeforeWrite = true,
        Removable = true,
        RegionsContiguous = true,
        RegionsEqualSized = true,
        RegionAddresses = new long[] { 0 },
        RegionSizes = new int[] { SectorSize },
        RegionCount = (2 * 1024 * 1024) / (SectorSize)
    };

    private IStorageControllerProvider qspiDrive;

    public QspiMemory() : this(2 * 1024 * 1024)
    {

    }

    public QspiMemory(uint size)
    {
        var maxSize = Flash.IsEnabledExtendDeployment ? (10 * 1024 * 1024) : (16 * 1024 * 1024);

        if (size > maxSize)
            throw new ArgumentOutOfRangeException("size too large.");

        if (size <= SectorSize)
            throw new ArgumentOutOfRangeException("size too small.");

        if (size != descriptor.RegionCount * SectorSize)
        {
            descriptor.RegionCount = (int)(size / SectorSize);
        }

        qspiDrive = StorageController.FromName(SC20260.StorageController.QuadSpi).Provider;

        this.Open();
    }

    public void Open()
    {
        qspiDrive.Open();
    }

    public void Close()
    {
        qspiDrive.Close();
    }

    public void Dispose()
    {
        qspiDrive.Dispose();
    }

    public int Erase(long address, int count, TimeSpan timeout)
    {
        return qspiDrive.Erase(address, count, timeout);
    }

    public bool IsErased(long address, int count)
    {
        return qspiDrive.IsErased(address, count);
    }

    public int Read(long address, int count, byte[] buffer, int offset, TimeSpan timeout)
    {
        return qspiDrive.Read(address, count, buffer, offset, timeout);
    }

    public int Write(long address, int count, byte[] buffer, int offset, TimeSpan timeout)
    {
        return qspiDrive.Write(address, count, buffer, offset, timeout);
    }

    public void EraseAll(TimeSpan timeout)
    {
        for (var sector = 0; sector < this.Descriptor.RegionCount; sector++)
        {
            qspiDrive.Erase(sector * this.Descriptor.RegionSizes[0], this.Descriptor.RegionSizes[0], timeout);
        }
    }
}