FatFs with Kinetis

An SD (Secure Digital) Card interface is kind of standard for many applications today: it provides a lot of memory at a reasonable cost. Still, I need a software stack for it, up to the level of a file system. So far I was really happy with using FatFs: an open source FAT file system provided by Elm-Chan. I’m using the FatFs Processor Expert component already in multiple designs. What was missing: a port to the Freescale Kinetis ARM Cortex-M4 family of processors.

FatFs Architecture

FatFs is provided as set of open source files implementing the file system and block management:

FatFs Layers (Source: Elm-Chan)

FatFs Layers (Source: Elm-Chan)

To make things easy for an application (and programmer), I have Processor Expert components created which encapsulate the different blocks:

  1. FatFs module: the file system is implemented with the FAT_FileSystem component.
  2. Low level disk I/O: this performs read/write operations on the bus to the memory. For non-Kinetis this is implemented with the SD_Card component plus HW or SW SPI drivers; for Kinetis this is the FatFsMemSDHC component plus a SDHC_LDD driver.
  3. RTC: A Real Time Clock for time/date information, if files are written or changed on the disk. Here the GenericTimeDate component is used (see “There is a Time and Date for both Worlds”).

To verify my port, I have created an application with FatFs, FreeRTOS and a serial shell application.

Hardware

As hardware I use the TWR-K60N512 with the TWR-SER:

Tower System (TWR-K60N512, TWR-SER, TWR-ELE and P&E Multilink FX)

Tower System (TWR-K60N512, TWR-SER, TWR-ELEV and P&E Multilink FX)

The TWR-ELEV card provides power and a signal bus. The TWR-SER provides a serial connection to the host. As microcontroller card I use the TWR-K60N512, as it has a SD card slot on the backside of the card:

Back Side of Tower System with SD Card Slot

Back Side of Tower System with SD Card Slot

For debugging, CodeWarrior and the P&E Multilink Fx provide fast debugging and turnaround cycles.

Processor Expert Application

The application consist of multiple Processor Expert components:

Application with FatFs

Application with FatFs

Timeout Component

As many things can timeout working with SD cards, a special Timeout component is used. That component needs be ‘served’ by a timer interrupt, say every 10 ms (as specified in the Timeout component properties. This can be done e.g. with adding a TimerInt component and then call the AddTick() method from the interrupt event in Events.c:

void TI1_OnInterrupt(void)
{
  TMOUT1_AddTick();
}

💡 Alternatively a ‘shared’ interrupt event can be used, e.g. the TickTimer of an RTOS.

FAT_FileSystem Component

The FAT_FileSystem component implements the file system and offers typical file operations like reading and writing files:

FAT_FileSystem Component

FAT_FileSystem Component

In the properties many things of the file system are configured. One important thing is the ‘Memory’ property which implements the low-level disk I/O:

FAT_FileSystem Properties

FAT_FileSystem Properties

FatFsMemSDHC

For Kinetis, a new FatFsMemSDHC component implements the low-level disk I/O routines:

FatFsMemSDHC Component

FatFsMemSDHC Component

In the component properties, the speed, card detection and interfaces to other components are specified:

FatFsMemSDHC Properties

FatFsMemSDHC Properties

  • The component supports three Speed Mode: ‘slow‘ (max 400 kHz SPI clock) for card initialization, ‘normal‘ for normal operations after initialization (up to about 12 MHz SPI) and a ‘fast‘ speed for high-speed cards if supported by the card. The numbers are index values inthe the SDHC_LDD speed table (more about this below).
  • An optional Card Detect Pin: This references a GPIO_LDD component and field name. Additionally code for pin pullup select and pullup enable is provided.
  • Links to the SDHC and Timeout components complete the system interfaces.

The properties are mainly used in the driver Init() method:

%-BW_METHOD_BEGIN Init
%ifdef Init
%define! ParUserDataPtr
%define! RetVal
%include Common\FatFsMemSDHCInit.Inc
LDD_TDeviceData* %'ModuleName'%.%Init(LDD_TUserData *UserDataPtr)
{
  bool Error = FALSE;

  (void)UserDataPtr; /* not used */
  SD.SDHCPtr = 0;
%ifdef GPIO_LDD
  SD.GPIOPtr = 0;
%endif
  SD.Finished = FALSE;
  SD.Inserted = FALSE;
  SD.CardId = inherited.SDHC.NO_CARD;

%ifdef GPIO_LDD
  /* Enable pull-up on GPIO pin used for SD card detection */
  %CDPinSelectPullupCode
%CDPinEnablePullupCode
  SD.GPIOPtr = inherited.GPIO_LDD.Init(&SD);
%endif
  SD.SDHCPtr = inherited.SDHC.Init(&SD);
%ifdef GPIO_LDD
  SD.Inserted = (inherited.GPIO_LDD.GetFieldValue(SD.GPIOPtr, %CDFieldName) != 1);
%else
  SD.Inserted = FALSE;
%endif
  SD_Wait(&SD, &Error); /* Wait for card reset to finish */
  if (!Error && SD.Inserted) {
    if (inherited.SDHC.DetectCards(SD.SDHCPtr)!=ERR_OK) {
      Error = TRUE;
    }
    SD_Wait(&SD, &Error);
    if (!Error && SD.CardId != inherited.SDHC.NO_CARD) {
      /* card detected - selecting card... */
      Error = inherited.SDHC.SelectCard(SD.SDHCPtr, SD.CardId)!=ERR_OK;
      SD_Wait(&SD, &Error);
    }
    if (!Error) {
      /* card selected - requesting card info... */
      Error = inherited.SDHC.GetCardInfo(SD.SDHCPtr, &SD.CardInfo)!=ERR_OK;
      SD_Wait(&SD, &Error);
    }
    if (!Error) {
      /* switching gears for higher speed */
      Error = inherited.SDHC.SelectBusClock(SD.SDHCPtr, %'ModuleName'%.SPEED_INDEX_NORMAL)!=ERR_OK;
      SD_Wait(&SD, &Error);
    }
    if (!Error && SD.CardInfo.Caps.HighSpeed) {
      Error = inherited.SDHC.SelectBusClock(SD.SDHCPtr, %'ModuleName'%.SPEED_INDEX_FAST)!=ERR_OK;
      SD_Wait(&SD, &Error);
      /* running at high speed (high slew rate on all the SDHC pins should be set) */
    }
    if (!Error) {
      if (SD.CardInfo.Caps.DataWidths&LDD_SDHC_CARD_DATA_WIDTH_8_BIT) {
        Error = inherited.SDHC.SetDataWidth(SD.SDHCPtr, LDD_SDHC_CARD_DATA_WIDTH_8_BIT)!=ERR_OK;
      } else if (SD.CardInfo.Caps.DataWidths&LDD_SDHC_CARD_DATA_WIDTH_4_BIT) {
        Error = inherited.SDHC.SetDataWidth(SD.SDHCPtr, LDD_SDHC_CARD_DATA_WIDTH_4_BIT)!=ERR_OK;
      } else if (SD.CardInfo.Caps.DataWidths&LDD_SDHC_CARD_DATA_WIDTH_1_BIT) {
        Error = inherited.SDHC.SetDataWidth(SD.SDHCPtr, LDD_SDHC_CARD_DATA_WIDTH_1_BIT)!=ERR_OK;
      }
      SD_Wait(&SD, &Error);
      /* selected highest possible data width */
    }
  }
  return &SD;
}

%endif %- Init
%-BW_METHOD_END Init

After generating code, this produces the following C code:

/*
** ===================================================================
**     Method      :  FATM1_Init (component FatFsMemSDHC)
**
**     Description :
**         Initialization method
**     Parameters  :
**         NAME            - DESCRIPTION
**       * UserDataPtr     - Pointer to RTOS structure
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
LDD_TDeviceData* FATM1_Init(LDD_TUserData *UserDataPtr)
{
  bool Error = FALSE;

  (void)UserDataPtr; /* not used */
  SD.SDHCPtr = 0;
  SD.GPIOPtr = 0;
  SD.Finished = FALSE;
  SD.Inserted = FALSE;
  SD.CardId = SDHC1_NO_CARD;

  /* Enable pull-up on GPIO pin used for SD card detection */
  PORT_PDD_SetPinPullSelect(PORTE_BASE_PTR, 28, PORT_PDD_PULL_UP);
  PORT_PDD_SetPinPullEnable(PORTE_BASE_PTR, 28, PORT_PDD_PULL_ENABLE);
  SD.GPIOPtr = GPIO2_Init(&SD);
  SD.SDHCPtr = SDHC1_Init(&SD);
  SD.Inserted = (GPIO2_GetFieldValue(SD.GPIOPtr, SD_CARD_DETECT) != 1);
  SD_Wait(&SD, &Error); /* Wait for card reset to finish */
  if (!Error && SD.Inserted) {
    if (SDHC1_DetectCards(SD.SDHCPtr)!=ERR_OK) {
      Error = TRUE;
    }
    SD_Wait(&SD, &Error);
    if (!Error && SD.CardId != SDHC1_NO_CARD) {
      /* card detected - selecting card... */
      Error = SDHC1_SelectCard(SD.SDHCPtr, SD.CardId)!=ERR_OK;
      SD_Wait(&SD, &Error);
    }
    if (!Error) {
      /* card selected - requesting card info... */
      Error = SDHC1_GetCardInfo(SD.SDHCPtr, &SD.CardInfo)!=ERR_OK;
      SD_Wait(&SD, &Error);
    }
    if (!Error) {
      /* switching gears for higher speed */
      Error = SDHC1_SelectBusClock(SD.SDHCPtr, FATM1_SPEED_INDEX_NORMAL)!=ERR_OK;
      SD_Wait(&SD, &Error);
    }
    if (!Error && SD.CardInfo.Caps.HighSpeed) {
      Error = SDHC1_SelectBusClock(SD.SDHCPtr, FATM1_SPEED_INDEX_FAST)!=ERR_OK;
      SD_Wait(&SD, &Error);
      /* running at high speed (high slew rate on all the SDHC pins should be set) */
    }
    if (!Error) {
      if (SD.CardInfo.Caps.DataWidths&LDD_SDHC_CARD_DATA_WIDTH_8_BIT) {
        Error = SDHC1_SetDataWidth(SD.SDHCPtr, LDD_SDHC_CARD_DATA_WIDTH_8_BIT)!=ERR_OK;
      } else if (SD.CardInfo.Caps.DataWidths&LDD_SDHC_CARD_DATA_WIDTH_4_BIT) {
        Error = SDHC1_SetDataWidth(SD.SDHCPtr, LDD_SDHC_CARD_DATA_WIDTH_4_BIT)!=ERR_OK;
      } else if (SD.CardInfo.Caps.DataWidths&LDD_SDHC_CARD_DATA_WIDTH_1_BIT) {
        Error = SDHC1_SetDataWidth(SD.SDHCPtr, LDD_SDHC_CARD_DATA_WIDTH_1_BIT)!=ERR_OK;
      }
      SD_Wait(&SD, &Error);
      /* selected highest possible data width */
    }
  }
  return &SD;
}

SDHC_LDD

CodeWarrior with Processor Expert provides the SDHC_LDD component which implements a device driver for SD cards. The FatFsMemSDHC component inherits its methods and events:

SDHC_LDD Component

SDHC_LDD Component

In the properties, the interface and pin settings are configured:

SDHC_LDD Properties

SDHC_LDD Properties

The Bus Clock lists several values (‘list of values’) with corresponding speed index from the FatFsMemSDHC component from above:

Speed Modes in SDHC_LDD

Speed Modes in SDHC_LDD

Depending on the card speed capabilities, the Init() method of the FatFsMemSDHC component will switch gears:

if (!Error) {
  /* switching gears for higher speed */
  Error = SDHC1_SelectBusClock(SD.SDHCPtr, FATM1_SPEED_INDEX_NORMAL)!=ERR_OK;
  SD_Wait(&SD, &Error);
}
if (!Error && SD.CardInfo.Caps.HighSpeed) {
  Error = SDHC1_SelectBusClock(SD.SDHCPtr, FATM1_SPEED_INDEX_FAST)!=ERR_OK;
  SD_Wait(&SD, &Error);
  /* running at high speed (high slew rate on all the SDHC pins should be set) */
}

FSShell Component

The FSShell component is part of the appliction and provides a shell interface with file commands like listing the directory or deleting files:

FSShell Component

FSShell Component

In the properties it links to the FatFs, RTOS, Timer and Terminal/SCI connection:

FSShell Properties

FSShell Properties

Shell Application

To test the SD card support along with a benchmark, the following application code has been written:

/*
* Shell.c
*
*      Author: Erich Styger
*/
#include "PE_LDD.h"
#include "FRTOS1.h"
#include "Shell.h"
#include "FSSH1.h"
#include <string.h>

#define PL_HAS_SD_CARD  1 /* if we have SD card support */

#if PL_HAS_SD_CARD
/*! \brief Simple benchmark function: first we are going to write a file, then we will copy it */
static void benchmark(const FSSH1_StdIOType *io) {
  static FIL fp, fpDest;
  uint16_t i;
  UINT bw;
  uint8_t read_buf[10];
  TIMEREC time, startTime;
  int32_t start_mseconds, mseconds;

  /* write benchmark */
  FSSH1_SendStr((const unsigned char*)"Benchmark: open file, write 10k times 10 bytes (100'000 bytes), close file:\r\n", io->stdOut);
  FSSH1_SendStr((const unsigned char*)"Deleting any existing files...\r\n", io->stdOut);
  (void)FSSH1_DeleteFile((const unsigned char*)"./bench.txt", io);
  (void)FSSH1_DeleteFile((const unsigned char*)"./copy.txt", io);

  FSSH1_SendStr((const unsigned char*)"Creating benchmark file...\r\n", io->stdOut);
  (void)TmDt1_GetTime(&startTime);
  if (FAT1_open(&fp, "./bench.txt", FA_CREATE_ALWAYS|FA_WRITE)!=FR_OK) {
    FSSH1_SendStr((const unsigned char*)"*** Failed opening benchmark file!\r\n", io->stdErr);
    return;
  }
  for(i=0;i<10000;i++) {
    if (FAT1_write(&fp, "benchmark ", sizeof("benchmark ")-1, &bw)!=FR_OK) { FSSH1_SendStr((const unsigned char*)"*** Failed writing file!\r\n", io->stdErr);
      (void)FAT1_close(&fp);
      return;
    }
  }
  (void)FAT1_close(&fp);
  (void)TmDt1_GetTime(&time);
  start_mseconds = startTime.Hour*60*60*1000 + startTime.Min*60*1000 + startTime.Sec*1000 + startTime.Sec100*10;
  mseconds = time.Hour*60*60*1000 + time.Min*60*1000 + time.Sec*1000 + time.Sec100*10 - start_mseconds;
  FSSH1_SendNum32s(mseconds, io->stdOut);
  FSSH1_SendStr((const unsigned char*)" mseconds needed for command.\r\n", io->stdOut);

  /* read benchmark */
  FSSH1_SendStr((const unsigned char*)"Reading benchmark file...\r\n", io->stdOut);
  (void)TmDt1_GetTime(&startTime);
  if (FAT1_open(&fp, "./bench.txt", FA_READ)!=FR_OK) {
    FSSH1_SendStr((const unsigned char*)"*** Failed opening benchmark file!\r\n", io->stdErr);
    return;
  }
  for(i=0;i<10000;i++) {
    if (FAT1_read(&fp, &read_buf[0], sizeof(read_buf), &bw)!=FR_OK) {
      FSSH1_SendStr((const unsigned char*)"*** Failed reading file!\r\n", io->stdErr);
      (void)FAT1_close(&fp);
      return;
    }
  }
  (void)FAT1_close(&fp);
  (void)TmDt1_GetTime(&time);
  start_mseconds = startTime.Hour*60*60*1000 + startTime.Min*60*1000 + startTime.Sec*1000 + startTime.Sec100*10;
  mseconds = time.Hour*60*60*1000 + time.Min*60*1000 + time.Sec*1000 + time.Sec100*10 - start_mseconds;
  FSSH1_SendNum32s(mseconds, io->stdOut);
  FSSH1_SendStr((const unsigned char*)" mseconds needed for command.\r\n", io->stdOut);

  /* copy benchmark */
  FSSH1_SendStr((const unsigned char*)"Benchmark: copy file (100'000 bytes):\r\n", io->stdOut);
  FSSH1_SendStr((const unsigned char*)"Going to copy file...\r\n", io->stdOut);
  (void)TmDt1_GetTime(&startTime);
  (void)FSSH1_CopyFile((const unsigned char*)"./bench.txt", (const unsigned char*)"./copy.txt", io);
  (void)TmDt1_GetTime(&time);
  start_mseconds = startTime.Hour*60*60*1000 + startTime.Min*60*1000 + startTime.Sec*1000 + startTime.Sec100*10;
  mseconds = time.Hour*60*60*1000 + time.Min*60*1000 + time.Sec*1000 + time.Sec100*10 - start_mseconds;
  FSSH1_SendNum32s(mseconds, io->stdOut);
  FSSH1_SendStr((const unsigned char*)" mseconds needed for command.\r\n", io->stdOut);
  FSSH1_SendStr((const unsigned char*)"done!\r\n", io->stdOut);
}
#endif /* PL_HAS_SD_CARD */

/*!
* \brief Parses a command
* \param cmd Command string to be parsed
* \param handled Sets this variable to TRUE if command was handled
* \param io I/O stream to be used for input/output
* \return Error code, ERR_OK if everything was fine
*/
static uint8_t ParseCommand(const unsigned char *cmd, bool *handled, const FSSH1_StdIOType *io) {
  /* handling our own commands */
#if PL_HAS_SD_CARD
  if (UTIL1_strcmp((char*)cmd, FSSH1_CMD_HELP)==0) {
    FSSH1_SendHelpStr((const unsigned char*)"run benchmark", (const unsigned char*)"Run FatFS benchmark\r\n", io->stdOut);
    *handled = TRUE;
  } else if (UTIL1_strcmp((char*)cmd, "run benchmark")==0) {
    benchmark(io);
    *handled = TRUE;
  }
#endif
  return ERR_OK;
}

static portTASK_FUNCTION(ShellTask, pvParameters) {
  unsigned char cmd_buf[32];
#if PL_HAS_SD_CARD
  bool cardMounted = FALSE;
  static FAT1_FATFS fileSystemObject;
#endif

(void)pvParameters;
  FSSH1_Init();
  (void)FSSH1_ParseCommand((const unsigned char*)FSSH1_CMD_HELP, FSSH1_GetStdio(), ParseCommand);
  for(;;) {
#if PL_HAS_SD_CARD
    (void)FSSH1_CheckCardPresence(&cardMounted, 0 /* volume */, &fileSystemObject, FSSH1_GetStdio());
#endif
    (void)FSSH1_ReadAndParseCmd(cmd_buf, sizeof(cmd_buf), FSSH1_GetStdio(), ParseCommand /* local cmd parser */);
    FRTOS1_vTaskDelay(50/portTICK_RATE_MS);
    LED2_Neg();
  };
}

void SHELL_Init(void) {
if (FRTOS1_xTaskCreate(ShellTask, (signed portCHAR *)"Shell", configMINIMAL_STACK_SIZE+350, NULL, tskIDLE_PRIORITY+1, NULL) != pdPASS) {
  for(;;){} /* error */
}

Running the Application

Putting everything together will run multiple tasks on the board, one of it running the a console shell:

Example Application Session

Example Application Session

Source and Example Code

The Processor Expert components discussed is available from here. The example project sources are available here or with this direct link.

Happy FatFs’ing 🙂

198 thoughts on “FatFs with Kinetis

  1. Pingback: Virtual COM/USB CDC for OSBDM/OSJTAG | MCU on Eclipse

  2. Pingback: A Shell for the Freedom KL25Z Board | MCU on Eclipse

  3. First of all many a thanks for posting this.
    This is what I was exactly searching for.

    However when I downloaded the example code & tried to generate Processor Expert code as a first step…..I received error(s) like:
    Description Resource Path Location Type
    1.”ERROR: This component is not implemented in selected language & compiler! TWR-MK60_FreeRTOS LED1 Processor Expert Problem”
    Same error for LED2,LED3 and LED4
    2.”ERROR: This component is not implemented in this version! TWR-MK60_FreeRTOS Inhr3 Processor Expert Problem”
    Same problem for Inhr4, Inhr5 and Inhr6

    I am using “special Edition of CW10.2.2 & I ‘ve included all the necessary plugins-(I can see them under “Embedded Components)
    I’ve included all *.PEupd components.
    Basically my complier has objection to BITIO component of Processor Exert that you have included. I can see this component under Categories->CPU internal Peripherals->Port I/O
    Still there is an error………
    Any idea what could be wrong???

    Like

  4. Hi Erich
    Adding “LED” component helped…..THANKS for this !! (Though I’ve noticed that this still a low level component rather than LDD level abstration…..Anyways as of now it removes my error).

    Now there is one more error that I had not paid any heed to earlier:
    “ERROR: at line 2785: “RX Buffer”/RxBuffer has not assigned the component (file: Drivers\sw\FSShell.drv)”
    This is also received when I try to generate Processor Expert Code.
    This error is reported in one particular file in 12 lines & I don’t have slightest of the idea what’s it refering to?

    Like

  5. Pingback: Sports Timing System in a Lunch Box | MCU on Eclipse

  6. Pingback: Arduino Data-Logger Shield with the FRDM-KL25Z Board | MCU on Eclipse

  7. Hello Erich,

    thanks again for this great work. Just some lines for confirm that this component works fine with my “old” GB60.

    Regards,
    Juan A Luna
    Barcelona

    Like

  8. First – thanks for this blog. **Fantastic** work.
    So I imported your TWR_K70F120M_FatFS project into CW10.3 and got three errors:

    ERROR: at line 96: Unknown macro: “existsRoute” (file: Drivers\Kinetis\SDHC_LDD.rgi) TWR-K70F120M_FatFS SDHC1 Processor Expert Problem

    Got the exact same error Line 103, line 111, and line 96.
    Just grabbed this off github today.
    Best,
    Marc

    Like

    • sorry to pollute your blog… so after I restarted CW, those errors were gone. So maybe, advise people to restart CW after adding all the CW components. But now something else, error in linking (mingw… yecch!):

      C:\Freescale\CW MCU v10.3\gnu\bin\mingw32-make -j8 all
      ‘Building target: TWR-K70F120M_FatFS.afx’
      ‘Executing target #19 TWR-K70F120M_FatFS.afx’
      ‘Invoking: ARM Linker’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwldarm” @@”TWR-K70F120M_FatFS.args” -o “TWR-K70F120M_FatFS.afx”
      mingw32-make: *** [TWR-K70F120M_FatFS.afx] Error -1073741811

      Like

      • Hi Marc,
        ok, let me try the same on my machine today again. But there is no other error message or information in the console view? It happens to me that sometimes the error is multiple lines above the end of the output.

        Like

        • Hi Marc,
          I tried it on my end, and it works.
          Could you check your complete console output? Additionally, I know that GNU/Ming might have problems if the paths are too big. Try if it helps if you have your workspace/project closer to the drive root, e.g. in ‘C:\tmp\projects’, and not deep in a long path.

          Like

      • now comes the fun part… why is the benchmark so slow? I’m getting read speed of 40KB/s and write speed of half that…. with a sandisk ultra microSDHC claiming 30MB/s write speeds…
        I tried changing the interface from 1 to 4 bits, and changing the clock speed table for the SDHD component (had 2 entries, 375KHz/10.5MHz, changed it to 375KHz/12.5MHz/60MHz) and upping the interrupt priority from medium to high, and I get exactly the same benchmark result…?!

        CMD> File System mounted
        Card type : SD1
        Sector count : 5523840
        Sector size : 512
        READ_BL_LEN : 512
        High capacity: yes
        High speed : yes
        Low voltage : no
        Data widths : 1 4
        Operations : BlockRead BlockErase WriteProtect
        Benchmark: open file, write 10k times 10 bytes (100’000 bytes),
        close file:
        Deleting existing benchmark files…
        Creating benchmark file…
        4290 ms needed for creating file.
        Reading benchmark file…
        2490 ms needed reading.
        Copy file (100’000 bytes)…
        6260 ms needed for copy file.
        done!
        CMD>

        Like

      • Hi Eric,
        thanks for the datalogger link, lots of useful info re: SD on there!
        From the comments I gather you had the same problem where 1/4 bit data path made no difference… and it looks like there are some other driver inefficiencies and so forth… but I would expect that a processor with a specific SDHC interface (as opposed to simple SPI) should attain respectable write speeds. About 8 years ago I benchmarked the LPC3180 running uClinux at about 3MB/s, and the i.MX31 running linux at 30MB/s, both using the iozone benchmark program recompiled. The Kinetis UM’s claim impressive raw speed and the SDHC peripheral is well featured, so I have to think it’s possible to get usable speeds…. I’m going to try your K60F120 project now (your mastery of this stuff is showing, you turned that around at light speed!)
        Thanks again!!

        Like

      • new project works well (K60F120M)…. did some mods on the benchmark to try bigger read/write buffer, but hit a wall in compilation:

        Description Resource Path Location Type
        ERROR: at line 103: Unknown macro: “existsRoute” (file: Drivers\Kinetis\SDHC_LDD.rgi) TWR-K60F120M_FatFS SDHC1 Processor Expert Problem
        ERROR: at line 111: Unknown macro: “existsRoute” (file: Drivers\Kinetis\SDHC_LDD.rgi) TWR-K60F120M_FatFS SDHC1 Processor Expert Problem
        ERROR: at line 96: Unknown macro: “existsRoute” (file: Drivers\Kinetis\SDHC_LDD.rgi) TWR-K60F120M_FatFS SDHC1 Processor Expert Problem

        Like

      • it was read_buf inside FAT1_Benchmark, but as a further testament to me not knowing what I’m doing I went to re-check and the code of course is gone, I noticed that FAT1.c is in a folder called ‘generated code’… aha, this PE system I guess, so again I learn the hard way… in any case that shows that the compiler error has nothing to do with the mod, but also probably why there’s no change when I change SDHC parameters.
        Anyhow what my plan was, to change read_buf to (actually defined so I can change it later) 2048 and use it for writing and reading, and also have a couple more timers vars to time just the read/write portions and check the results before diving deeper into the stack….

        Like

      • ok I’m back at this…. so I found where the benchmark program is in FatFilesystem.drv and edited that file, put in an ifndef so I could make an external version of the benchmark (line 2847):

        /*! \brief Simple benchmark function: first we are going to write a file, then we will copy it */
        #ifndef EXTERNAL_FAT_BENCHMARK
        byte %’ModuleName’%.%Benchmark(const %@Shell@’ModuleName’%.StdIOType *io)
        ….

        So then I basically cut n pasted your benchmark and modified it, and made a predefined symbol in the project properties to define EXTERNAL_FAT_BENCHMARK. So far so good.

        I modified your benchmark (i can send you the code if you want? no way to post a file here…) to vPortMalloc an array of 4096 bytes, and filled that with printable characters, and wrote that enough times to make a 1MB file. I added time captures around the actual write as well, so I could get a more accurate write (same on read) time, excluding file open and close.

        So I ran that and got:
        ——
        Custom Benchmark: open file, write 1048576 bytes in 4096 byte blocks, close file:
        Deleting existing benchmark files…
        Creating & writing benchmark file…
        28660 ms total for creating file of which 27560 ms for actual wr
        ite (38047 B/s)
        Reading benchmark file…
        23810 ms total for opening & reading file of which 23800 ms for
        actual read (44057 B/s)
        Copy file…
        53530 ms needed for copy file (19588 B/s)
        done!
        ——-

        So basically, the same times!
        Then, I configured my K60’s PLL1 to 100MHz and set up the SDHC peripheral to use that clock, and set up the 3 speeds to be 390KHz, 25MHz, 50MHz and tried that:

        ——
        Custom Benchmark: open file, write 1048576 bytes in 4096 byte blocks, close file:
        Deleting existing benchmark files…
        Creating & writing benchmark file…
        28590 ms total for creating file of which 27520 ms for actual wr
        ite (38102 B/s)
        Reading benchmark file…
        23820 ms total for opening & reading file of which 23810 ms for
        actual read (44039 B/s)
        Copy file…
        53300 ms needed for copy file (19673 B/s)
        done!

        ——–
        So basically, no difference. So maybe the SDHC peripheral isn’t switching speeds? Or the block size (of your read/write call) doesn’t matter? Or there’s some big delays somewhere else?

        Like

        • Hi Marc,
          I simply have not had the time to dig into this, so thanks for the work on your side. Yes, I was disappointed as well, and first version with FatFS even had half of performane we both see now. I had filed a service request to Freescale about the fact that I did not see any improvements to use more pins on the SDHC: I received a response, but I’m deliquent that I was not able to follow up on it an to try out things. I believe the problems might be on different levels: at least on SPI connection I planned to have a look at the transfer cycles if there is anyhting to be improved. I made some changes a while back to use block transfers, and this improved performance for about 10%. I think having a hard look at the code will get some better results. Another thing is: a reader of this blog reported me that the Processor Expert SDHC layer has room for improvements too.

          Like

        • Hi Marc,
          here is what I received as answer (maybe it helps):
          SDHC_LDD component seems not to take advantage of 4pin vs 1pin mode
          I have made some performance tests and here are the achieved results:
          16 x 512 bytes block per transfer (sequence of 8192 bytes)
          – read in 1 ms (8192 B / 0,001 s = 7,8125 MB/s)
          – written in 12 ms (8192 B / 0,013 s = aprox. 615 kB/s)
          Settings:
          Bus clock set in run-time to 25 MHz
          Buffers/Transfer buffer table size set to 16
          Code:
          bool Error = FALSE;
          const uint16_t BlockSize = 512;
          const uint16_t BlockCount = 16;
          uint32_t CardAddr = SD_ByteToCardAddress(&SD->CardInfo, Address); /* Read block address */
          LDD_SDHC_TBufferDesc BufferDesc[BlockCount];
          uint32_t Index;

          /* Init read buffer descriptors */
          for (Index = 0; Index SDHCPtr, LDD_SDHC_READ, CardAddr, &BufferDesc, BlockCount);
          SD_Wait(SD, &Error);
          Note:
          I will add this example to the component’s Typical usage section in the documentation. Probably it is more typical than writing one block.

          Like

    • I realized my workspace path had spaces in it (lamenting the fact that in 2013, tools still can’t handle that…) and re-imported the project to (still long-ish) path with no spaces…. no improvement but here’s the log. Then I imported it to a workspace with a very short path (C:\cw10_workspace – btw always importing into workspace), that’ll be below. First the full log:

      **** Build of configuration MK70FN1M0_INTERNAL_FLASH for project TWR-K70F120M_FatFS ****

      C:\Freescale\CW MCU v10.3\gnu\bin\mingw32-make -j8 all
      ‘Building file: ../Sources/Events.c’
      ‘Building file: ../Sources/ProcessorExpert.c’
      ‘Building file: ../Sources/UART.c’
      ‘Building file: ../Generated_Code/Cpu.c’
      ‘Building file: ../Generated_Code/FAT1.c’
      ‘Building file: ../Generated_Code/FATM1.c’
      ‘Building file: ../Generated_Code/GPIO1.c’
      ‘Building file: ../Generated_Code/PE_LDD.c’
      ‘Executing target #1 ../Sources/Events.c’
      ‘Executing target #2 ../Sources/ProcessorExpert.c’
      ‘Executing target #3 ../Sources/UART.c’
      ‘Executing target #4 ../Generated_Code/Cpu.c’
      ‘Executing target #5 ../Generated_Code/FAT1.c’
      ‘Executing target #6 ../Generated_Code/FATM1.c’
      ‘Executing target #7 ../Generated_Code/GPIO1.c’
      ‘Executing target #8 ../Generated_Code/PE_LDD.c’
      ‘Invoking: ARM Compiler’
      ‘Invoking: ARM Compiler’
      ‘Invoking: ARM Compiler’
      ‘Invoking: ARM Compiler’
      ‘Invoking: ARM Compiler’
      ‘Invoking: ARM Compiler’
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Sources/Events.args” -o “Sources/Events_c.obj” -c “../Sources/Events.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Sources/ProcessorExpert.args” -o “Sources/ProcessorExpert_c.obj” -c “../Sources/ProcessorExpert.c” -MD -gccdep
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Sources/UART.args” -o “Sources/UART_c.obj” -c “../Sources/UART.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/Cpu.args” -o “Generated_Code/Cpu_c.obj” -c “../Generated_Code/Cpu.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/FAT1.args” -o “Generated_Code/FAT1_c.obj” -c “../Generated_Code/FAT1.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/FATM1.args” -o “Generated_Code/FATM1_c.obj” -c “../Generated_Code/FATM1.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/GPIO1.args” -o “Generated_Code/GPIO1_c.obj” -c “../Generated_Code/GPIO1.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/PE_LDD.args” -o “Generated_Code/PE_LDD_c.obj” -c “../Generated_Code/PE_LDD.c” -MD -gccdep
      ‘Finished building: ../Sources/UART.c’
      ‘ ‘
      ‘Building file: ../Generated_Code/SDHC1.c’
      ‘Executing target #9 ../Generated_Code/SDHC1.c’
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/SDHC1.args” -o “Generated_Code/SDHC1_c.obj” -c “../Generated_Code/SDHC1.c” -MD -gccdep
      ‘Finished building: ../Generated_Code/GPIO1.c’
      ‘ ‘
      ‘Finished building: ../Generated_Code/FAT1.c’
      ‘Building file: ../Generated_Code/TI1.c’
      ‘Finished building: ../Sources/Events.c’
      ‘Finished building: ../Generated_Code/FATM1.c’
      ‘ ‘
      ‘Executing target #10 ../Generated_Code/TI1.c’
      ‘Finished building: ../Generated_Code/PE_LDD.c’
      ‘ ‘
      ‘ ‘
      ‘Building file: ../Generated_Code/TMOUT1.c’
      ‘Finished building: ../Sources/ProcessorExpert.c’
      ‘Invoking: ARM Compiler’
      ‘ ‘
      ‘Building file: ../Generated_Code/TU1.c’
      ‘Finished building: ../Generated_Code/Cpu.c’
      ‘Building file: ../Generated_Code/TWR_UART.c’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/TI1.args” -o “Generated_Code/TI1_c.obj” -c “../Generated_Code/TI1.c” -MD -gccdep
      ‘Executing target #11 ../Generated_Code/TMOUT1.c’
      ‘ ‘
      ‘Building file: ../Generated_Code/TimerIntLdd1.c’
      ‘Finished building: ../Generated_Code/SDHC1.c’
      ‘Executing target #12 ../Generated_Code/TU1.c’
      ‘ ‘
      ‘Executing target #13 ../Generated_Code/TWR_UART.c’
      ‘Invoking: ARM Compiler’
      ‘Building file: ../Generated_Code/TmDt1.c’
      ‘Executing target #14 ../Generated_Code/TimerIntLdd1.c’
      ‘ ‘
      ‘Invoking: ARM Compiler’
      ‘Building file: ../Generated_Code/Vectors.c’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/TMOUT1.args” -o “Generated_Code/TMOUT1_c.obj” -c “../Generated_Code/TMOUT1.c” -MD -gccdep
      ‘Invoking: ARM Compiler’
      ‘Executing target #15 ../Generated_Code/TmDt1.c’
      ‘Invoking: ARM Compiler’
      ‘Building file: ../Generated_Code/WAIT1.c’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/TU1.args” -o “Generated_Code/TU1_c.obj” -c “../Generated_Code/TU1.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/TWR_UART.args” -o “Generated_Code/TWR_UART_c.obj” -c “../Generated_Code/TWR_UART.c” -MD -gccdep
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/TimerIntLdd1.args” -o “Generated_Code/TimerIntLdd1_c.obj” -c “../Generated_Code/TimerIntLdd1.c” -MD -gccdep
      ‘Executing target #16 ../Generated_Code/Vectors.c’
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/TmDt1.args” -o “Generated_Code/TmDt1_c.obj” -c “../Generated_Code/TmDt1.c” -MD -gccdep
      ‘Executing target #17 ../Generated_Code/WAIT1.c’
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/Vectors.args” -o “Generated_Code/Vectors_c.obj” -c “../Generated_Code/Vectors.c” -MD -gccdep
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/WAIT1.args” -o “Generated_Code/WAIT1_c.obj” -c “../Generated_Code/WAIT1.c” -MD -gccdep
      ‘Finished building: ../Generated_Code/TI1.c’
      ‘ ‘
      ‘Building file: ../Generated_Code/ff.c’
      ‘Executing target #18 ../Generated_Code/ff.c’
      ‘Invoking: ARM Compiler’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm” -gccinc @@”Generated_Code/ff.args” -o “Generated_Code/ff_c.obj” -c “../Generated_Code/ff.c” -MD -gccdep
      ‘Finished building: ../Generated_Code/TMOUT1.c’
      ‘Finished building: ../Generated_Code/TWR_UART.c’
      ‘Finished building: ../Generated_Code/TU1.c’
      ‘ ‘
      ‘ ‘
      ‘Finished building: ../Generated_Code/TimerIntLdd1.c’
      ‘ ‘
      ‘ ‘
      ‘Finished building: ../Generated_Code/TmDt1.c’
      ‘Finished building: ../Generated_Code/WAIT1.c’
      ‘ ‘
      ‘ ‘
      ‘Finished building: ../Generated_Code/Vectors.c’
      ‘ ‘
      ‘Finished building: ../Generated_Code/ff.c’
      ‘ ‘
      ‘Building target: TWR-K70F120M_FatFS.afx’
      ‘Executing target #19 TWR-K70F120M_FatFS.afx’
      ‘Invoking: ARM Linker’
      “C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwldarm” @@”TWR-K70F120M_FatFS.args” -o “TWR-K70F120M_FatFS.afx”
      mingw32-make: *** [TWR-K70F120M_FatFS.afx] Error -1073741811

      So then, after importing to the super-short C: path, lo and behold it works. Tell me again why mingw doesn’t suck? 🙂 Thanks for the hand-holding.

      btw – when importing the project I got this:

      System directory = C:\Freescale\CW MCU v10.3\MCU\ProcessorExpert
      User working directory = C:\Documents and Settings\All Users\Application Data\Processor Expert\CWMCU_PE5_00
      Internal cache directory = C:\Documents and Settings\All Users\Application Data\Processor Expert\PECache\5c3ec413
      Mar 7, 2013 2:22:36 PM Successfully started Processor Expert service
      BeanLoader.loadTemplate: error loading template Templts\TimerInt_LDD.dev

      But it still compiled….

      Like

      • p.s. I also tried importing the project from the no-spaces-but-longish path (btw not on C:) to the short-path workspace, but not copying to workspace, and that gives the mingw make linker error. So mingw wants the project either on C: or with a short path or both.

        Like

        • I do have as well spaces in my paths, but not seen such aproblem. Could you tell me what your original path was so I might try to replicate what you see? And it is new to me that something else then C:\ does not work (altough my projects are on C:\ too, and I only have C:\ drive. I might try with a virtual drive or something else.

          Like

        • Hi Marc, I have created a virtual F:\ drive, having a workspace directory on it with spaces, and can build the project without problems. Not sure what the problem might be on your end? But I know that Eclipse/GCC has problems with international characters (like àöü) in paths and file names, so they should be avoided.

          Like

      • Hi Marc,
        I already have reported the ‘erro loading template’ message to Freescale, and they said they will fix it. But it has no effect or impact (at least on my side), so this is not your problem.

        Like

      • I wonder if there’s some flag or something so I could get some detailed information from the mingw layer to figure out why it’s failing. Million reasons why… for example, my system: Win XP SP2 on Parallels 7. The drive that’s failing is a parallels translated mount (Y:) translation to my mac home directory and then a path within that. But… I use that setup with e.g. TI’s CW 5.3 which is eclipse-based and it works fine.

        As for diffs between the K70 and K60 project, well this blog page I’m polluting shows that the K60 project does a nice job of benchmarking the SD card, and has the command interpreter integrated… K70 doesn’t have either (I’m still trying to figure out the diff between the four K60 projects on github, varying combinations of FreeRTOS, FatFS, and GCC….) My current task is to benchmark SD read speed for a couple of different processors to see if they’re up to snuff for a project I’m working on.

        Like

        • For sure CC 5.3 is using a diffrent MinG version. CodeWarrior is using the one in C:\Freescale\CW MCU v10.3\gnu\bin.
          I know that at least for 10.2 there was a problem that the MinG environment was using the Cygwin stuff (renaming my c:\cygwin to something different prevented the make to use a different version).

          As for the K70 project: I see if I find time in the next days to add the benchmark code. There are different versions/combinations because different people asked for different things 🙂

          Like

        • Hi Marc,
          I worked today on the K70 project, and have beefed it up so it includes now FreeRTOS plus the command interpreter. I have moved the benchmark command to the FatFS module so everyone using FatFs can benefit from it. I’ll have it commited to GitHub. I see if I can do the same changes for the K60 projects today (you will see it commited to the GitHub too).

          Like

      • I’ll investigate the cywin issue… thanks for the pointer (anyhow the underlying problem is Windoze… CC now also supports linux, yay… NXP’s eclipse tool also supports OSX, double yay! Hopefully CW Eclipse will branch out soon.)

        as for the project, don’t worry about it, at least for me, because I’m targeting the K60 anyhow, and getting the TWR board for it next week, the K70 was just an interim loaner.

        Like

        • Hi Marc, FYI, I have updated both K60 projects (the one with the legacy FSL ARM compiler, and the one with the ARM gcc compiler) to use the new shell and FatFs with the built in comands.

          Like

        • Hi Marc,
          the command interpreter in FreeRTOS seems LGPL any more. I still carry forward the LGPL one from a previous FreeRTOS version (to keep it LGPL). But the one I’m using is my own one (which is LGPL as well).

          Like

      • finally got my K60 board and… it’s a K60F120M! I was getting the ‘secured’ issue, found out from this post https://mcuoneclipse.com/2012/05/28/device-is-secure/ that I need to change the processor, so I’m attempting to modify the project for the new processor (based on your post https://mcuoneclipse.com/2013/02/28/switching-processor-package-in-processor-expert/), tricky business…

        p.s. I figured out how to update the ProcessorExpert components from github thanks to your post https://mcuoneclipse.com/2012/06/30/cde-hacking-where-is-my-stuff-a-dissection/ – in a nutshell, just copy over the Beans and Drivers folders.

        Like

      • actually it occurred to me that the K70F120M project might be closer… after all the K70F is the K60F with LCD support, right? It actually compiles and runs on the K60F120 board, LEDs are flashing, looks like it’s running, but I’m just not getting anything out of the serial port…

        Like

      • hey thanks for that link, i didn’t realize i could launch a serial terminal right inside eclipse! very cool!
        When I first plugged in the K60, CWE prompted me to upgrade the firmware so it’s good. Comparing the TWR board docs for the K70F and K60F and for some reason Freescale uses UART2 on the K70 and UART5 on the K60 for the OSBDM serial port. I tested the old K70 FATFS project, hacked UART.c to use serial port 5 (and changed the PE component settings for the correct pins) and that worked (115K baud).
        OK just tried the new K70F120M_FatFS project, changed AS1 to UART5 and voila! It’s working!

        Like

  9. Hi Erich,

    First of all, thanks for all the info on your site! So many useful tools here!

    I grabbed the project file for the K70 tower fatfs project off of github, however it appears I am missing the new shell component. I see the source on github but is the PEupd package somewhere that I am missing? I can’t compile without it and I am not sure how to make a PE component from the source.

    Thanks!

    Quincy

    Like

  10. Pingback: Serial Bootloader for the Freedom Board with Processor Expert | MCU on Eclipse

        • No, not needed in my view. Polling is more than ok for that use case. I mean: it does not matter if you detect the card insertion a few milliseconds later. But I agree that it would be useful for detecting a card removal while writing: but then it is already too late. What I do is having a ‘unmount’ command which the user can use to gracefully eject a card. But you are free to use an interrupt line if you want. Maybe I simply add a ‘CardHasRemoved’ and ‘CardHasInserted’ methods to the stack for this you could call from the interrupt?

          Like

      • oh, that was fast!!
        re: interrupt, i just noticed that the PE component instantiated it, but i agree what’s the point. Just poll it. And maybe on a read/write failure, it could be polled and a different error code returned from the access functions (card not present/removed, etc.)

        Like

        • Hi Marc,
          yes, I agree with you. As far as I can tell there is already a failure code coming from FatFS, but I have not verified it.

          Like

  11. Pingback: Added Write Protection Pin to FatFsMemSDHC | MCU on Eclipse

  12. Pingback: USB MSD Host for the FRDM-K20D50M Board | MCU on Eclipse

  13. Pingback: Hacking the Heating System for Cooling – Geothermal Drilling with extra Benefits | MCU on Eclipse

  14. Erich hi,
    Thanks for posting the FatFs components, this really makes writing to SD card a breeze.
    I have two questions:
    1. The first one is pretty simple, when the component is not using the Card Detect switch, it seems to keep the SD.Inserted flag in it’s FALSE value. Is there a method to override this (except changing the internal code)?
    2. When closing a file, it seems the component waits for the timeout time of about 3 seconds even though there seems to be no operation present (hence the event never returns with the ready flag on). Is there a way to fix this?

    The sample code I’m using right now is:
    FAT1_Init();
    fr = FAT1_mount(0,&fs);
    while (1)
    {
    sprintf(FilePath,”%d\.log”,myFileCounter++);

    fr = FAT1_open(&fp,FilePath,FA_WRITE | FA_OPEN_ALWAYS);
    for (MyCounter=1000; MyCounter > 0; MyCounter–)
    {
    sprintf(MsgStr,”File:%d Counter:%d”,myFileCounter,TimeCounter);
    fr = FAT1_write(&fp,MsgStr,strlen(MsgStr),&BytesWritten);
    MyLastTimeCounter = TimeCounter;
    }
    MyLastTimeCounter = TimeCounter;
    fr = FAT1_close(&fp);

    }

    The result shows about 60 counts passing between the close start and end, While debugging I was able to see that the sync calls the disk_ioctl which waits for the while (!SD->Finished && !isTimeout) but this time it gets to the timeout.

    Thanks in advance.

    Like

    • Hi Rami,
      first: thanks for your feedback, and that this component is useful for you, appreciated!

      about your point 1): this is indeed an easy change. I have committed an additional attribute to GitHub (https://github.com/ErichStyger/mcuoneclipse/commit/262ea099983df149c55770288a35ab84f263faf5) where you can configure the return value of DiskPresent().

      about your point 2): I have not seen this (yet?). Yes, it needs to flush the internal caches at close() time, but it should not run into a timeout. If it does, you can try to increase the timeout values in the SD_Card component to see if this helps?

      Like

      • Erich hi,
        Thanks for the quick reply. I will look up the new version.
        I’ve been looking at the logic of the close and found the following (might be inexact as I’m not an expert):
        1. Calling Close calls the sync function which eventually calls the disk_ioctl function with the CTRL_SYNC parameter.
        2. disk_ioctl calls FATM1_Activate which is an empty function and then calls SD_Wait.
        3. Since the data was already flushed, at this point there is no pending operation so the SDHC1_OnFinished event doesn’t get called, resulting in a timeout. I was considering calling a simple read function of the SDHC just to get the event, but I’m not sure which would work and not cause any mess.
        I’ll recheck the new version of the component.

        Thanks again,
        Rami

        Like

  15. Erich hi,
    Just found a quick fix which seems to work for me.
    In the disk_ioctl function, under the CTRL_SYNC case (switch (ctrl)) I placed the following code:
    case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
    FATM1_Activate();
    if (SDHC1_GetCardInfo(SD.SDHCPtr, &SD.CardInfo)!=ERR_OK)
    Error = TRUE;
    if (!Error)
    SD_Wait(&SD, &Error);
    if (Error)
    res = RES_ERROR;
    break;

    This seems to get me response times of about 160ms, assuming my timing mechanism is correct.

    I’d like your opinion on this fix, especially if you see any problem with it,

    Thanks,
    Rami

    Like

  16. I’ve been exploring for a bit for any high-quality articles
    or blog posts in this kind of niche. Fortunately I ultimately stumbled upon this website.
    Reading this info, i am glad I found out what I needed.

    Thank you for posting.

    Like

  17. Hi Erich,
    It’s possible to use the FatFs without any RTOS? For my purposes I don’t need an RTOS running on my device. It’s more important to reduce the total code size and speed up the execution time.

    Hi
    Walter

    Like

  18. Hey Erich,
    I keep getting FR_DISK_ERR when trying to read a file from my sd card,when i run the code from my TWR-K60F120M board.Any idea what might be causing this?

    Like

  19. I got it working :),I used another card and it worked like a charm. 🙂
    I have never used a RTOS before,so it took me a while to understand the code briefly.Generally i code everything inside an infinite loop.Can this project be done without using an OS?
    I also would like to learn how to use an RTOS,is there any material /documentation i can follow ?
    Thanks for all your help Erich

    Arun

    Like

      • Thanks for those links.
        I notice sometimes i get the same error(0x01) when ever i try to open a file.(f_open()).
        By the error codes provided by PE.Error.h : its ERR_SPEED
        I tried changing the frequencies but i still keep getting the same error.
        Debugging further inside f_open(),
        “res = chk_mounted(&path, &dj.fs, (uint8_t)(mode & ~FA_READ));”
        is giving the internal error :: FR_DISK_ERR
        going further into the chk_mounted() function:
        “fmt = check_fs(fs, bsect = 0);” is returning 3,which is giving the error.

        Any suggestions as to how to fix this issue?
        I tried a range of frequencies right from 100Khz to 25 MHz,but still keep getting this annoying error

        Like

        • Hi Arun,
          can you check with a logic analyzer if you pin connections and signals are correct?
          If you get these kind of errors, it usually means that you cannot talk to the SD card at all.
          Have you tried with different cards?

          Like

  20. Hey Erich,
    I got it working correctly now.
    It was some kind of program error.Once i re-programmed the MCU those errors vanished.Its working correctly now.Strange actually,never though such errors could also occur.I double checked with multiple SD cards(checked up to 8GB) and they are all working perfectly.

    Like

  21. Hi Erich,

    I’ve been working on a program for the K70 that uses FatFS and the SDHC (via your components) to write files to a uSD card.
    When using a 32GB uSD, the program correctly mounts the card, creates the file, writes to the file, etc.
    When using a 64GB uSD, the program correctly mounts the card, but I get an Assertion Failed error (corresponding to FR_INT_ERR) when attempting to create the file.

    I haven’t had much time to try and debug it yet, but I wanted to see if you had ever experienced this or had any thoughts on the cause.
    Looking briefly at ff.c, it is bombing out in one of the functions when testing the value of the variable clst.
    This variable had the value 4294967295 (0xFFFFFFFF) which is obviously an issue.

    It does appear to mount the 64GB card successfully.
    I’ve seen it get past the open function before, but it would then fail when trying to write to the file.
    (I think this occurred if I pointed to a file that already existed and did not have to be created…I need to test further.)

    Any thoughts ?

    Thanks for all of your hard work.
    My application wouldn’t be as far along as it is if it wasn’t for your blog !

    V/R,
    Chandler

    Like

    • Hi Chandler,
      I think the largest SD card I own is only 8 GB :-(.
      I have used/tested it with a larger size, so it could be that larger sector sizes are not supported.
      I would first need to buy a larger card to check this. I guess you really need that 64 GB?

      Like

      • Hi Erich,

        I’ve tested the 64GB card again, and it worked…not sure what changed.
        I have encountered a new problem though which I assume is related to the implementation of FATFs.
        Our program continuously writes 8MB data files.
        I’ve noticed that once we reach 4GB (512 files), the next file does not get written (Assertion failed error), and the file system gets corrupted.
        It seems like it is wrapping around to the beginning and overwriting the FAT instead of correctly continuing on to the next location.

        Any thoughts ?
        I know the SDHC controller is able to write later locations, as I’ve tested this before without the use of the FATFs component.
        I assume that FATFs doesn’t have this 4GB limit, and that something in the implementation has caused this issue.
        This has occurred on multiple card brands and sizes, so it appears to be a software thing.

        I’m going to dig further now.

        V/R,
        Chandler

        Like

      • I believe I’ve found the culprit but still need to test the theory.

        The problem lies in the driver handling both SD and SDHC cards.
        Unfortunately, it is a terrible implementation.

        For SD cards, the controller wants the byte address.
        For SDHC cards, the controller wants the sector address.

        FATFs works with sectors.
        The logical solution would be to use the sector number provided, and if the card is not high capacity, then multiply by sector size to get the correct byte address.
        Unfortunately, the code passes sector number * sector size (512 here), then tests for high capacity, and if true shifts >> 9 to divide by the 512.
        Not only is this a complete waste of cycles multiplying by 512 only to divide by 512, it also causes an issue once you get past sector 8388608, which corresponds to my 4GB limitation.

        My solution modifies the call to TransferBlock within disk_write, removing the multiply by 512.
        TranferBlock calls ByteToCardAddress.
        This is modified to keep the sector address if high capacity, or shift << 9 if not high capacity.

        I believe this will work, but will update this post once I have verified.

        V/R,
        Chandler

        Like

  22. Hi Erich,
    Great Blog for starters!
    I am using TWR-k60N512 with CW 10.5 and trying to run your project FATfs from github updated for 10.4.
    So my version of process expert doesnt support the component shell CLS1. Any remedy?

    Like

      • Hi Erich,
        that solved the component problem. Now when I am building the Fatfs_gcc, its giving me errors like
        ../Sources/Events.h:27:26: fatal error: RTOSTICKLDD1.h: No such file or directory
        mingw32-make: *** [Sources/ProcessorExpert.o] Error 1
        mingw32-make: *** Waiting for unfinished jobs….
        mingw32-make: *** [Sources/Events.o] Error 1

        Like

      • Hi erich,
        Really appriciate your services. The code is running now and its compiled.

        In the shell when i am giving the command, cmd> dir , its not being processed, idont know why, same is with all the other commands except (help)…The response is always
        ” *** Failed or unknown command: dir “

        Like

      • I solved the last problem now having problem in going for benchmark
        here it is
        when i write CMD> FAT1 benchmark, the response is
        CMD> Benchmark: open file, write 10k times 10 bytes (100’000 bytes), close file:
        Deleting existing benchmark files…
        ERROR: unlink failed: (1) A hard error occurred in the low level disk I/O layer
        ERROR: unlink failed: (1) A hard error occurred in the low level disk I/O layer
        Creating benchmark file…
        *** Failed opening benchmark file!
        *** Failed or unknown command: FAT1 benchmark

        Like

        • Hello, are you using one of my examples or your own? It looks like the communication with the SD card failed resulting in that error message. Does “FAT1 dir” work?

          Like

    • Hi Erich, Sorry for getting back late to you.

      Yes I am using your example.

      FAT1 diskinfo is working
      CMD> Card type : SD1
      Sector count : 1955840
      Sector size : 512
      READ_BL_LEN : 1024
      High capacity: no
      High speed : yes
      Low voltage : no
      Data widths : 1 4
      Operations : BlockRead BlockErase WriteProtect

      But FAT1 benchmark and dir gives the same error as in the previous comment

      Like

      • I have changed the SD card but its again 2GB. and the problem is same. for diskinfo its giving the info but for dir and benchmark is the error.

        CMD> Benchmark: open file, write 10k times 10 bytes (100’000 bytes), close file:
        Deleting existing benchmark files…
        ERROR: unlink failed: (1) A hard error occurred in the low level disk I/O layer
        ERROR: unlink failed: (1) A hard error occurred in the low level disk I/O layer
        Creating benchmark file…
        *** Failed opening benchmark file!
        *** Failed or unknown command: FAT1 benchmark
        *** Type help to get a list of available commands

        Like

        • Are you using the Timeout componet in your project? If so, are you calling TMOUT1_AddTick()?
          Additionally, check your SPI bus speed (that you have 6 MHz in high speed mode).
          I hope this helps.

          Like

        • Maybe you can send me your project to the email address mentioned on the About page of this blog? Then I can have a look. You are using the TWR-K60N512, correct?

          Like

    • HI Erich,
      First of all many thanks for providing a BM project for starters like me. you are really contributing to community
      I have a question.
      Whether the same project would be compatible with other CPU’s and packages?
      forexample if we change the cpu from the one in TWRk60N512 to the one in TWRk60FX512 that contains 120MHz processor.

      If not then could you suggest some points to make it compatible for cpu MK60FX512VLQ15,

      Like

      • Hi Erich,

        could you let me know if that low level IO problem is only in the project for TWRk60N512 or it is in all the projects related to FATfs + SDHC?

        More over I am having the same problem as soon as I am changing the block count and block size from 1 to 50 and 512 to 1024 respectively in SD.SendTransferBlock command in FATM1.h

        And while implementing memorycard commands you must have disabled the ADMA (Internal DMA) in SDHC block. Could you give me a clue where should I implement it (I think there is a command for it which enables the Adma and set the Adma address).

        Waiting for your reply.

        Regards
        Abdullah

        Like

        • Hi Abdullah,
          I really do *not* recommend to change the default block size of 512 bytes, unless you really know what you are doing. Because this can have all kind of side effects. So this could be the reason for the problems you are seeing.
          And I’m not aware that I have disabled ADMA in the SDHC block.

          Like

  23. Hi Eric,
    You are doing a fantastic job with your blog. Even though this is the 1st time I am commenting, I am actually following your posts many months.
    The reason for commenting at this post is to ask if the example here was tested onto the TWR-K60D100M. I am trying to get the example from here (https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K60F120M) to work on the board I have but I am seeing some issues. Even though I have changed the derivative part (from PE) to “MK60DN512ZVMD10 in MAPBGA 144-pin package” I am seeing a hard fault when the PE_low_level_init() is executed.
    It seems when the CPU is reading from this address (0x40048040), the hard fault exception is raised.
    r3 = 0x40048040
    ldr r2,[r3,#0]

    I tried to create a simple example(no RTOS) on my own that would just have the following lines in the main application code:

    FAT1_Init();
    fr = FAT1_mount(0,&fs);
    fr = FAT1_open(&fsrc, srcFileName, FA_READ | FA_OPEN_EXISTING);
    fr = FAT1_close(&fsrc);

    For some reason, I cannot read any data from my 4GB SDHC.
    Do you have a very simple example that would only open a file and maybe read a few bytes from it?

    Thank you

    Like

    • Hi Bogdan,
      first: thanks for your feedback on the blog, very much appreciated!
      There are multiple answers/pieces to your questions:
      a) Another reader of this blog reported me a problem yesterday using SDHC with the TWR-K60N512. I was able to reproduce it, and have created a hot fix (available on GitHub: https://github.com/ErichStyger/mcuoneclipse/commit/a19ff3f4432a4f53730828e73370c34ba0256ee1). The problem was that the ‘FAT1 dir’ command returned a disk error. With above fix this problem has been removed. But I need to check if this fix is impacting performance. Unfortunately all my ‘real board’ projects are using SPI for SD card communication, so this bug was undetected for a long time :-(. But it was not a hard fault.
      b) I do not have a TWR-K60D100M, but I was told that the TWR-K60N512 projects should run there too. However, the silicon is different, so this might create issues. I hope I do not need to buy now a TWR-K60D100M.
      c) A hard fault could happen if you are using the FSL (non-ARM) compiler. I realized that this compiler is going EOL, so I switched over to use the ARM GNU gcc instead (which is now the official and default compiler from Freescale). Especially there are issues with the (legacy) FSL compiler, so this this could be the reason for the hard fault (that you were not using gcc)?
      d) I realized that I had the wrong package in Processor Expert selected for the TWR-K60N512 (thanks for your tip on this!). I have fixed this in the project on GitHub now. But the package only influences which pins are available to the outside, so does not really impact that project.
      e) I see your point about bare metal SD card example. Let me see if I can quickly create one (as you are not the only one asking for this). I’ll post a new comment once I have it created and tested (I probably will just use the TWR-K60N512, but that really should not matter).

      I hope this helps you.

      Like

      • Hi Erich,
        Sorry for misspelling your name in my 1st post.
        Thank you for providing the BM example. I will try it tonight 🙂
        I have some updates regarding the SDHC example.
        I was a bit intrigued on the faults I got and since I’ve had far too many coffees during the day, I spent some hours in the evening trying to do something.

        First of all, I spot a mistake on my CPU choice. The CPU on my board doesn’t have any “Z” letters by the end of its name.
        I opened the PE view and I added the correct CPU “MK60DN512VMD10”. I think this was the reason for which I have seen the hard-fault exception before. Afterwards, I made the settings on the clock sources and values and I have changed the pin designations for the LEDs, SDHC presence GPIO and UART.
        After a few more tweaks I was able to compile the code and managed to execute it successfully. 🙂

        I tried the example using the same 4GB SDHC card I’ve mention in my 1st comment. This time it worked but from time to time I have seen (I think) the same kind of errors the others commenters have seen.
        I modified the SDHC mode to work in 4-bit mode but I have seen the same error appearing in most of the cases.
        I lowered the “Speed Index Normal” clock to 3.125MHz and I can say the example runs fine all the time with no issues.
        In the end, around 2AM 🙂 I went to bed, happy the example was running fine on my board as well.

        I would be happy to share the project or project settings with you and the community.
        What I would like to try is to see what happens if I put a value for the “Speed Index Fast” in the SDHC component.

        I’ll come back with updates. I’ll try to sleep at a decent hour tonight :-), probably not.

        Like

        • Hi Bogdan,
          oh, now your hard faults make sense: if you selected the wrong processor, then it could be that the flash programming (or other stuff) went terribly wrong, causing a hard fault. In general I’m not so happy with the SDHC way: I have not seen any performance gains using more or less bits, and I’m not sure why. The hot fix I had to add today is about changing the clock speed to, so this is a general problem I’m seeing. I had much better (and stable) results using SD cards with normal SPI.

          Like

  24. Hi Erich,

    I wanted to increase the writting speed of my sdcard as with your configurations, I am able to get 5-8 KBps with your example but Now I want to increase it by increasing the clock speed and then enabling to write in blocks of Minimum 512bytes each. Could you tell me where have you configured the Block Attributes in your Process Expert code. Or whether it is possible in project of yours. I wanted to know also if you have enabled the DMA operation while testing.

    Regards
    Abdullah

    Like

  25. Pingback: First Steps with the Freescale TWR-K64F120M | MCU on Eclipse

  26. Hi Erich, I think you work is great with supporting all this components for PE. I’m using K10 with your FatFsMemSDHC component. Until now I’m going baremetal, probably will be using Adam Dunkel’s protothreads. So far everything is working great but I’m having some problems with the speed. I cant not increase from 400KHz clk freq. I tried https://github.com/ErichStyger/mcuoneclipse/commit/9509e39e1eafe4fbe67bf7391a37c419ef7403a6 fix but with this it just stop working completely, block reading fails and it doesn’t work.
    At this moment my code looks like this:
    FAT1_Init(); // after this the clock is running at 10MHz (it never stops, is this normal?)
    fr = FAT1_mount(0,&fs);
    FAT1_mkfs(0,0,512); //during this and after clk = 400KHz
    FAT1_mount(0,NULL);
    fr = FAT1_mount(0,&fs);
    fr = FAT1_open(&fsrc, “ddd.txt”, FA_CREATE_ALWAYS + FA_WRITE);
    FAT1_write(&fsrc, “Test1”, 6, &mbytes);
    f_sync(&fsrc);
    fr = FAT1_close(&fsrc);
    FAT1_mount(0,NULL);
    FAT1_Deinit();

    everything works as described in the comments (400KHz) without the https://github.com/ErichStyger/mcuoneclipse/commit/9509e39e1eafe4fbe67bf7391a37c419ef7403a6 patch. When I use it the speed is retained at 10MHz as I want but everything else fails (mkfs, open, write, etc).

    Any hint about where to look will be highly appreciated.

    Like

    • Hi William,
      Well, you ask a very good question. The thing is that I had to uncomment that code a while back, only to realize that at least with MCU10.5 I had to enable it again, otherwise my SD cards did not work. I was very desparate, and only found out that I needed to add that piece of code of that commit again to have things working. I verified it with my TWR-K60 and TWR-K70, and they are ok with that code. Which version of CodeWarrior are you using? Maybe they changed something in the Processor Expert code?

      Like

      • Hi Eric,
        I developed a software application with Kinetis K60 to copy images from USB key to a SD card class 4. I used the processor expert of codeworrior 10.2 and I followed your steps. The application works fine, but sometimes some images in SD card are alterated and it’s impossible open them. The SD working frequency is 25MHz. Have you got any idea aboute the reason? Please note that I haven’t any experience on SD card :-(.
        Thank you in advance for you support.
        Best Regards,
        Stefano.

        Like

        • Hi Stefano,
          I have not seen something like this. But here are a few tips: does it happen if you lower the speed to say 10 MHz too? If something bad happens while writing the directory or files, that could cause problems. I call the flush() function frequently in my applications so the data gets not lost. The other thing is that you could try different SD cards: I have seen some very slow ones which can cause problems.
          I hope this helps.

          Like

  27. Hi Erich,
    I’m using PE v10.2 generating the code for IAR compiler. Using project connections as I saw in one of your tutorials. Do you recommend to move to a newer PE? I have another question, is there some difference in the SDHC controller of K10, K60 and K70 families?, I mean registers addresses, setup for operation, registers configuration are same? If your component works fine in K60 and K70 it should also work in K10 or maybe it will need some tuning? Thank you very much for your support.

    Like

    • Yes, I recommend to use the 10.3 version of PE. I have not looked at the details of SDHC controllers (Processer Expert abstracted it for me), but I thought they are the same?

      Like

  28. Pingback: FTF: FRDM-K64F, Kinetis Design Studio and Kinetis SDK | MCU on Eclipse

  29. Hello Erich,

    I am using the latest CW IDE 10.6 and the SD Card component you supplied on GIT (15.04.2014) and somehow things are not working for me. Well, it was yesterday and today when I reopened my project I had new errors and I tried to recreate the good results I had yesterday with no luck. It says I’m missing a “diskio.h” and then many more files in the “Drivers” directory you supplied when I try to Build (All) my project. I have moved the “Beans” and “Drivers” in the “C:\ProgramData\Processor Expert\CWMCU_PE5_00” folder and the first time I tried out your components it worked out ok. Now, I’m trying to add the components in a different sequence to see if it helps but I have not found the right combination yet.

    Please advise,
    Mevon

    Like

    • Ok, I added the Fat FS after and it worked. I had a SM1_DeviceData missing in the SD.c file but hen I check Auto Initialize in the SPI Master LDD and it works. Still got this warning “/Generated_Code/SD1.c:807:3: warning: implicit declaration of function ‘SM1_SelectConfiguration’ ” but for now it seems it’s ok. Thank you for supplying all these resources, I don’t know how I would be able to make it whitout it. THANK YOU!!! 😀

      Like

      • About the warning, I was trying my project in the CW IDE 10.5 to see if it changed something to my troubles when I found my mistake. Now, back in the CW IDE 10.6 I don’t have that warning anymore. Thanks (sorry for my newbie mistakes, I am very new to ARM programming and CW IDE) A LOT !!!

        Like

  30. Pingback: FRDM with Arduino Ethernet Shield R3, Part 4: MinIni | MCU on Eclipse

  31. Hi Erich,

    How extensively have you used the FatFSMemSDHC component? We are running into an memory alignment issue where the ADMA controller expects word-aligned addresses and no such guarantee is made by FatFS, a problem warned about here:

    http://elm-chan.org/fsw/ff/en/dread.html

    This issue surfaces when the application buffer being read into is larger than the block size and not word-aligned. The listed fixes are rather onerous for more advanced application code that doesn’t simply read word-aligned data in a loop.

    The best application-level fix we can come up with is to always read less than BLOCK_SIZE bytes of data to ensure that FatFs uses its internal buffer rather than the application buffer. I thought you might want to know of this issue to warn others and possibly save them from days of debugging why data is almost correct but mysteriously offset, and _not_ in a way that compounds over time.

    Thanks,
    Vishal

    Like

    • Hi Vishal,
      I use the component more in SPI mode, and not much with SDHC. However, sometimes I have seen strange issues with SDHC, which appeard and then disappeared. I was never able to track it down :-(. looks like what you report could be the issue?

      Like

      • Yes, disk_read() and the other low level functions have a physical drive number as argument. What I need to do is to make possibly a ‘multi-drive’ low level disk component. In that component, I can the assign multiple ‘disks’ like SD card, USB MSD, etc.

        Like

  32. Hello Erich,

    So the day has come when I have to learn how to create or modify PEx components… Seems I have to use two (2) Fat modules in my project and PEx doesn’t like it. I want one fat module for a USB MSD device and an other one for a SD card, so the troubles come when PEx tries to create another set of “diskio.h” and “ff” confic.h .c and .h files. Gives me the error that the files already exist and the functions “disk_initialize”, “disk_ioctl”, “disk_read”, “disk_status”, and “disk_write” already declared with FAT1 when time to create FAT2 comes. So, I think I have to modify the Fat_Fs component to have it create the said files with say “Fat1_” prefix and same goes with the functions in the SD1 and FsMSD1 files. For me it`s a big deal now but maybe you could help me overcome my lack of component design skills and point me in a direction I could take your components and update them? I`m guessing there might be repurcussions in the Shell component too, please advise.

    As always, you got my best regards,
    Mevon

    Like

    • Hi Mevon,
      hmm, I think that’s not an easy problem to solve. It is not only a Processor Expert problem, but a FatFS one too. It would be easy to create different files for ff.h etc, but there still would be the conflict for disk_read/etc. FatFS would have the ability to work with multiple ‘volumes’ or ‘disks’. I have not used that (I only had only one memory device). I would need to look into that option, maybe using multiple volumes/drives would be the way to go. That way the bulk of the FatFS code would not be duplicated too, which would be good.
      Bottom line is that I would need to set some time aside to think this through. Unless someone else reading this has a great idea?

      Like

      • my $0.02… using multiple volumes is the way to do this. But you have to recognize different low-level functions for accessing the media for the different volumes through some kind of selector. Not sure if ChanFS has that built in, but probably wouldn’t be terrible to do with arrays of function pointers indexed by the volume….

        Like

      • The Quick fix I want to try for now is disable the USB MSD and compile with only the SD + Fs. Copy those files generated into my “Source” directory (“SD1.c+h” for starters) and removed them from Compiled Ressources and modify them so they would be disctinct before re-enabling the MSD Fs. That would make the second Fs kinda static and hell to regenerate via PEx but meh, that would be enought for me now.. I believe if PEx was not so “C” (vs “C++”) and real objects would be created, then each would have their own sets of “utility” methods but C++ and PEx don’t mix great for now. If I was good with component editing/creating, I would add the prefixes for the files generated and the functions used and yes it would be duplicated but then again I think it needs to be that way because of the differences in the way to access the media involved. Maybe there are some more generic functions that can be kept out of the mix and PEx should allow using the same files if they already exist, but then again, Im not a PEx comp pro…. yet 😛

        Thanks Erich and sorry to stumble upon all the unlikely bugs lurking around, I just want to make your library a better one, the best one!

        Mevon

        Like

        • Hi Mevon, yes, you can give this a try, but I think it will be a mess very quickly. Let me see if I can prototype something quickly….

          Like

        • Hi Mevon, made some progress. However, the changes will break some interfaces, so I will need to get you a helping hand how to transform the to the ‘multiple drives’ version.

          Like

      • I’m making progress, but I need some time to complete and test it (as best as I can). It is getting late night here, but I still need some hours to complete it.
        Can you send me an email to my email address listed on the About page of this blog? Then i can send you the updated components with instructions by tomorrow so you can give it a try?

        Like

  33. Pingback: Multi-Drive Support with FatFS | MCU on Eclipse

  34. Hey Guys, I have some very simple questions I’m hoping someone can help me with. My first time trying to use FatFS and SDHC. What triggers the card detect interupt? What function am I supposed to routinely call, or am I supposed to simply poll the pin? I am not using an operating system, and actually I am just validating hardware at this point. I feel like I am missing something very simple. I just want to see it interrupt on a card insert and init, then interrupt on the card being removed and deinit.

    any pointers, including ‘stop being stupid’ would be appreciated. Using the K60 on a custom board, using CW10.6, using the Fat_FS component and the SDHC component.

    Thanks!

    Brett.

    Like

    • Hi Brett,
      There are two ways of solving your situation. The first one is really easy and is embedded in the SD Card component for ProcessorExpert that Erich created. Your call the function “CardPresent()” and returns true if a card is present. When you use that component you can chose if you use the card detect pin or not, so it returns always true if you chose not to use the pin. I think goes deaper then that, in sens whe the FatFs wont read on the card if no card is present, and many other situations where you want the status of the card, etc. The other way is manage that you own self by using an interrupt on a pin connected to the CardDetect of the sd card holder itself. That is another ProcessorExpert component that can generate an “Event” and from there you can do what you’d like. Just remember that you cannot use the same pin on the Freescale for more then one ProcessorExpert component so you’d have to physically connect two K60 pin to the same card detect pin on the holder. (I think you can actually share the pin with processor expert but I think it’s complicated and not recommended..) Best way it to try it yourself, ProcessorExpert is great for beginners and you’ll learn many more other things in the process.

      Best of luck,
      Mevon

      Like

      • Thanks to Mevon for jumping in here. Yes, you can share pins with Processor Expert (I had to use this for a resistive touch display), but as Mevon says, this is not that simple. I have used so far the CardPresent() method which is using polling. Polling in that case is not critical, so I have not used interrupts for it. Inserting a card is a rather slow process (several hundreds of milli-seconds), and in my view it is ok to check if the card is present say twice a second or so. Using an interrupt for the card detection would be a kind of overkill.
        Card removal might be a different thing, and actually there is not much protection for that. I recommend to use an ‘eject’ method approach where the user tells that he is going to remove/eject a card, so buffers can be written back to the card. Otherwise you risk that the card file system will be damaged. To prevent data loss, I’m calling flush() frequently in my application too: that limits write performance, but makes sure the file system data on the card is kept intact.

        Best of luck too,
        Erich

        Like

        • Hey Guys, thanks for the replies. I’ve actually used pin sharing many times, and I thought about using it. What I am trying to figure out I guess, is what the “OnCardInserted” event in the FatFsMemSDHC component is for. It only seems to get triggered from ‘card_Registration’, which you only call if you are doing an init, which you would only call if the card was inserted. So polling on the pin works, then you init, then it calls the inserted event. I’m confused why the event is there? Maybe I’m over thinking it? I initially thought that it was set up as an external event, and would trigger on the pin. When that didn’t happen, I set up to poll and then call init myself. Then I noticed that the debug code I had placed in the interrupt was getting called. I don’t want to use the component incorrectly, or more accurately, I don’t want to rewrite what has already been written.

          Like

        • Hi Brett,
          the OnCardInserted(), OnCardRemoved() and OnFinished() events are in my component because I inherit them from the SDHC component. Inheriting them just allows them that the upper layers can hook into it. I have not used them for my appliction (maybe I should have?), and worked fine for me.

          Like

  35. Pingback: Tutorial: Playing MP3 Files with VS1053B and FRDM Board | MCU on Eclipse

  36. Pingback: Code Coverage for Embedded Target with Eclipse, gcc and gcov | MCU on Eclipse

  37. Hi Erich,

    great tutorial. I’m working on the simple datalogger using KwikStik board and CodeWarrior. I’d like to write some data from ADC on my microSD card (.txt or .dat format) with sampling frequency more than 20kHz. Could you please give some advice how to implement this without using any RTOS (the simplest continous datalogging using SDLH_LDD) on KwikStik? I’ve tried to import Elm-Chan’s FATFs to my barebord project and modify diskio.c by putting functions generated from SDHC_LDD component in it to provide low-drive handling for higher file layer. I don’t know if it’s enough to run SD card or if there is any simpler solution. It seems that I can’t even mount the logical drive. I’ve tried your components but all of them require other components, such as FreeRTOS. Any of your sugestions would be of great interest for me (reassuming: simple datalogger on kwikstik, no RTOS, only SDHC_LDD and FatFS library).

    Regards,

    Marcin

    Like

    • Hi Marcin,
      you don’t have to use the RTOS with FatFS, although that’s the typical case, because using the RTOS with FatFS makes things much, much easier.
      I have a CodeWarrior example project with FatFS in bare metal mode published here:
      https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K60F120M
      As for the KwikStik: I’m not using that board any more, as it has too many board and Kinetis silicon issues.
      I recommend that you use a different board, e.g. the FRDM-K64F one.

      I hope this helps,
      Erich

      Like

      • Erich,

        thanks for quick response. I’m going to develop more complex project, including acquisition data from peripheral sensor to SD card and simple user interface with LCD and push buttons. Hence I’ve chosen KwikStik but e.g. access to I/O pins is a nightmare… The board you recommend seems to be a good idea, especially because I’m actually also considering wireless transmission of data to PC via Virtual COM and additional USB board. I hope that the FRDM-K64F provide easy LCD handling (eg. HD44780 as external device). In the future I’d like to program stand-alone Kinetis chip on PC board. I hope that j-tag interface from FRDM-K64F will enable this operation. Additionally I count on high high speed of the whole datalogging process (I’d like to obtain more than 20kHz sampling rate without implementing any queuing algorithm). Or maybe you recommend even better, more, efficient board for my purposes, because this time I’d like to chose the best solution.

        Best regards,

        Marcin

        Like

  38. Hi Erich,
    thanks a lot for all your posts. They are really great.

    I am trying to use these libraries for K22F board. I am getting weird errors.

    1. Description Resource Path Location Type
    The component is not supported for selected processor (Component name) Last_try SDHC1/Component name Processor Expert Problem

    2. Description Resource Path Location Type
    Target processor does not contain peripheral of this type (Device) Last_try SDHC1/Device Processor Expert Problem

    3. Description Resource Path Location Type
    ERROR: This component is not supported in Kinetis SDK project mode Last_try SDHC1 Processor Expert Problem

    Can you please help me?

    Like

  39. Hi Erich,
    First of all, Thanks a lot for all your tutorial and such a nice way of explaination. Really appreciate it. And you really help a lot.
    I am currently working on Kinetis MCU, Freescale FRDM-K22F board. I tried Affing FatFs Module as explained by you in this tutorial. But I get error. Please help me. Error is for SDHC1 component.

    Error – “The component is not supported for selected processor”
    ” Target processor does not contain peripheral of this type”

    Like

    • Hi Vishal,
      thank you for your kind words :-).
      About your problem: it looks you have created a Kinetis SDK project? Because the Kinetis SDK API is very different from the API used in Processor Expert for High Level components (Beans) or logical device drivers (LDD), they usually do not work with the Kinetis SDK. I have made a few components ‘SDK compatible’, e.g. the FreeRTOS one. But as I cannot change the SDHC component, I cannot make it compatible with the SDK (anyway, that would be probably very difficult). So what you could do is to create a project for Processor Expert, but without the Kinetis SDK enabled. See https://mcuoneclipse.com/2014/12/27/usb-with-the-freescale-frdm-k22f-board/ how I did this for USB. Same thing should apply to FatFS too (I have not tried yet, as my FRDM-K22F board has no SD card socket on it).

      Like

      • Hi Erich,
        Thanks for your quick response. After your previous reply on other post, I have uninstalled Kinetis SDK. Currently I am just using KDS. The only difference I observe are as below.

        1. KDS version is 3.0. But I think you were using version 2.0.
        2. When I try to install new software from help menu, I do not get “Processor Expert Support for Kinetis K22F/KV31F @120/100MHz Service Pack” option. Instead I get “patch for Processor expert 3.0 Patch 1”.
        3. I tried uninstalling version 3.0 and installed version 2.0. I still get the same problem.

        Is ““Processor Expert Support for Kinetis K22F/KV31F @120/100MHz Service Pack” installed already in KDS version 3.0?

        I am really sorry to ask you so many questions. I am really stuck currently.

        Like

  40. Hi Erich,

    I’m trying to run FatFs on KwikStisk borad based on the code from your component FatFsMemSDHC and Component SDHC_LDD typical usage from CodeWarrior Help tool. I’ve written api functions: disk_initialize, disk_status and disk_read and now I want to call f_mount function from elm-chan library and I get FR_NO_FILESYSTEM status error which comes directly from check_fs method which is called from inside find_volume (he hierarchy of functions: f_mount->find_volime->check_fs).

    The line which generates the error in check_fs:

    if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
    return 2;
    Any other fucntions give no errors. To debug the application I’ve forced 0x00 in the adress where the value 0xAA55 should be using memset() function before the SDHC1_TransferBlocks is called in:

    f_mount->find_volume->check_fs->move_window->disk_read->SD_TransferBlock->SDHC1_TransferBlocks (according to your example)

    and after SDHC1_TransferBlocks procedure there are still zeros under this adress. Is it possible that the SDHC1_TransferBlocks generated by Processor Expert dosn’t read anything from the device despite returning no error? Could it be some hardware issues?

    Like

    • Hi Marcin,
      I was never able to get the SD card on the KwikStik board board working. I think it was either a silicon issue (that K40 was the first one and buggy). I believe it even had problems on the board with the wires to the SD card, so I gave up :-(. So it could be that you face the same problems not sure (might depend on the revision of the board, as there are multiple ones to my knowledge). And I had issues with SDHC too, I have found SPI working much, much better. Could you try SPI instead? I have not seen any performance benefits of using SDHC with the Processor Expert driver. That might be a problem of Processor Expert code. Can you hook up a logic analyzer to verify that there is indeed some data sent/received?
      I hope this helps.

      Like

      • Erich,
        thanks for quick response. So you suggest that I should use e.g functions generated by your SD_Card component to have SPI communication instead of 4bit mode from SDHC_LDD? If I disable FreeRTOS in SD_Card it will be still working without any RTOS? If so, I would give a try. Anyway if it doesn’t help I’ll consider using FRDM-K64F. But unfortunately, it doesn’t include j-link and in the future I’d like to flash stand-alone chip with the code prototyped on the board. Is there any other way? Should I invest in some separated programmer module? I have another question: is it easy to obtain sampling rate obove 20kHz using Kinetis MCU (K40, K60) SD card, FatFS and ADC in simple datalogger? Any additional buffering or algorithms are necessary?

        Like

        • Hi Marcin,
          yes, I recommend to use SPI instead: this protocol is very easy and you can easily inspect it with a logic analyzer. SDHC has not worked well for me in the past. And FreeRTOS should not be your problem: just keep in mind that the RTOS enables interrupts, so if you are using interrupts (e.g. in the SPI driver), you need to call things from a task context. And FRDM-K64F can be used with Segger J-Link, see https://mcuoneclipse.com/2014/04/27/segger-j-link-firmware-for-opensdav2/.
          As for the data rate of 20 kHz: I would recommend to use DMA for the ADC conversion not to load the processor. Writing to the SD card depends on the SD card, but is typically in the 50 kByte range. So if you have 20 kHz sampling (say 2 bytes each sample), this is doable. In any case you will need some buffering so you can write say 512 bytes blocks to the SD card.
          I hope this helps.

          Like

  41. Hi Erich,
    I am using FRDM-K22F Board. I am trying to get the data logger application up on this board. Components I am using.

    1. ADC
    2. FatFS (SD Card, HW SPI etc)
    3. FreeRTOS

    I am facing a weird problem.
    I have one more project where I have the same components without FreeRTOS. SD Card works perfectly fine. I can read, write etc.

    Now When I add FreeRTOS, things start getting worst. During the FAT1_init, the code gets hanged at a particular place.

    In FIle SD1.c, function: SD1_SPI_WRITE, it waits in while loop until the receivedflag is set high. In the project where I add FreeRTOS, the code keeps on waiting in this loop. Whcih basically means it is not getting the receive interrupt.

    void SD1_SPI_WRITE(unsigned char write) {
    unsigned char dummy;

    SD1_DataReceivedFlag = FALSE;
    (void)SM1_ReceiveBlock(SM1_DeviceData, &dummy, sizeof(dummy));
    (void)SM1_SendBlock(SM1_DeviceData, &write, sizeof(write));
    while(!SD1_DataReceivedFlag){}
    }

    What can be the potential cause for this? Can you please give some suggestions.

    Like

  42. Hi Erich,
    I digged a bit more. Below are the two scenarios.

    1. FatFS with SDcard, HW en, Utility, Timeout, CS1, SPIMaster_Ldd, Generic Time Date.
    These are the components.

    During Fat1Init, SD1_init(), Below function is called.

    void SD1_SPI_WRITE(unsigned char write) {
    unsigned char dummy;
    SD1_DataReceivedFlag = FALSE;
    (void)SM1_ReceiveBlock(SM1_DeviceData, &dummy, sizeof(dummy));
    (void)SM1_SendBlock(SM1_DeviceData, &write, sizeof(write));
    while(!SD1_DataReceivedFlag){}
    }

    After that, I see the interrupt getting triggered. I have put break point in SM1_Interrupt.

    2. Adding FreeRTOS component to the existing project.
    Interrupt does not get triggered at all.

    3. Remove FreeRTOS component.
    ISR is called.

    This is weird. I do not have any clue what is happening. Can you please please help me?

    Like

    • You need to call FAT1_Init() from a task (at the beginning of a task execution). Because if FAT depends on interrupts (it does usually), then you need to have interrupts enabled.
      Using an FreeRTOS interupts are disabled until you start the scheduler. Therefore do the FAT1_Init() in a task. I do this in my applications that way.
      This is the same thing if you use an accelerometer or something else on an interrupt based I2C bus (or anything else using interrupts): you need to talk to the device after the RTOS has been started.

      Like

  43. Hello Erich,

    I generated the code to communicate with SD card in 4 bit mode, but it doesn’t work. The communication between my kinetis and the SD card is in 1 bit mode. To verify it I saw that the loading speed doesn’t increase and I disconnected some SD case pins. How I can enable the 4 bit mode? I need to increase the loading speed of the images.
    Many thanks for your support.

    Best Regards,

    Mark

    Like

    • Hi Mark,
      I have noticed now speed improvement too, so I have not used SDHC mode and switched to normal SPI mode which was fast enough for me. Not sure if this is a bug in Processor Expert or in the hardware?

      Like

      • Hi Erich,

        I can not use the SPI to communicate with the SD card because my hardware is already developed. The SD card case has been connected to the SDHC ports of my kinetis K20. To generate the code I followed your posts and I used the Processor Expert 10.2. Must I generate a new code using Processor Expert of Code warrior 10.6? I saw that many people have the same problem, but I haven’t found any solution.

        Many thanks.

        Mark.

        Like

        • Hi Mark,
          it really depends on your wiring: but typically you can use the SDHC pins in SPI mode as well.
          I know that does not help you: But the problem you have is *exactly* what I had in the past too. That’s why I have first the software done, then the hardware. At least the software with all the pin connections has to work before doing the hardware design. I have burned too many times where the reference manual/data sheet was misleading or wrong. For example I had a design where the data sheet indicated that I have interrupt capability on a pin, but it turned out that this was not the case :-(.

          Erich

          Like

        • Hi Mark,
          another thought: You might try out Kinetis Design Studio/Processor Expert for Kinetis which comes with a newer version of Processor Expert (v3.0.1)?

          Like

      • Hi Erich,

        I’m sorry, but I don’t have experience about SD card. It’s my first time. Now I understood what you’re refering to about the SPI mode. But I have some questions about it:
        1. How I can switch from SDCH mode to normal SPI?
        2.Is it enough this switching or it’s necessary to change some parts of code to use the SPI mode?

        Many Thanks for your support.

        Best regards,

        Mark.

        Like

        • Hi Mark,
          If you use my components, then you can simply switch from the SDHC subcomponent to be used as interface to the SD card to use the SPI version of it. You should be find several examples on GitHub as I think I have now all projects using SPI instead of SDHC. No need to change the application code as the driver library is handling this :-).

          Erich

          Like

  44. Pingback: The Return of the 3D Printed Flying Toaster! | MCU on Eclipse

  45. Hi Erich,
    Hello. I have been your follower from long time. Didnt post any questions recently. I have a doubt.

    I am planning to implement a system where in I will need to list all the files in a particular order inside a folder. How do I do it? Where is the information of the files in a folder (directory) stored?

    Like

  46. Pingback: FatFS with Adafruit MicroSD Breakout Board and NXP FRDM-KL25Z | MCU on Eclipse

  47. Hi Erich,
    l must copy many images from an USB key to SD card, but I have a problem. Sometimes some images are corrupted. I proceed following the steps below:
    1 open the file on USB key (in read mode)and sd card (in write/create mode)
    2 read the file piece by piece and I copy each one of them on the sd card;
    3 at the end I close both files.

    I’m working with kinetis k60 microcontroller and FatFS of Freescale.
    Have you got any idea to solve this problem?

    Many thanks in advance for your support.

    Best regards,
    Stefano

    Like

  48. Hi Erich,

    I think that the problem was I passed to the sd writing function more than 512bytes. After this correction, I have made about 20 tests and only an image has been corrupted. I decided to increase the writing size of data to compensate the writing low speed. Anyway to write about 2,5M Byte of images on SD card it’s necessary to wait about 33 minutes. Please note that I have to reduce the SD clock because, writing 512 bytes at standard speed every time, some images were corrupted.

    Many thanks.

    Best Regards,

    Stefano

    Like

  49. Dear Erich,

    I’m writing you because I’ve got a problem about my embedded project where I used Freescale K60 microcontroller an a micro SD card. The firmware reads imagas from SD card and I haven’t got any problem until I have change the micro SD card (I passed from Sandisk 4GB class 4 to Sandisk 8GB class 10) because the first SD card is now out of production. Using the new SD card, sometimes it stops working, the microcontroller cannot read images. I have a MOSFET mounted on the electronic board to drive the SD card power supply, so when the problem emerges, the firmware turns the SD card OFF for 2 seconds and disables the K60 module to communicate with the SD card. Then the K60 turns SD card ON again using the MOSFET and initilizes the module to communicate with the SD card. The software code to enable/disable the K60 SD card module was generated by processor expert. All this is not enought to wake up the SD card. If I reset the software emulator and restarts it again, the SD card starts working. Other solution is to open the SD card case and close it agin and SD card starts working. Unfortunately my software developed to wake up the SD card automatically doesn’t work correctly, but I don’t know why.
    Have you got any advise to help me?

    Many thanks in advance.

    Best Regards,

    Stefano

    Like

    • Hi Stefano,
      it sounds like you are using consumer SD cards. I would not use these cards for any serious projects. I use industrial SD cards (e.g. from https://swissbit.com/). It could be that your card draws too much current? I had this issue in some designs and I had to spend a better power supply source. What is your ‘software emulator’? Do you have other devices on the SPI bus?
      The other thing is that you might still power the card with MISO/MOSI pins high: make sure they are pulled low.
      I hope this helps,
      Erich

      Like

      • Hi Erich,
        I don’t use SPI to cimmunucate with micro SD card, but I’m using the K60 microcontroller peripheral module. The sd card that I’m using is an industrial type. When it stops working, the error I can see is “disk error” and I cannot solve the error. Have you got any idea how to solve the sd card error?
        P.S: my software debugger is the Lautherbach trace and I’m developing software by CodeWarrior IDE.

        Many thanks.

        Best Regards,

        Stefano

        Like

        • Hi Stefano,
          not sure what you mean with ‘peripheral module’. The SDHC one?
          I’m affraid that you have to set a breakpoint where that error occurs. Are you using my version of FafFS or something different?

          Like

  50. Hi. Wanting to add the FatFS to a TWR K21 board and I’m getting an undefined reference to “SDHC1_SelectBusClock”. I presume it’s an issue with the PE component versions, but I can’t seem to find the right match.

    Like

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.