We are implementing a datalogger function using the 16MB of built in QSPI. Our code is based on the samples provided at File System
After a variable amount of writes (something between 500 and 4000), the system hungs while performing fsWrite.Flush(). Then the only option is to reboot and Format the filesystem. Sometimes we have been able to write up to 10,000 records, but most of the time the problem happens earlier.
To simplify the analysis, we wrote a small program and run it on the 20260 development board. It is easy to replicate the problem, running the program 2 or 3 times.
Here is the code:
using System;
using System.Collections;
using System.Text;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Pins;
using System.IO;
using System.Diagnostics;
using GHIElectronics.TinyCLR.Native;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.Devices.Storage.Provider;
using GHIElectronics.TinyCLR.IO.TinyFileSystem;
using TinyCLRApplication1;
namespace TinyCLRApplication1
{
class Program
{
static void Main()
{
TFS_init();
TFS_listdir();
TFS_test(10000,100);
while (true)
{
Thread.Sleep(1000);
}
}
public sealed class QspiMemory : StorageDriver
{
public override int Capacity => 0x1000000;
public override int PageSize => 0x400;
public override int SectorSize => 0x1000;
public override int BlockSize => 0x10000;
private StorageController qspiController;
private IStorageControllerProvider qspiDrive;
public QspiMemory()
{
qspiController = StorageController.FromName(SC20260.StorageController.QuadSpi);
qspiDrive = qspiController.Provider;
qspiDrive.Open();
}
public override void EraseBlock(int block, int count)
{
if ((block + count) * BlockSize > Capacity) throw new ArgumentException("Invalid block + count");
var address = block * BlockSize;
for (var i = 0; i < count; i++)
{
qspiDrive.Erase(address, BlockSize, TimeSpan.FromSeconds(100));
address += BlockSize;
}
}
public override void EraseChip()
{
var block = this.Capacity / this.SectorSize;
var address = 0;
while (block > 0)
{
qspiDrive.Erase(address, SectorSize, TimeSpan.FromSeconds(100));
address += SectorSize;
block--;
}
}
public override void EraseSector(int sector, int count)
{
if ((sector + count) * SectorSize > Capacity) throw new ArgumentException("Invalid sector + count");
var address = sector * SectorSize;
for (var i = 0; i < count; i++)
{
qspiDrive.Erase(address, BlockSize, TimeSpan.FromSeconds(100));
address += SectorSize;
}
}
public override void ReadData(int address, byte[] data, int index, int count)
{
qspiDrive.Read(address, count, data, index, TimeSpan.FromSeconds(1));
}
public override void WriteData(int address, byte[] data, int index, int count)
{
qspiDrive.Write(address, count, data, index, TimeSpan.FromSeconds(1));
}
}
public static TinyFileSystem tfs = new TinyFileSystem(new QspiMemory());
public static long FreeMEM;
public static void TFS_init()
{
Debug.WriteLine("TFS_init. Inicializa TFS");
if (!tfs.CheckIfFormatted())
{
//Do Format if necessary
Debug.WriteLine("TFS_init. Formatea el TFS");
tfs.Format();
}
else
{
// Mount tiny file system
Debug.WriteLine("TFS_init. Monta el TFS");
tfs.Mount();
}
}
public static string TFS_listdir()
{
string rsp = "TFS Files:";
Debug.WriteLine(rsp);
var lista = tfs.GetFiles();
string[] file = lista;
for (int k = 0; k < file.Length; k++)
{
rsp += " " + file[k] + "(" + tfs.GetFileSize(file[k]).ToString() + ");";
Debug.WriteLine(" " + file[k]);
}
return rsp;
}
public static void TFS_writeLine(string archivo, string data)
{
Debug.WriteLine("TFS_writeLine. Archivo: " + archivo);
try
{
using (var fsWrite = tfs.Open(archivo, FileMode.Append))
{
using (var wr = new StreamWriter(fsWrite))
{
wr.WriteLine(data);
Debug.WriteLine("TFS_writeLine. wr.WriteLine Ejecutado OK");
wr.Flush();
Debug.WriteLine("TFS_writeLine. wr.Flush Ejecutado OK");
fsWrite.Flush();
Debug.WriteLine("TFS_writeLine. fsWrite.Flush Ejecutado OK");
}
}
}
catch (Exception e)
{
Debug.WriteLine("TFS_writeLine. ERROR: " + e.Message);
}
}
public static void TFS_test(int nreg, int lreg)
{
Debug.WriteLine("TFS_test. INICIO. NREG=" + nreg + " LREG=" + lreg);
var LED = GpioController.GetDefault().OpenPin(SC20260.GpioPin.PH10);
LED.SetDriveMode(GpioPinDriveMode.Output);
string data = "";
int k;
for (k = 0; k < lreg; k++)
{
data += "A";
}
FreeMEM = System.GC.GetTotalMemory(true);
Debug.WriteLine("TFS_test. INICIO WAIT. Memoria usada= " + FreeMEM);
for (k = 0; k < nreg; k++)
{
LED.Write(GpioPinValue.High);
Thread.Sleep(100);
Debug.WriteLine(" Registro: " + k.ToString("D6"));
TFS_writeLine("TEST.txt", data);
LED.Write(GpioPinValue.Low);
Thread.Sleep(100);
}
FreeMEM = System.GC.GetTotalMemory(true);
Debug.WriteLine("TFS_test. FIN WAIT. Memoria usada= " + FreeMEM);
}
}
}