SD/MMC From the ground up

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).

Thank you,Ttrialex.

I got that to work. I put in about 15k of data, and got back time stamps up to approx 29450. I guess that means about 30 seconds of writing. That made me happy.

Now if I can just figure out how to enter data, collected from an exterior source, to the card using the arduino. By that I mean, entering data on one of the arduino pins, binary 3 for instance, then have that data relayed to and entered into the SD card.
I'll be much happier if I can get that to happen.

Does the uFat example have anything to do with entering data?
The uFat example gives this result: "1 files found.", "data.bin not present on card."

Much thanks for the help

@packrat

How much arduino or avr experience do you have? just out of interest, because sometimes it is easier to help someone when you know what they can or can't understand.

Anyway the deviceprint demo file really does show you a lot, it is an excellent example. Look for these two lines

    dp.print_P(PSTR("Time is now: "));
    dp.println(millis(), DEC);

So the first line shows you how to send a string to be saved to the card. The second line shows you how to log a variable, and go to a new line.

So you could write something like

dp.println(analogRead(0), DEC);

and it would log the value on analog pin 0.

Posted by: trialex Posted on: Yesterday at 22:55:01
@packrat

How much arduino or avr experience do you have? just out of interest, because sometimes it is easier to help someone when you know what they can or can't understand

.

I'm very new at it, but I have managed to put together a couple of sketches that are somewhat above Blink, but much less complicated than this one. Borrowing from arduino's playground, I put together sketches from which I can enter external data to an arduino, save the data to external eeprom, then read it back using a seperate arduino board. Not real complicated, and rather crude, I'm sure.

These SD sketches are rather complicated for me, since some of the commands aren't even listed in Arduino's Reference file, and the tutorial was obviousloy written for those that have had quite a lot of experience with, not only arduino, but with microconntrollers, programming and computer science in general. There are many terms in the tutorial that I had bever heard of, which were apparenty from old time computerese, much of it being terms that the reader "should already know" Some of the nomenclature would make an army manual read like "Richard and Jane".

However, I will thank you for this last bit of information. I had pretty much come to that conclusion myself. If it works that will be great, if not, I will go back to plan 'A.67', which will be just using the eeprom, for data logging. I don't plan on going much further than that.

Some other time.

Looks like I got back just in time! Don't Jump!!

Unfortunately you can't pick up a violin and instantly play like Yehudi Mehuhin. If programming was easy I'd be out of a job...
;D

I'm sorry to hear you're having a hard time with this. I think if you just keep plugging away all those strange sounding terms will become familiar and slot into some order. It won't happen overnight but it's like building a lot of little bridges, you need the keystones in place to get any further.

You should be able to get from my demo app to a fully fledged data logger in very few steps. Would it help if I provided a new sketch which did the grunt work leaving only the bits needed to gather the data?

sirmorris asks:
Would it help if I provided a new sketch which did the grunt work leaving only the bits needed to gather the data?

No, I'd rather that you didn't; I think it would be unfair of me to ask you to do that.

I needed to know where, on a board and in the sketch, to inject electronic pulses so that they could be counted, timed, then have that data saved in a transportable memory chip or card. Mr trialex helped me with that. So, I think I can take it from this point.(I hope)

In another sketch I used "attachInterrupt()" to allow pulses to be fed to the board at pin3, and "millis()" plus other needed code to time and count the pulses, then used code , which I found in arduino's playground, to send, and receive, the resulting data to, and from, external EEPROM. I kinda thought maybe I could do something similar with your (sirmorris's) "SD/MMC from the ground up" coding.

Using an SD card to save data collected from Harley's speed sensor, by an arduino board, I should be able to leave the board attached to the bike, and, after a test run, remove the card only, grasp the card between forefinger and thumb, run to my computer and enter the data, which I almost killed myself to collect, directly into the PC by use of USB port. I have high hopes for this sketch.

By the way, part of my confusion resulted from the suggestion that both Ufat2 example and DevicePrint demo be downloaded. (Maybe you didn't suggest that both be downloaded.) Anyway, I got the impression that both were necessary, and I guess that's not the case. :-/

I'm not sure if I've ever heard music by that fiddler you mentioned, but old Eric Clapton is a dang good git-tar picker. :slight_smile:

sláinte (on St. Paddy's day)

This should help. please bear in mind it's fresh off my fingertips and I haven't had a chance to try it out.. :o

I think it kind-of does what you need.. you should develop the interrupt pulse counter and get that all working printing its results to the serial port, then transplant the counting code into here. Add the stop button and you're good to go.

// !! use the device print demo, and delete the setup & main from it
// !! replacing it with what you see here.


 // or whatever
#define STOP_PIN 3

void setup(void)
{
  Serial.begin(115200);

  // some users have reported cards which won't initialise 1st time
  //
  int n = 0;
  while (mmc::initialize() != RES_OK)
  {
    if (++n == 10)
    {
      error_P(PSTR("Couldn't initialise card"));
    }
    delay(500);
  }

  if (!microfat2::initialize(sectorBuffer, &mmc::readSectors))
  {
    error_P(PSTR("Couldn't initialise microfat"));
  }

  // find the start sector and length of the data we'll be overwriting

  unsigned long sector, fileSize;

  if(!microfat2::locateFileStart(PSTR("DATA    TXT"), sector, fileSize))
  {
    error_P(PSTR("Couldn't find data.txt on the card"));
  }
  
  // The dp library won't write past the end of the allowed space.
  // Indeed, it will only write up to the nearest sector boundary at
  // the end of the file on the card. If your target file is 1000 bytes,
  // only 512 will be written over. The remaining will be left as they
  // were when written to the card.

  dp.initialize(sector, fileSize / 512, sectorBuffer, proxyWriter);
  
  memset(sectorBuffer, '.', 512);

  // get pulses
  //
  attachInterrupt(0, interruptHandler, RISING);

  // make the stop button pin an input, and set it's pull-up resistor
  // the switch should be push-to-make, and connect the pin to ground.
  //
  pinMode(STOP_PIN,INPUT);
  digitalWrite(STOP_PIN,HIGH);

  print_P(PSTR("All initialised OK!\nWriting..."));
}



// this variable is set by the interrrupt routine once a second.
//
// the volatile keyword instructs the compiler that the value
// can change at any time, and should therefore not be cached
// or otherwise involved in optimisations.
//
volatile int counts;

// this variable gets set to true by the interrupt routine when
// a second has elapsed and the count is ready. it's set to false
// by the main loop when the data has been written to the card.
//
volatile bool dataIsAvailable = false;


// every time the sensor pulses low to high, we get called here.
// static variables retain the value they're given between calls.
//
void interruptHandler()
{
  static int ct = 0;
  static long lastMillis = millis();

  ++ct;

  long now = millis();
  if(now - lastMillis > 1000)
  {
    ct = 0;
    counts = ct;
    lastMillis = now;
    dataIsAvailable = true;
  }
}


void loop(void)
{
  if(dataIsAvailable && dp.m_sectorsAvailable > 0)
  {
    // reset the flag variable so we don't keep writing the vale over and over...
    // put the count value into the file. we don't _need_ to flush here, but it
    // will ensure that we don't lose any values as we can stop logging at any time.
    //
    dataIsAvailable = false;
    dp.println(counts, DEC);
    dp.flush();
  }

  // attach a button to some pin and define this variable to let the compiler
  // know which one it's on :)
  //
  if(digitalRead(STOP_PIN)==LOW)
  {
    // switch on the on-board LED to say that the sketch is stopped
    digitalWrite(13,HIGH);

    for(;;) // ever
    {
      // this simply stops the sketch dead, so the card can be removed.
    }
  }
}

Charlie

Thanks, sirmorris, you needn't have done all that, and I appreciate it.

I will give it a try, or "give it a bit of a go" as they say in those old English movies.

Hehe you're welcome! I hope the hog appreciates all this attention :wink:

Posted by: sirmorris Posted on: Yesterday at 00:01:38
This should help. please bear in mind it's fresh off my fingertips and I haven't had a chance to try it out..

I really hate to bother you again, but my first attemts at using your most recent code of 3/17/09, results in the following:

o.In 'function interrupt handler()':
C:\Users\Owner\AppData\Local\Temp\build22823.tmp/Temporary_6346_5538:150:undefined reference to '__cxa_guard_acquire'
C:\Users\Owner\AppData\Local\Temp\build22823.tmp/Temporary_6346_5538:150:undefined reference to '__cxa_guard_release'

Couldn't determine program size:
C:\Users\Owner\arduino-0014\hardware/tools/avr/bin/avr-size:
'C:\Users\Owner\AppData\Local\Temp\build22823.tmp\sketch_"sketchname".hex':No such file

I left the name of the sketch as the automatic name that appears, which was '090319b'.
I have 3-ms*(pos)*, 5v, square wave multivibrator pulses fed into arduino digital pin2, which corresponds to "attachInterrupt(0,interruptHandler,RISING);, approx. line 109

And Idid as follows:

// !! use the device print demo, and delete the setup & main from it
// !! replacing it with what you see here.

Which was to put in the new code

Sorry to be such a pest
Thank you for your help

Hi

I've an old memory stick, see here some pictures
Do you think i can use this one, like an sd card used by uFat or Roland Riegel lib ?
Do you know how pins are numbered ?

Hi there.

No, this is a completely different standard to MMC. Sorry! :-[