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:
To make things easy for an application (and programmer), I have Processor Expert components created which encapsulate the different blocks:
- FatFs module: the file system is implemented with the FAT_FileSystem component.
- 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.
- 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:
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:
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:
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:
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:
FatFsMemSDHC
For Kinetis, a new FatFsMemSDHC component implements the low-level disk I/O routines:
In the component properties, the speed, card detection and interfaces to other components are specified:
- 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:
In the properties, the interface and pin settings are configured:
The Bus Clock lists several values (‘list of values’) with corresponding speed index from the FatFsMemSDHC component from above:
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:
In the properties it links to the FatFs, RTOS, Timer and Terminal/SCI connection:
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:
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 🙂
Pingback: Virtual COM/USB CDC for OSBDM/OSJTAG | MCU on Eclipse
Pingback: A Shell for the Freedom KL25Z Board | MCU on Eclipse
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???
LikeLike
Hello,
are you using the example project from http://www.steinerberg.com/EmbeddedComponents/FatFsMemSDHC/TWR-MK60_FreeRTOS_FatFs.zip?
The thing is this: BitIO is not supported for Kinetis. If you add your own LED, make sure that you select ‘LDD’ as interface.
See https://mcuoneclipse.wordpress.com/2012/07/26/there-is-a-time-and-date-for-both-worlds/ how the LED needs to be configured for Kinetis (section “LED Example: Dual Interface”.
Let me know if this works (or not).
Erich
LikeLike
Just noticed that the real problem is with DSC_LED componenet which is NOT avaialalble for K60. Then how did you manage to use this component?
what alternative do I have now?
LikeLike
ok, then it makes sense. Alternatively you can use the LED component (http://www.steinerberg.com/EmbeddedComponents/LED): this is the one I’m using all the time. As mentioned in my previous reply: make sure you use the LDD interface (see https://mcuoneclipse.wordpress.com/2012/07/26/there-is-a-time-and-date-for-both-worlds/).
Hope this helps,
Erich
LikeLike
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?
LikeLike
I now know why LED component works…..so thanks for the first part. Please over look the first comment
Now please help me with second error “RX Buffer”/RxBuffer has not assigned the component (file: Drivers\sw\FSShell.drv” ….I am not sure where to begin !!!!!!!!!
LikeLike
Yes, this is my fault :-(. It is fixed now in the FSShell component 1.217 on http://www.steinerberg.com/EmbeddedComponents/FSShell.
Erich
LikeLike
Hello,
that “RX Buffer” thing is clearly my fault, sorry about that. I was running into this myself last night too, and have released a new version of the FSShell component on http://www.steinerberg.com/EmbeddedComponents/FSShell/home.htm. There is as well a fix in the FreeRTOS component in case optimizations are used: http://www.steinerberg.com/EmbeddedComponents/FreeRTOS.
Hope this helps,
Erich
LikeLike
Hi….Now we are left with four errors only.
At following line numbers(these should be same for you as well…..as this is your code)
line number 2787 in file: Drivers\sw\FSShell.drv
line number 2854 in file: Drivers\sw\FSShell.drv
line number 2884 in file: Drivers\sw\FSShell.drv
line number 2928 in file: Drivers\sw\FSShell.drv
LikeLike
Hi,
the errors indicate that it cannot find the Ringbuffer. For Kinetis K60, in the shell you should have LDD Enabled with a RingBuffer and and a Serial interface, and the non-LDD disabled. Otherwise send me an email to erich _dot_ styger _at_ hslu _dot_ ch.
Erich
LikeLike
Pingback: Sports Timing System in a Lunch Box | MCU on Eclipse
Hi this component supports JM128?
What is the wiring for SD connection? needs other component?
thank you
LikeLike
Hello, yes, JM128 is supported (as any ColdFire or S08). I use it for example with the TWR-LCD board. You can see a possible wiring on that TWR-LCD schematic (http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-LCD). And no additional components required, similar to the Kinetis ones. Maybe have a look at http://www.steinerberg.com/EmbeddedComponents/Examples/Example_CN128_FatFS/home.htm which uses the CN128.
LikeLike
Pingback: Arduino Data-Logger Shield with the FRDM-KL25Z Board | MCU on Eclipse
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
LikeLike
Hi Juan, thanks for that information. I have had no time to try it out on all my platforms, so good to know that it still is working ok for the GB60 too. Best regards, Erich
LikeLike
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
LikeLike
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
LikeLike
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.
LikeLike
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.
LikeLike
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>
LikeLike
Read/Write speed heavily depends on buffer size. The fact that you have a 30MB/s on your card does not mean you ever will get this performance say with a SPI clock of a few MHz. Simply impossible.
Have a look at the comments from Chandler in https://mcuoneclipse.com/2012/11/18/arduino-data-logger-shield-with-the-frdm-kl25z-board/
LikeLike
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!!
LikeLike
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
LikeLike
Hi Marc, which read/write buffer did you change, and to which value?
LikeLike
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….
LikeLike
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?
LikeLike
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.
LikeLike
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.
LikeLike
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….
LikeLike
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.
LikeLike
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.
LikeLike
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.
LikeLike
p.s. the K70 project after all that runs :)…. not the same as the K60 project which benchmarks, has the shell etc but still…. awesome! thx
LikeLike
Hi Marc, great to hear that things are running now. Do you miss something in that K70 project?
LikeLike
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.
LikeLike
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.
LikeLike
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 🙂
LikeLike
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).
LikeLike
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.
LikeLike
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.
LikeLike
cool… getting the K60 board tomorrow … is that command interpreter still based on the LGPL version from FreeRTOS 7.0?
LikeLike
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).
LikeLike
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.
LikeLike
Hi Marc,
looks like your finding your way :-). It might be easier to create a new project with the new project wizard for the K60F120M and then copy the needed source files. You can copy the Processor Expert components too: simply copy and paste them. I thought I had a post on this, but cannot find it right now. But you can use drag&drop as well: https://mcuoneclipse.com/2012/03/08/dragdrop-in-processor-expert/
LikeLike
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…
LikeLike
The LCD support does not matter at least for this project. I see if I have a K60F with me (I know I have one at the university). As for the serial port: is the correct OSJTAG firmware on the board, as only newer OSJTAG support USB CDC (https://mcuoneclipse.com/2012/08/04/virtual-comusb-cdc-for-osbdmosjtag/)
LikeLike
FYI, I have OSBDM/OSJTAG v31.21 on my TWR-K60F120M
LikeLike
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!
LikeLike
I have completed my port to the K60F120M board and committed on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K60F120M
LikeLike
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
LikeLike
Hi Quincy,
you are right, there is no such *.PEupd file available. Instead, you can grab the components as described on
https://github.com/ErichStyger/mcuoneclipse/wiki/Getting-Started
Let me know if this works for you.
LikeLike
That was easy! I’m up and running without any problems, thanks!
LikeLike
Hi Quincy,
cool, good to hear that 🙂
LikeLike
Pingback: Serial Bootloader for the Freedom Board with Processor Expert | MCU on Eclipse
Someone just pointed out to me – the FatFsMemSD component doesn’t instantiate a Write Protect switch GPIO input…
LikeLike
Hi Marc,
indeed, I missed that as I had not used it. Anyway I think I need to change the Card Detect pin to a general BitIO pin too?
LikeLike
looks like there’s no interrupt associated with bitIO, which you need for card detect, no?
LikeLike
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?
LikeLike
Hi Marc,
just wanted to let you know, that I have implemented it 🙂
LikeLike
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.)
LikeLike
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.
LikeLike
Pingback: Added Write Protection Pin to FatFsMemSDHC | MCU on Eclipse
Pingback: USB MSD Host for the FRDM-K20D50M Board | MCU on Eclipse
Pingback: Hacking the Heating System for Cooling – Geothermal Drilling with extra Benefits | MCU on Eclipse
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.
LikeLike
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?
LikeLike
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
LikeLike
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
LikeLike
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.
LikeLike
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
LikeLike
Yes, this is possible.
I think I always used it with an RTOS, but you can use it bare metal too. Then you simply cannot have parallel access to files, but that should be ok for you.
LikeLike
Hi,
I’m using it for now without an OS.
Works great.
The only consideration is that closing a file might take a while (in my system, data is read through interrupts which keep working so data isn’t lost).
Hope this helps
LikeLike
Hi,
thanks for the confirmation!
LikeLike
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?
LikeLike
Hi Arun,
it could be multiple reasons. Are you using my example from https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K60F120M?
Otherwise: you have to debug your application to see what is going on.
LikeLike
Yep the same example.Also my sd card is formatted as a FAT32 file system.Will the program work for all FAT formats?(FAT32,FAT16,etc)
LikeLike
Yes, they are supported (or I had no problems with it). Try using a different card, and try using a smaller card (I tested up to 8 GByte cards).
LikeLike
i am also getting same error. but for me it happens sometimes (not always), that too after reading/writing for sometime. USB works fine for sometime and i start getting this error. any idea about this?
LikeLike
I have not seen that myself, and really I have no idea (yet) 😦
LikeLike
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
LikeLike
Hi Arun,
yes, it can be used without an RTOS (but it is simpler with an RTOS).
There are a lot of good tutorials here: http://www.freertos.org/FreeRTOS-quick-start-guide.html
LikeLike
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
LikeLike
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?
LikeLike
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.
LikeLike
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
LikeLike
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?
LikeLike
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
LikeLike
Maybe this could be someting: I’m using FatFs R0.08a, but I see that the latest release is R0.10a (http://elm-chan.org/fsw/ff/00index_e.html). I have not checked the changes yet, but maybe this is something fixed since then?
LikeLike
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
LikeLike
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?
LikeLike
Hi Abdullah,
have you loaded the latest version from https://sourceforge.net/projects/mcuoneclipse/
?
And do you have a ‘Shell’ component available in your components list? The CLS1 is made from the Shell component.
LikeLike
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
LikeLike
Hi Abdullah,
looks like you have built it earlier with an old version. Simply delete that include inside Events.h (line 27 or 26).
LikeLike
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 “
LikeLike
Try using
FAT1 dir
(the latest implementation uses the component name in front of the command)
LikeLike
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
LikeLike
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?
LikeLike
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
LikeLike
So this means that the low level block operations are working, but not the file system on top of it. Have you tried using another SD card?
LikeLike
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
LikeLike
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.
LikeLike
Yes i Have called the timeout component.
However i am unaware of how to check the spi speed in Highspeed mode.
LikeLike
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?
LikeLike
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,
LikeLike
You are welcome 🙂
Yes, the beauty using Processor Expert is that a project can be very easily changed to another microcontroller:
LikeLike
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
LikeLike
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.
LikeLike
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
LikeLike
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.
LikeLike
Hi Bogdan,
to answer your question about a BM example:
have a look here:
https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K60F120M
Erich
LikeLike
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.
LikeLike
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.
LikeLike
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
LikeLike
see freescale community thread/304017
if you use bigger block sizes and larger transfers you’ll get speed increases…. 10MB or 100MB files will run faster.
LikeLike
Pingback: First Steps with the Freescale TWR-K64F120M | MCU on Eclipse
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.
LikeLike
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?
LikeLike
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.
LikeLike
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.
LikeLike
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.
LikeLike
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?
LikeLike
Pingback: FTF: FRDM-K64F, Kinetis Design Studio and Kinetis SDK | MCU on Eclipse
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
LikeLike
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!!! 😀
LikeLike
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 !!!
LikeLike
no worries, good if things are working now for you. The warning could have been because that method was maybe disabled? Just a guess.
LikeLike
Pingback: FRDM with Arduino Ethernet Shield R3, Part 4: MinIni | MCU on Eclipse
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
LikeLike
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?
LikeLike
so according to that link, the disk_read() function should guarantee the alignment…
LikeLike
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.
LikeLike
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
LikeLike
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?
LikeLike
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….
LikeLike
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
LikeLike
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….
LikeLike
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.
LikeLike
Ok, let’s do this, tell me the best way to coordinate I will try your new versions!
Mevon
LikeLike
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?
LikeLike
Pingback: Multi-Drive Support with FatFS | MCU on Eclipse
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.
LikeLike
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
LikeLike
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
LikeLike
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.
LikeLike
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.
LikeLike
Pingback: Tutorial: Playing MP3 Files with VS1053B and FRDM Board | MCU on Eclipse
Pingback: Code Coverage for Embedded Target with Eclipse, gcc and gcov | MCU on Eclipse
Hi. Do you have an example for the JM128? I tried downloading this example for the CN128, but the link is broken.
http://www.steinerberg.com/EmbeddedComponents/Examples/Example_CN128_FatFS/home.htm
Thanks.
LikeLike
No, I don’t have such a project at hand for the JM128, as this board did not had an SD card on it.
But there are other projects available on GitHub (not sure if you have seen them): https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples
I hope this helps. Otherwise I hope the information in this article are good enough to get you up to speed.
LikeLike
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
LikeLike
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
LikeLike
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
LikeLike
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?
LikeLike
I guess you are using a Kinetis SDK project? If so, the Kinetis SDK comes with a completely different approach and API, and many components are not supported.
LikeLike
Hi Erich,
Yes I am using Kinetis SDK project. What is the work around? How do I solve this problem?
Can I just use KDS without Kinetis SDK? Will that solve all my problems?
LikeLike
The solution is to create a project without Kinetis SDK enabled. And yes, this should solve your problem.
LikeLike
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”
LikeLike
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).
LikeLike
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.
LikeLike
Hi Vishal,
yes, the K22 support is already included in v3.0.0, so no need for an extra package.
Erich
LikeLike
Hi Erich,
I tried https://mcuoneclipse.com/2014/12/27/usb-with-the-freescale-frdm-k22f-board/ the other day and it perfectly works fine with K22F board. K22F board has optional SD card support and I am planning to use it. But the PE component SDHC_LDD seems like does not work. I tried without KSDK. Can you please help me out with this?
LikeLike
Hi Vishal,
From the user guide (http://cache.freescale.com/files/microcontrollers/doc/user_guide/FRDMK22FUG.pdf):
… and an SDHC slot (for use over SPI).
So I believe it supports SPI only?
LikeLike
Hi Erich,
Yes it supports SPI. I did not get your point exactly Erich.
LikeLike
I believe that SD card socket and how it is wired on the board only supports SPI, not SDHC.
I remember seeing something about this in the forums, but not sure anymore if this was for FRDM-K22F or FRDM-K64F.
LikeLike
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?
LikeLike
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.
LikeLike
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?
LikeLike
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.
LikeLike
Erich,
thanks for your advice, it’s very helpful:) regards
LikeLike
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.
LikeLike
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?
LikeLike
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.
LikeLike
Hi Erich,
Thanks a lot. It worked. My bad, I did not notice it.
LikeLike
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
LikeLike
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?
LikeLike
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.
LikeLike
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
LikeLike
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)?
LikeLike
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.
LikeLike
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
LikeLike
Pingback: The Return of the 3D Printed Flying Toaster! | MCU on Eclipse
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?
LikeLike
Hi Vishal,
Have a look at the FAT1_PrintDirectory() function which calls PrintDir(). This function lists the files in a direcory.
Erich
LikeLike
Pingback: FatFS with Adafruit MicroSD Breakout Board and NXP FRDM-KL25Z | MCU on Eclipse
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
LikeLike
Hi Stefano,
it is really hard to tell what could go wrong. My guess would be a reentrancy problem? I always have used the original FatFS from ElmChan, and not the one from Freescale. One thing you could look at if it does any dynamic memory allocation (malloc()?). Otherwise, if it is using FreeRTOS, that the interrupts are set correctly (have a look at https://mcuoneclipse.com/2016/08/28/arm-cortex-m-interrupts-and-freertos-part-3/).
LikeLike
Hi Erich,
Can I send you a piece of my code where I copy the images from USB key to SD card? Have you got an email address where I can send it?
Many thanks
Best regards,
Stefano
LikeLike
Hi Stefano,
You find my email address on the About page of this blog.
But not sure if I can help, as just looking at the code might not be enough.
Erich
LikeLike
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
LikeLike
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
LikeLike
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
LikeLike
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
LikeLike
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?
LikeLike
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.
LikeLike
Hi Alex,
you should have the SHDC component in your project. And it should have a method SelectBusClock(): if that one is not enabled: enable it.
LikeLike