Main Site Documentation

Project - Tiny File System


That is interesting, how do you interface to the FRAM chip?


Via SPI, just like Flash. But instead, FRAM has no sectors and is executed at bus speed, so no waiting for anything.


Oh yes, and virtually no wearing, as it handles 10^12 cycles.


@ Simon from Vilnius - That looks like a very interesting chip. And they even have a DIP version so I am definitely going to get one of those. Thanks for the info.


The driver has been compiled with the latest firmware. The code share now also includes the Gadgeteer module driver so that the Tiny Flash File system can be used with the flash module connected via the Gadgeteer designer in Visual Studio.


Nice :clap:


Thank you.


I have migrated this code to a GIT repository on codeplex. Going forward I will be publishing all updates to the codeplex repository.

The repository can be found at:


Cool! And as it’s been a while since I saw a bug in my FRAM chip driver, I post the code for it. Can you include it to Codeplex?

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace dotnetwarrior.NetMF.IO {
    /// <summary>
    /// BlockDriver for the FM25H20 FRAM chip (2Mb).
    /// </summary>
    /// <remarks>FRAM does not have any sectors or clusters, every byte is read/written at bus speed. So the sizes of sectors and clusters are somewhat arbitrary. </remarks>
    public class Fm25H20BlockDriver : IBlockDriver {
        private readonly SPI _spi;
        private readonly byte[] _bufferForErasing;

        /// <summary>
        /// Initializes a new instance of the <see cref="Fm25H20BlockDriver"/> class.
        /// </summary>
        /// <param name="spi">The SPI bus to use.</param>
        public Fm25H20BlockDriver(SPI spi) {
            if (spi == null) throw new ArgumentNullException("spi");
            _spi = spi;

            //To maintain compatibility with flash modules, I'll set FRAM bytes to 0xFF on erase. To save some cycles, I'll create a static buffer for that.
            _bufferForErasing = new byte[SectorSize];
            for (int i = 0; i < SectorSize; i++) {
                _bufferForErasing[i] = 0xFF;

        //===== Implementing IBlockDriver =====

        /// <summary>
        /// Full capacity of the device in bytes.
        /// </summary>
        public int DeviceSize { get { return 1024 * 256; } }

        /// <summary>
        /// The size in bytes of a sector on the device.
        /// </summary>  
        public int SectorSize { get { return 1024; } }

        /// <summary>
        /// The cluster size in bytes.
        /// </summary>    
        public ushort ClusterSize { get { return 256; } }

        /// <summary>
        /// Erases the entire device.
        /// </summary>
        public void Erase() {
            int count = DeviceSize / SectorSize;

            for (int i = 0; i < count; i++) {
                WriteToChip(i * SectorSize, _bufferForErasing, 0, _bufferForErasing.Length);

        /// <summary>
        /// Erases a sector on the device.
        /// </summary>
        /// <param name="sectorId">Sector to be erased.</param>
        public void EraseSector(int sectorId) {
            int address = sectorId * SectorSize;
            WriteToChip(address, _bufferForErasing, 0, _bufferForErasing.Length);

        /// <summary>
        /// Read a block of data from a cluster.
        /// </summary>
        /// <param name="clusterId">The cluster to read from.</param>
        /// <param name="clusterOffset">The offset into the cluster to start reading from.</param>
        /// <param name="data">The byte array to fill with the data read from the device.</param>
        /// <param name="index">The index into the array to start filling the data.</param>
        /// <param name="count">The maximum number of bytes to read.</param>
        public void Read(ushort clusterId, int clusterOffset, byte[] data, int index, int count) {
            int addressFrom = (clusterId * ClusterSize) + clusterOffset;
            if (addressFrom + count > DeviceSize) {
                throw new Exception("Past end of address space");

            ReadFromChip(addressFrom, data, index, count);

        /// <summary>
        /// Write a block of data to a cluster.
        /// </summary>
        /// <param name="clusterId">The cluster to write to.</param>
        /// <param name="clusterOffset">The offset into the cluster to start writting to.</param>
        /// <param name="data">The byte array containing the data to be written.</param>
        /// <param name="index">The index into the array to start writting from</param>
        /// <param name="count">The number of bytes to write.</param>
        public void Write(ushort clusterId, int clusterOffset, byte[] data, int index, int count) {
            int addressFrom = (clusterId * ClusterSize) + clusterOffset;
            if (addressFrom + count > DeviceSize) {
                throw new Exception("Past end of address space");
            WriteToChip(addressFrom, data, index, count);

        //===== Interfacing hardware =====
        private void ReadFromChip(Int32 addressFrom, byte[] bufferToHoldReadData, Int32 index, Int32 count) {
            //3 bytes is address, the rest is data
            _spi.WriteRead(new byte[] { 3, (byte)(addressFrom >> 16), (byte)(addressFrom >> 8), (byte)(addressFrom & 0xFF) }, 0, 4, bufferToHoldReadData, index, count, 4);
        private void WriteToChip(int addressFrom, byte[] bufferToWrite, Int32 index, Int32 count) {
            var bufferWithCommand = new byte[count + 4];
            bufferWithCommand[0] = 2;
            bufferWithCommand[1] = (byte)(addressFrom >> 16);
            bufferWithCommand[2] = (byte)(addressFrom >> 8);
            bufferWithCommand[3] = (byte)(addressFrom & 0xFF);
            Array.Copy(bufferToWrite, index, bufferWithCommand, 4, count);

            _spi.Write(new byte[] { 6 });


@ Simon from Vilnius - That is great, thank you very much!! I will add that into the repository as soon as possible. If you do not mind I will have to ask you to test it once I integrate it as I do not yet have an FRAM chip.


Ok, there are some more issues :slight_smile: I guess I should post it to Codeplex? Or here?


@ Simon from Vilnius - If you post it to codeplex it can be tracked better.


@ Simon from Vilnius - Did you see the comment I posted on the issue you raised on Codeplex?


Yes I saw. I’m just extremely busy these days. Will try to post the dump today/tommorow.


use your code, particularly I Block Driver and MX25l3206 Block Driver.
I would like to find a way try to optimize its burning speed…
I need to burn on the flash file with size of few MB, and important for me its speed.

after use the code, debugging the running, and check with scope the transactions of SPI protocol, I found there is quit large delay between 2 operations of write, what I should understand from the code, in this section:

class MX25l3206 Block Driver ,class MX25l3206,write date function:

          dataPage[0] = CMD_WRITE_PAGE;
          dataPage[1] = (byte)(address >> 16);
          dataPage[2] = (byte)(address >> 8);
          dataPage[3] = (byte)(address >> 0);
          Array.Copy(array, index + (i * PageSize), dataPage, 4, PageSize);

-the Array.copy operation.

someone have idea what to do, how to quick the speed, how to minimize the delays between the SPI write operations?


@ Chaya - Are you seeing that the Array.Copy call is taking a long time to complete?


Array.Copy takes 30 ms for 256 byte, it is a long time for me!, how can I short it? what “work around” I can do to save this time?
as I said, I have to burn 8mb, that says- 32768 Array.Coppy callings, 983040 ms!!


What should be if I pass my large array, when its size would be more the page-size?

-if dataPage .Length = 300 or more, when the 4 first bytes is the command??


I will have to fire up the Spider and test the speed of Array.Copy on a buffer of 256 bytes.

Have you tried just writting the data to the flash memory directly to get an indication of the speed of writting to the flash? I will do that as well, of course the files system does add overhead to the writes, so it will not be as fast as raw acces, this is the same for server class disks.


Just for reference, I read/write 12K in ~15ms using the SD Card on the F4.