SD/MMC From the ground up

@koetting:

Have you installed the mmc & microfat2 libraries properly? It sounds like the compiler isn't finding the code. The folders need to be in arduino\hardware\libraries.

@New Colin:

Problems like this are usually related to memory depletion. Have a look and see if any memory allocations or large static buffers are being declared.

@New Colin:

I have a sketch at http://docs.google.com/Doc?id=dqhc6fg_0gmk96kdd which uses the DS1307 with sirmorris's SD card software successfully. There's a LOT of code in there which will be totally irrelevant to you but I'm sure you can isolate the bits you need. If not, PM me & I'll cut the code down for you.

JB

Hi all,
and thank you for this really good documentation! Because of this, I'm convinced to try arduino for a study project I'm working on!

However, one question remains... and I hope it's not too stupid :wink: .. I tried to figure this out for hours now, but seemingly cannot decide it on my own.

The issue is this: we also depend on having fast PWM signalling - at a time-resolution of at least 64 micro-seconds / i.e. a minimum frequency of 15.625 kHz .

From the forum I have learned so far that PWM is possible on pins 5,6 (controlled by timer0) and 9,10 (timer 1), and 3,11 (timer2).
Since timer0 is also used for other stuff than pwm, I don't want to change it to have higher frequency... pins 9,10,11 are used by SPI anyway, which leaves us only with pin 3.

My question: Does somebody know whether setting timer2 to such a high frequency has any side-effects with the SPI-protocol? Maybe somebody might even try this shortly with a running setup? This would be amazing and probably save me days of studying Atmel's datasheet :cry:

Thank you already in advance!

PS: Here's a (hopefully working) post indicating how to change the PWM frequency of timer2: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1234764073#12 or http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/12#4

That is an excellent summary. If you put that onto a single page somewhere please
post the link.

(* jcl *)

@johanzebin: I don't know about this. The information would be great to add to the article though, so please let us kn ow how you get on. I think your best approach is to stick a frequency meter or oscilloscope on the PWM pin and look at what happens when you run the SPI code. You could write a little loop which writes or reads from the card and display the timings with and without tweaking the PWM rate. Experiment, have fun :slight_smile:

@jluciani: thanks! I looked into putting this up in the playground, but I don't have the time to learn wikispeak right now :frowning: Any volunteers?? :wink:

It seems to me that one ought to be able to write a MUCH smaller implementation for FAT16 on SD/MMC if all you want is read-only, AND you're willing to take into account the fact that accessing the flash card is relatively fast (compared to a floppy, say) so you won't need to cache quite as much info.

Does anyone know of such an implementation?

and in very simple mode, here....
I would like to read text [no writing] from a txt file on an SDcard, and send it to an LCD using serial.print... I have looked high and low through all the examples, but being um noob, I am having a heck of time figuring out how to do that. Could someone hold my hand, e.g. a code example? I use a 4x20 display, and of course there are control characters. I imagine I have to format the text for half the screen then the other half, each new section on a new line in the text file, padding each line to proper length [since I can't figure out how to parse/split text]... I am also having some um conceptual problems on how to go from bytes -> ascii, but I guess that will just be obvious in the code example, for which I certainly and hopefully do thank you in advance! I hope.

thanks,
David

I haven't got the time to play ATM, but you need to do the inverse of devicePrint.

initialise()
{
  bytesInBuffer = 0;
}

char getCharFromBuffer()
{
  if (bytesInBuffer == 0)
  {
     readSectors(sector, buffer, 1);
     ++sector;
     bytesInBuffer = 512;
  }

  --bytesInBuffer;
  return buffer[bytesInBuffer];
}

A byte is an 8-bit wide data type. So is a char. The distinction is usually whether the value is treated as signed or not. The ansi character set only uses 127 values because logically it's unsigned.

Do you really need SD for characters for an LCD display? Just how much text are you wanting to display??? Wouldn't it be better to store the strings in PROGMEM?

C

Am I getting this right, if I set up an arduino board, using the SPI pins connected to an SD card socket, with proper resistances;etc, I can log(save) data on an SD card? Then after saving data on the card, I can remove the card from the card socket, bring the card to a PC, and enter the data directly to the PC via one of the computer's ports, such as one of the USB ports? Can I do this by using the uFAT library?

Or do I have the wrong idea?

I've already downloaded uFAT2, uFAT EXAMPLE, DEVICE PRINT, DEVICE PRINT LIBRARY, DEVICE PRINT DEMO. Are the uFAT2 & DEVICE PRINT libraries for different purposes?

I've uploaded uFAT example and DevicePrint demo to my arduino board and, as soon as I connect the card socket to the SPI pins I'm ready to give it a try. ** Is there anything else I should do?** Is there anything that should be done with the SD card first? Does it need to be pre-programmed for FAT operation?

Thanks in advance
PWO

Hi there,

yes - you're getting it right.

uFat allows you to find the start sector of a file on a card. Deviceprint allows you to write strings to sectors belonging to a file the card.

All you need to do to read and write to the card is make sure it's formatted as FAT16 and copy a big old file on there in order to write into it.

How do I format the card for Fat16 ?
And copying a big old file, from where? Ya kind of lost me there. :-[
Can I store numerical data on the card?
Sorry for asking all the questions. It takes a while for this stuff to sink through my old skull.

Thanks for the help

If you're using Linux you're on your own I'm afraid - unless there's anyone reading that would care to share the power??!

On Windows it's easy - open MyComputer and right-click the drive allocated to the card. Select Format from the context menu. For the filesystem select FAT. Not FAT32, plain ol' FAT. Click start and a few seconds later you're done.

Now imagine how much data you're going to write. Find or create a 'donor' file on your harddrive. The contents are irrelevant - you'll be overwriting them. It's the size of the donor file which is important. Too small and you'll lose data 'off the end' when you read it back in the desktop computer. Once the donor file is ready, make sure it's named in 8.3 fashion and copy it to the card. Put the card to the arduino.

You can store whatever you like on the card. I recommend strings because they're the most portable format. Use DevicePrint and putting strings in the file is as easy as using the Serial.print functions.

Remember though: Every time the program runs it will start writing at the start of the file. If you don't want this to happen, then you'll have to think awhile and imagine a scheme to help!

:wink:

OK, I got an SD card formatted. I left the formatting procedure in default position, which was Fat, and 16k allocation, then it formatted alright. After that I loaded a file of 86 kb on the disc. Am I in good shape ?

I don't know for sure what the 16k allocation means. Does it mean that each file put on the disc can hold up to 16kbytes? I tried a smaller allocation of 512bytes at first, but after formatting for a while, windows stopped and said: "Windows cannot complete formatting". So I went with the default allocation of 16k, which worked.

I want to use the disc to store numerical data, which will be electronic pulse counts. The electronic pulses will come from the speed sensor of a motorcycle. The arduino board will detect and count the pulses per second, then the pps count will be stored on the SD card. I will be counting the pulses during a 15 second test run of the bike, and probably making more than one 15 second run each day that I make test runs. Then I want to remove the card from the arduino hook-up, take it into a pc and enter the data by using one of the pc's USB ports. If this is all possible.

That means there will be starts and stops of the arduino, so then each test run will need to be stored on a different location of the card. You mentioned that each time a program starts, the disc storage restarts at the beginning of a file, that could be an oh-oh. I've been able to perform this operation using external EEPROM.

Thank you

I don't know for sure what the 16k allocation means.

The allocation is the "block size" for the file, and it means that all your files will use AT LEAST 16K of storage space, and will always use a multiple of 16K of storage. Even if they're only 10 bytes long. The actual length of the CONTENTS of the file is stored separately, so you shouldn't need to worry about this other than that the files will take up more space than you expected.

Yes you're in good shape. How big are your sample sets? Counts per second implies you have 1 second resolution over 15 seconds. That's not exactly a google-smashing database, you should be able to pick and choose your method of saving. There are many ways to do this.

  • store output variables in Arduino's EEPROM between runs
  • write the code so that the data is written over a session which consists of many runs
  • make sure all the target files are named sequentially, empty or filled with a known value and scan each in turn at the start of a run to find an 'empty' one
  • scan the file after a run to find the end and begin writing there
    And I'm sure there are many others. Just use your imagination!

If there's some time between runs I'd plump for something that's fail-safe, like the last option above.
C

sirmorris and westfw:
Thank you, thank you very mauch*(E.P.)*

Oh no, here I am again.

I've got everything together. When my arduino is operating in "DevicePrint demo", on the serial monitor I get "ERROR: couldn't initialize card".

Operaring in "uFat2 example", I get "ERROR: mmc init failed".

I seem to be missing a whole bunch, here. Doesn't data or text have to be entered somewhere ?

sirmorris stated
Once the donor file is ready, make sure it's named in 8.3 fashion and copy it to the card. Put the card to the arduino.

What is 8.3 fashion?

I saved a large chunk of text on my SD card as "text", because that's the only choice given. Could that be a problem?

Perhaps my voltages are off. I don't have 1.8K resistors, so I used 2.2K in series with 3.3K as my voltage dividors, taking the output from across the
3.3K to gnd, results in 3.v.

I'm using an SD/MMC Mini Board from FUTURLEC (SD/MMC Mini Board) It has the card socket and other components mounted, including 10K resistors from socket pins to 3. v , which, apperently are to hold the pins HIGH. However, there are cutouts that can eliminate the 10K's.

Sorry for being such an old know nothing, and a probable pest. :-[

PWO

What is 8.3 fashion?

Heh. Short filenames; DOS 1.0 compatible: no more than 8 characters in the NAME part, not more than three in the "extension" part. No "funny" characters, probably only uppercase.

It's strange how certain phrases linger, even thought they're "obviously" pretty obscure.

Gentlemen:
This old boy is still having problems.

In devicePrint demo, I get: "couldn't find data.txt on card"

In uFat2 example, I get: "directory of files on card", "0 HOLA TXT"(name of file), "1 files found.", "data.bin not present on card."

I must have done something wrong when I loaded the SD card with bunch of text , and saved it as hola.txt.
I could use just a touch more advice at this point. Thank you.

I'm using an SD/MMC Mini Board from FUTURLEC (SD/MMC Mini Board) It has the card socket and other components mounted, including 10K resistors from socket pins to 3.3 v , which, apparently are to hold the pins HIGH. However, there are cutouts that can eliminate the 10K's.

@packrat -

You've got it then. The deviceprint demo needs a file called "data.txt" - it can be nothing else.

With your SD plugged into you computer, just open up notepad (assuming windows), and make a file consiting entirely of the letter "B" or something. Keep copy-n-pasting big blocks of the letter B. Save teh file to the card with the filename "data.txt". Check the size of the file in explorer - it should be AT LEAST 1k. Eject the card and put it in the arduino card holder.

Run the device print demo. Open the serial monitor in the arduino IDE. When the "done" message appears, take the card out of the arduino and put it back into the computer. Open the file - there should be a long list of timestamps.

The bigger you intially make the file, the longer it will keep writing. It will keep going until there is less than 512bytes left IN THE FILE, the remaining bytes will be unchanged from whatever you filled it with initially (B=blank in my head).