Jump to content

Wear Leveling on SD Card


Duggle

Recommended Posts

I'm using a core32 to log data from environmental sensors.

I'm concerned that writing 100bytes to a file every few seconds would result in the modification to the SD card's file allocation table (FAT) that over time may cause it to fail.

As a result I've made my logging code so that it caches the log records and writes them in one pass 10kbytes at a time.

I have the core hooked up with an analog input monitoring a signal derived from the 12V pre-regulated supply. If the power fails (or is switched off) the falling voltage is detected and the cache is written to disk followed by a call to FILE_WriteClose() .

My assumption is that the FAT is only modified when the FILE_WriteClose() is called.

I havn't looked at the filesystem code underlying the midibox FILE module, so my questions are:

Does the SD card have inbuilt wear leveling?

Does my strategy of write caching help the situation?

Assuming I'm writing lots of data over time what is the best strategy for getting maximum life fro m the SD Card?

Link to comment
Share on other sites

Interesting topic and usecase for a core32 :)

The SD standard does not specify wear levelling, but there are manufacturers, that explicitly provide it:

http://www.memorydep...t.asp?catid=isd

Using such a 2 GB card, one would have to write 10 TB of data, before it becomes unusable. So I would buy an "industrial" one and not worry too much about optimizing/caching on the software side.

Bye,

Peter

Edited by Hawkeye
Link to comment
Share on other sites

Industrial strength sounds like a good idea in any case!

I suppose if FILE_WriteClose() results in a change to the FAT table then the caching which I've written and somewhat tested would result in a x100 reduction in "wear" in the scenario I described.

So whilst the application can afford 10k of RAM I guess I'll keep it in.

Here's the code:

#define db MIOS32_MIDI_SendDebugMessage

/*

 * DataLog.c

 *

 *  Created on: 21/06/2012

 *      Author: Dug

 */

#include <mios32.h>

#include <FreeRTOS.h>

#include <task.h>

#include <semphr.h>

#include "file.h"

#include <string.h>

#include "debug.h"


#define CACHE_SIZE	10000

u32 DataLog_Index;

u8  DataLog_Cache[CACHE_SIZE];

xSemaphoreHandle DataLog_Mutex;

u8 DataLog_Held;

void CacheCommit();


void DataLog_Init(){

	if(DataLog_Mutex==NULL)

		DataLog_Mutex=xSemaphoreCreateMutex();

	xSemaphoreTake(DataLog_Mutex,portMAX_DELAY);

	DataLog_Index=0;		//start of cache

	xSemaphoreGive(DataLog_Mutex);

}


void DataLog_AddLine(char* s){				//cache null terminated string

	char eol[3]="\r\n";						//Windows compatable EOL

	xSemaphoreTake(DataLog_Mutex,portMAX_DELAY);

	db("AddLine:%s",s);

	if ((strlen(s)+3+DataLog_Index)>CACHE_SIZE){

		CacheCommit();					//cache now empty

		db("cache comitted.");

	}

	strcpy((char*)&DataLog_Cache[DataLog_Index],s);

	strcat((char*)&DataLog_Cache[DataLog_Index],eol);

	db("line cached:%s",&DataLog_Cache[DataLog_Index]);

	DataLog_Index+=strlen(s)+2;				//include eol but not null


	xSemaphoreGive(DataLog_Mutex);

}


void CacheCommit(){					//only called from these functions

	s32 r=FILE_FileExists("DataLog.txt");

	switch(r){

	case 0:	FILE_WriteOpen("DataLog.txt",1); //create new

			db("DataLog Create");

			break;//create

	case 1:	FILE_WriteOpen("DataLog.txt",0); //re-open existing

			db("DataLog Append");

			break;

	default:db("Datalog.txt problem");return;

	}

	FILE_WriteSeek(FILE_WriteGetCurrentSize());

	FILE_WriteBuffer(DataLog_Cache,DataLog_Index);

	DataLog_Index=0;

	FILE_WriteClose();

}


void DataLog_Commit(){							//write cache physical sd card

	xSemaphoreTake(DataLog_Mutex,portMAX_DELAY);

	CacheCommit();

	xSemaphoreGive(DataLog_Mutex);

}


void DataLog_HoldSafe(){				//commit to disk but don't release mutex (we've lost power)

	if (DataLog_Mutex&&(DataLog_Held==0)){	//only if DataLog has been initializied

		xSemaphoreTake(DataLog_Mutex,portMAX_DELAY); //take but don't release

		DataLog_Held=1;

		CacheCommit();

	}

}


void DataLog_UnHold(){					//power back up so release logging for use by tasks

	if (DataLog_Held){

		xSemaphoreGive(DataLog_Mutex);	//release mutex now

		DataLog_Held=0;

	}

}


void DataLog_PrintFile(){

	file_t F;

	char s[120]="";

	u8 b[2]={0,0};

	xSemaphoreTake(DataLog_Mutex,portMAX_DELAY);


	if (FILE_ReadOpen(&F,"DataLog.txt")<0){

		db("DataLog_Printfile problem");

		xSemaphoreGive(DataLog_Mutex);

		return;

	}

	while(FILE_ReadByte(&b[0])>=0){	//read until EOF

		if(b[0]=='\r')continue;

		if(b[0]=='\n'){

			b[0]=0;

			strcat(s,(char*)b);						//null terminate

			db("->%s<-",(char*)s);					//print line

			strcpy(s,"");							//reset

		}else

			strcat(s,(char*)b);						//add char

	}

	FILE_ReadClose(&F);

	xSemaphoreGive(DataLog_Mutex);

}


Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...